service status on atproto

refactor: move relevant code into store.ts and routes and automatically generate routes map

ptr.pet 356aadf7 bf0bc92e

verified
Changed files
+222 -115
proxy
+53
proxy/bun.lock
···
},
"devDependencies": {
"@types/bun": "latest",
+
"concurrently": "^9.2.0",
},
"peerDependencies": {
"typescript": "^5",
···
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
+
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
+
+
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+
"barometer-lexicon": ["barometer-lexicon@file:../lib", { "dependencies": { "@atcute/lexicons": "^1.1.0" }, "devDependencies": { "@atcute/lex-cli": "^2.1.1", "@types/bun": "latest" }, "peerDependencies": { "typescript": "^5" } }],
"bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
+
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+
+
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
+
+
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
+
+
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
+
+
"concurrently": ["concurrently@9.2.0", "", { "dependencies": { "chalk": "^4.1.2", "lodash": "^4.17.21", "rxjs": "^7.8.1", "shell-quote": "^1.8.1", "supports-color": "^8.1.1", "tree-kill": "^1.2.2", "yargs": "^17.7.2" }, "bin": { "concurrently": "dist/bin/concurrently.js", "conc": "dist/bin/concurrently.js" } }, "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ=="],
+
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
+
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
+
+
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
+
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
+
+
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
+
+
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
+
+
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
+
+
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
+
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
+
+
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
+
+
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
+
+
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
+
+
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
+
+
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
+
+
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
+
+
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
+
+
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
+
+
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
+
+
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
+
+
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
}
}
+39
proxy/gen-routes.ts
···
+
#!/usr/bin/env bun
+
// build-routes.ts - Run this at build time
+
+
import { Glob } from "bun";
+
import { writeFileSync } from "fs";
+
+
const routeImports: string[] = [];
+
const routeMap: string[] = [];
+
+
// Use Bun.Glob to find all route files
+
const glob = new Glob("*.ts");
+
+
for await (const file of glob.scan("./src/routes")) {
+
// Skip index.ts
+
if (file === "index.ts") continue;
+
+
const routeName = file.replace(".ts", "");
+
const routePath = `/${routeName}`;
+
+
// Generate import statement
+
routeImports.push(`import ${routeName}Route from "./${routeName}";`);
+
+
// Generate route map entry
+
routeMap.push(` "${routePath}": ${routeName}Route,`);
+
}
+
+
// Generate the complete index.ts content
+
const indexContent = `// Auto-generated route index
+
${routeImports.join("\n")}
+
+
export const routes = {
+
${routeMap.join(",\n")}
+
};
+
+
export default routes;
+
`;
+
+
// Write the generated index.ts file
+
writeFileSync("./src/routes/index.ts", indexContent);
+4 -2
proxy/package.json
···
"type": "module",
"private": true,
"scripts": {
-
"dev": "bun --watch src/index.ts"
+
"build:routes": "bun run gen-routes.ts",
+
"dev": "bun run build:routes && concurrently 'bun --watch gen-routes.ts' 'bun --watch src/index.ts'"
},
"devDependencies": {
-
"@types/bun": "latest"
+
"@types/bun": "latest",
+
"concurrently": "^9.2.0"
},
"peerDependencies": {
"typescript": "^5"
+6 -113
proxy/src/index.ts
···
PlcDidDocumentResolver,
WebDidDocumentResolver,
} from "@atcute/identity-resolver";
-
import {
-
parseCanonicalResourceUri,
-
type RecordKey,
-
} from "@atcute/lexicons/syntax";
import { config } from "./config";
import type {} from "@atcute/atproto";
-
import { is, safeParse } from "@atcute/lexicons";
-
import {
-
SystemsGazeBarometerState,
-
SystemsGazeBarometerHost,
-
SystemsGazeBarometerService,
-
SystemsGazeBarometerCheck,
-
} from "barometer-lexicon";
-
import { err, expect, getRecord, ok, putRecord, type Result } from "./utils";
-
-
interface Check {
-
record: SystemsGazeBarometerCheck.Main;
-
}
-
interface Service {
-
checks: Map<RecordKey, Check>;
-
record: SystemsGazeBarometerService.Main;
-
}
-
const services = new Map<RecordKey, Service>();
-
let host: SystemsGazeBarometerHost.Main | null = null;
+
import { getRecord, ok, putRecord, type Result } from "./utils";
+
import store from "./store";
+
import routes from "./routes";
const docResolver = new CompositeDidDocumentResolver({
methods: {
···
os.hostname(),
);
if (maybeRecord.ok) {
-
host = maybeRecord.value;
+
store.host = maybeRecord.value;
}
// if it doesnt exist we make a new one
-
if (host === null) {
+
if (store.host === null) {
const hostname = os.hostname();
await putRecord(
{
···
);
}
-
interface PushRequest {
-
serviceName?: string; // service manager service name
-
state: SystemsGazeBarometerState.Main;
-
}
-
-
const parsePushRequest = (json: unknown): Result<PushRequest, string> => {
-
if (typeof json !== "object" || json === null) {
-
return err("invalid request");
-
}
-
if ("serviceName" in json && typeof json.serviceName !== "string") {
-
return err("serviceName is not a string");
-
}
-
if ("state" in json) {
-
const parsed = safeParse(SystemsGazeBarometerState.mainSchema, json.state);
-
if (!parsed.ok) {
-
return err(`state is invalid: ${parsed.message}`);
-
}
-
} else {
-
return err("state not found");
-
}
-
return ok(json as PushRequest);
-
};
-
-
const badRequest = <Error extends { msg: string }>(error: Error) => {
-
return new Response(JSON.stringify(error), { status: 400 });
-
};
-
const server = Bun.serve({
-
routes: {
-
"/push": {
-
POST: async (req) => {
-
const maybeData = parsePushRequest(await req.json());
-
if (!maybeData.ok) {
-
return badRequest({
-
msg: `invalid request: ${maybeData.error}`,
-
});
-
}
-
const data = maybeData.value;
-
-
const serviceAtUri = expect(
-
parseCanonicalResourceUri(data.state.forService),
-
);
-
let service = services.get(serviceAtUri.rkey);
-
if (!service) {
-
const serviceRecord = await getRecord(
-
"systems.gaze.barometer.service",
-
serviceAtUri.rkey,
-
);
-
if (!serviceRecord.ok) {
-
return badRequest({
-
msg: `service was not found or is invalid: ${serviceRecord.error}`,
-
});
-
}
-
service = {
-
record: serviceRecord.value,
-
checks: new Map(),
-
};
-
services.set(serviceAtUri.rkey, service);
-
}
-
-
if (data.state.generatedBy) {
-
const checkAtUri = expect(
-
parseCanonicalResourceUri(data.state.generatedBy),
-
);
-
let check = service.checks.get(checkAtUri.rkey);
-
if (!check) {
-
let checkRecord = await getRecord(
-
"systems.gaze.barometer.check",
-
checkAtUri.rkey,
-
);
-
if (!checkRecord.ok) {
-
return badRequest({
-
msg: `check record not found or is invalid: ${checkRecord.error}`,
-
});
-
}
-
check = {
-
record: checkRecord.value,
-
};
-
service.checks.set(checkAtUri.rkey, check);
-
}
-
}
-
-
const result = await putRecord(data.state);
-
return new Response(
-
JSON.stringify({ cid: result.cid, uri: result.uri }),
-
);
-
},
-
},
-
},
-
});
+
const server = Bun.serve({ routes });
console.log(`server running on http://localhost:${server.port}`);
+8
proxy/src/routes/index.ts
···
+
// Auto-generated route index
+
import pushRoute from "./push";
+
+
export const routes = {
+
"/push": pushRoute,
+
};
+
+
export default routes;
+85
proxy/src/routes/push.ts
···
+
import { SystemsGazeBarometerState } from "barometer-lexicon";
+
import { err, expect, getRecord, ok, putRecord, type Result } from "../utils";
+
import { parseCanonicalResourceUri, safeParse } from "@atcute/lexicons";
+
import store from "../store";
+
+
interface PushRequest {
+
serviceName?: string; // service manager service name
+
state: SystemsGazeBarometerState.Main;
+
}
+
+
const parsePushRequest = (json: unknown): Result<PushRequest, string> => {
+
if (typeof json !== "object" || json === null) {
+
return err("invalid request");
+
}
+
if ("serviceName" in json && typeof json.serviceName !== "string") {
+
return err("serviceName is not a string");
+
}
+
if ("state" in json) {
+
const parsed = safeParse(SystemsGazeBarometerState.mainSchema, json.state);
+
if (!parsed.ok) {
+
return err(`state is invalid: ${parsed.message}`);
+
}
+
} else {
+
return err("state not found");
+
}
+
return ok(json as PushRequest);
+
};
+
+
const badRequest = <Error extends { msg: string }>(error: Error) => {
+
return new Response(JSON.stringify(error), { status: 400 });
+
};
+
const POST = async (req: Bun.BunRequest) => {
+
const maybeData = parsePushRequest(await req.json());
+
if (!maybeData.ok) {
+
return badRequest({
+
msg: `invalid request: ${maybeData.error}`,
+
});
+
}
+
const data = maybeData.value;
+
+
const serviceAtUri = expect(parseCanonicalResourceUri(data.state.forService));
+
let service = store.services.get(serviceAtUri.rkey);
+
if (!service) {
+
const serviceRecord = await getRecord(
+
"systems.gaze.barometer.service",
+
serviceAtUri.rkey,
+
);
+
if (!serviceRecord.ok) {
+
return badRequest({
+
msg: `service was not found or is invalid: ${serviceRecord.error}`,
+
});
+
}
+
service = {
+
record: serviceRecord.value,
+
checks: new Map(),
+
};
+
store.services.set(serviceAtUri.rkey, service);
+
}
+
+
if (data.state.generatedBy) {
+
const checkAtUri = expect(
+
parseCanonicalResourceUri(data.state.generatedBy),
+
);
+
let check = service.checks.get(checkAtUri.rkey);
+
if (!check) {
+
let checkRecord = await getRecord(
+
"systems.gaze.barometer.check",
+
checkAtUri.rkey,
+
);
+
if (!checkRecord.ok) {
+
return badRequest({
+
msg: `check record not found or is invalid: ${checkRecord.error}`,
+
});
+
}
+
check = {
+
record: checkRecord.value,
+
};
+
service.checks.set(checkAtUri.rkey, check);
+
}
+
}
+
+
const result = await putRecord(data.state);
+
return new Response(JSON.stringify({ cid: result.cid, uri: result.uri }));
+
};
+
export default { POST };
+27
proxy/src/store.ts
···
+
import type { RecordKey } from "@atcute/lexicons";
+
import type {
+
SystemsGazeBarometerCheck,
+
SystemsGazeBarometerHost,
+
SystemsGazeBarometerService,
+
} from "barometer-lexicon";
+
+
interface Check {
+
record: SystemsGazeBarometerCheck.Main;
+
}
+
interface Service {
+
checks: Map<RecordKey, Check>;
+
record: SystemsGazeBarometerService.Main;
+
}
+
+
class Store {
+
services;
+
host: SystemsGazeBarometerHost.Main | null;
+
+
constructor() {
+
this.services = new Map<RecordKey, Service>();
+
this.host = null;
+
}
+
}
+
+
const store = new Store();
+
export default store;