decentralised sync engine
1import type { AtUri, Did } from "@/lib/types/atproto";
2import { type ShardSessionInfo } from "@/lib/types/handshake";
3import {
4 httpSuccessResponseSchema,
5 shardHandshakeResponseSchema,
6} from "@/lib/types/http/responses";
7import { atUriToString } from "@/lib/utils/atproto";
8import { getShardEndpointFromDid } from "@/lib/utils/gmstn";
9import { createInterServiceJwt } from "@/lib/utils/jwt";
10import type { Result } from "@/lib/utils/result";
11import z from "zod";
12
13export const initiateHandshakeTo = async ({
14 did,
15 channels,
16}: {
17 did: Did;
18 channels: Array<AtUri>;
19}): Promise<Result<ShardSessionInfo, unknown>> => {
20 const shardUrlResult = await getShardEndpointFromDid(did);
21 if (!shardUrlResult.ok) return { ok: false, error: shardUrlResult.error };
22
23 const jwt = await createInterServiceJwt(did);
24
25 const shardBaseUrl = shardUrlResult.data.origin;
26
27 const handshakeReq = new Request(`${shardBaseUrl}/handshake`, {
28 method: "POST",
29 body: JSON.stringify({
30 interServiceJwt: jwt,
31 channelAtUris: channels.map((channel) => atUriToString(channel)),
32 }),
33 headers: {
34 "Content-Type": "application/json",
35 },
36 });
37 const handshakeRes = await fetch(handshakeReq);
38 const handshakeResponseData: unknown = await handshakeRes.json();
39
40 const {
41 success: httpResponseParseSuccess,
42 error: httpResponseParseError,
43 data: handshakeResponseDataParsed,
44 } = httpSuccessResponseSchema.safeParse(handshakeResponseData);
45 if (!httpResponseParseSuccess) {
46 console.error("Parsing response failed.", httpResponseParseError);
47 console.error("Incoming data:", JSON.stringify(handshakeResponseData));
48 return {
49 ok: false,
50 error: z.treeifyError(httpResponseParseError),
51 };
52 }
53
54 const { data: handshakeData } = handshakeResponseDataParsed;
55
56 const {
57 success: handshakeDataParseSuccess,
58 error: handshakeDataParseError,
59 data: handshakeDataParsed,
60 } = shardHandshakeResponseSchema.safeParse(handshakeData);
61 if (!handshakeDataParseSuccess)
62 return { ok: false, error: z.treeifyError(handshakeDataParseError) };
63
64 const { sessionInfo } = handshakeDataParsed;
65
66 return { ok: true, data: sessionInfo };
67};