import { safeParse, type InferOutput, type RecordKey } from "@atcute/lexicons"; import { schemas as BarometerSchemas } from "barometer-lexicon"; import { config } from "./config"; import { ok as clientOk } from "@atcute/client"; import { atpClient } from "."; import { now as generateTid } from "@atcute/tid"; import type { AtprotoDid } from "@atcute/lexicons/syntax"; export type CollectionUri = `at://${AtprotoDid}/${Nsid}/${RecordKey}`; export type StateUri = CollectionUri<"systems.gaze.barometer.state">; export type CheckUri = CollectionUri<"systems.gaze.barometer.check">; export type ServiceUri = CollectionUri<"systems.gaze.barometer.service">; export const getUri = < Collection extends | "systems.gaze.barometer.state" | "systems.gaze.barometer.check" | "systems.gaze.barometer.service", >( collection: Collection, rkey: RecordKey, ): CollectionUri => { return `at://${config.repoDid}/${collection}/${rkey}`; }; export type Result = | { ok: true; value: T; } | { ok: false; error: E; }; export const ok = (value: T): Result => { return { ok: true, value }; }; export const err = (error: E): Result => { return { ok: false, error }; }; export const expect = ( v: Result, msg: string = "expected result to not be error", ) => { if (v.ok) { return v.value; } throw msg; }; export const getRecord = async < Collection extends keyof typeof BarometerSchemas, >( collection: Collection, rkey: RecordKey, ): Promise< Result, string> > => { let maybeRecord = await atpClient.get("com.atproto.repo.getRecord", { params: { collection, repo: config.repoDid, rkey, }, }); if (!maybeRecord.ok) return err(maybeRecord.data.message ?? maybeRecord.data.error); const maybeTyped = safeParse( BarometerSchemas[collection], maybeRecord.data.value, ); if (!maybeTyped.ok) return err(maybeTyped.message); return maybeTyped; }; export const putRecord = async < Collection extends keyof typeof BarometerSchemas, >( record: InferOutput<(typeof BarometerSchemas)[Collection]>, rkey: RecordKey | null = null, ) => { return await clientOk( atpClient.post("com.atproto.repo.putRecord", { input: { collection: record["$type"], repo: config.repoDid, record, rkey: rkey ?? generateTid(), }, }), ); }; export const log = { info: console.log, warn: console.warn, error: console.error, }; export type Middleware = ( req: Bun.BunRequest, ) => Promise; export const applyMiddleware = ( fns: Middleware[], route: Bun.RouterTypes.RouteHandler, ): Bun.RouterTypes.RouteHandler => async (req, srv) => { for (const fn of fns) { const result = await fn(req); if (result instanceof Response) return result; else req = result; } return route(req, srv); }; type Routes = Record< string, Record> >; export const applyMiddlewareAll = ( fns: Middleware[], routes: Routes, ): Routes => { return Object.fromEntries( Object.entries(routes).map(([path, route]) => { return [ path, Object.fromEntries( Object.entries(route).map(([method, handler]) => { return [method, applyMiddleware(fns, handler)]; }), ), ]; }), ); };