decentralised sync engine
1import { OWNER_DID, SERVER_PORT, SERVICE_DID } from "@/lib/env";
2import { performHandshakes } from "@/lib/setup";
3import { setRegistrationState } from "@/lib/state";
4import type { AtUri } from "@/lib/types/atproto";
5import { getRecordFromAtUri } from "@/lib/utils/atproto";
6import { newErrorResponse } from "@/lib/utils/http/responses";
7import { connectToPrism } from "@/lib/utils/prism";
8import {
9 attachLatticeRegistrationListener,
10 wrapHttpRegistrationCheck,
11 wrapWsRegistrationCheck,
12} from "@/lib/utils/registration";
13import { routes } from "@/routes";
14import { setupServer } from "@/server";
15
16const main = async () => {
17 let latticeUrlOrigin = decodeURIComponent(
18 SERVICE_DID.startsWith("did:web:") ? SERVICE_DID.slice(8) : "",
19 );
20 if (latticeUrlOrigin === "localhost")
21 latticeUrlOrigin += `:${SERVER_PORT.toString()}`;
22 if (latticeUrlOrigin === "") {
23 // TODO: resolve did:plc endpoint to get the origin of the lattice endpoint described by the did:plc doc
24 // for now we just throw.
25 throw new Error(
26 "did:plc support not yet implemented. Provide a did:web for now. did:plc support will come in the future.",
27 );
28 }
29
30 const latticeAtUri: Required<AtUri> = {
31 // @ts-expect-error alas, template literal weirdness continues uwu
32 authority: OWNER_DID,
33 collection: "systems.gmstn.development.lattice",
34 rKey: latticeUrlOrigin,
35 };
36
37 const latticeRecord = await getRecordFromAtUri(latticeAtUri);
38
39 if (latticeRecord.ok) {
40 setRegistrationState(true);
41 }
42
43 const prismWebsocket = connectToPrism({
44 wantedCollections: ["systems.gmstn.development.*"],
45 });
46
47 // TODO: probably move this to an `attachListeners` hook that attaches the listeners we want.
48 attachLatticeRegistrationListener(prismWebsocket);
49
50 await performHandshakes(latticeAtUri);
51
52 const server = await setupServer();
53 for (const [url, route] of Object.entries(routes)) {
54 if (!route.wsHandler) {
55 const { handler, method, skipRegistrationCheck } = route;
56 server.route({
57 url,
58 method,
59 handler: skipRegistrationCheck
60 ? handler
61 : wrapHttpRegistrationCheck(handler),
62 });
63 } else {
64 const {
65 wsHandler,
66 method,
67 handler: httpHandler,
68 skipRegistrationCheckHttp,
69 skipRegistrationCheckWs,
70 } = route;
71 const handler =
72 httpHandler ??
73 (() =>
74 newErrorResponse(404, {
75 message:
76 "This is a websocket only route. Did you mean to initiate a websocket connection here?",
77 }));
78 server.route({
79 url,
80 method: method ?? "GET",
81 handler: skipRegistrationCheckHttp
82 ? handler
83 : wrapHttpRegistrationCheck(handler),
84 wsHandler: skipRegistrationCheckWs
85 ? wsHandler
86 : wrapWsRegistrationCheck(wsHandler),
87 });
88 }
89 }
90
91 server.listen({ port: SERVER_PORT }).catch((err: unknown) => {
92 server.log.error(err);
93 process.exit(1);
94 });
95};
96
97main()
98 .then(() => {
99 console.log(`Server is running on port ${SERVER_PORT.toString()}`);
100 })
101 .catch((err: unknown) => {
102 console.error("Something went wrong :(");
103 console.error(
104 "=========================== FULL ERROR BELOW ===========================",
105 );
106 console.error(err);
107 });