1import { safeParse, type InferOutput, type RecordKey } from "@atcute/lexicons";
2import { schemas as BarometerSchemas } from "barometer-lexicon";
3import { config } from "./config";
4import { ok as clientOk } from "@atcute/client";
5import { atpClient } from ".";
6
7export type Result<T, E> =
8 | {
9 ok: true;
10 value: T;
11 }
12 | {
13 ok: false;
14 error: E;
15 };
16
17export const ok = <T, E>(value: T): Result<T, E> => {
18 return { ok: true, value };
19};
20export const err = <T, E>(error: E): Result<T, E> => {
21 return { ok: false, error };
22};
23
24export const expect = <T, E>(
25 v: Result<T, E>,
26 msg: string = "expected result to not be error",
27) => {
28 if (v.ok) {
29 return v.value;
30 }
31 throw msg;
32};
33
34export const getRecord = async <
35 Collection extends keyof typeof BarometerSchemas,
36>(
37 collection: Collection,
38 rkey: RecordKey,
39): Promise<
40 Result<InferOutput<(typeof BarometerSchemas)[Collection]>, string>
41> => {
42 let maybeRecord = await atpClient.get("com.atproto.repo.getRecord", {
43 params: {
44 collection,
45 repo: config.repoDid,
46 rkey,
47 },
48 });
49 if (!maybeRecord.ok) {
50 return err(maybeRecord.data.message ?? maybeRecord.data.error);
51 }
52 const maybeTyped = safeParse(
53 BarometerSchemas[collection],
54 maybeRecord.data.value,
55 );
56 if (!maybeTyped.ok) {
57 return err(maybeTyped.message);
58 }
59 return maybeTyped;
60};
61
62export const putRecord = async <
63 Collection extends keyof typeof BarometerSchemas,
64>(
65 record: InferOutput<(typeof BarometerSchemas)[Collection]>,
66 rkey: RecordKey,
67) => {
68 return await clientOk(
69 atpClient.post("com.atproto.repo.putRecord", {
70 input: {
71 collection: record["$type"],
72 repo: config.repoDid,
73 record,
74 rkey,
75 },
76 }),
77 );
78};
79
80export const log = {
81 info: console.log,
82 warn: console.warn,
83 error: console.error,
84};
85
86export type Middleware = (
87 req: Bun.BunRequest,
88) => Promise<Bun.BunRequest | Response>;
89
90export const applyMiddleware =
91 <T extends string>(
92 fns: Middleware[],
93 route: Bun.RouterTypes.RouteHandler<T>,
94 ): Bun.RouterTypes.RouteHandler<T> =>
95 async (req, srv) => {
96 for (const fn of fns) {
97 const result = await fn(req);
98 if (result instanceof Response) {
99 return result;
100 } else {
101 req = result;
102 }
103 }
104 return route(req, srv);
105 };
106
107type Routes = Record<
108 string,
109 Record<string, Bun.RouterTypes.RouteHandler<string>>
110>;
111export const applyMiddlewareAll = (
112 fns: Middleware[],
113 routes: Routes,
114): Routes => {
115 return Object.fromEntries(
116 Object.entries(routes).map(([path, route]) => {
117 return [
118 path,
119 Object.fromEntries(
120 Object.entries(route).map(([method, handler]) => {
121 return [method, applyMiddleware(fns, handler)];
122 }),
123 ),
124 ];
125 }),
126 );
127};