frontend client for gemstone. decentralised workplace app
1import type { Did } from "@/lib/types/atproto";
2import { type LatticeSessionInfo } from "@/lib/types/handshake";
3import {
4 httpSuccessResponseSchema,
5 latticeHandshakeResponseSchema,
6} from "@/lib/types/http/responses";
7import type { SystemsGmstnDevelopmentChannelMembership } from "@/lib/types/lexicon/systems.gmstn.development.channel.membership";
8import { getLatticeEndpointFromDid } from "@/lib/utils/gmstn";
9import { requestInterServiceJwtFromPds } from "@/lib/utils/jwt";
10import type { Result } from "@/lib/utils/result";
11import type { OAuthContextValue } from "@/providers/OAuthProvider";
12import { z } from "zod";
13
14export const initiateHandshakeTo = async ({
15 did,
16 memberships,
17 oauth,
18}: {
19 did: Did;
20 memberships: Array<SystemsGmstnDevelopmentChannelMembership>;
21 oauth: OAuthContextValue;
22}): Promise<Result<LatticeSessionInfo, unknown>> => {
23 const latticeUrlResult = await getLatticeEndpointFromDid(did);
24 if (!latticeUrlResult.ok)
25 return { ok: false, error: latticeUrlResult.error };
26
27 let jwt = "";
28 if (did.startsWith("did:web:localhost")) {
29 if (__DEV__)
30 jwt = await requestInterServiceJwtFromPds({ oauth, aud: did });
31 else
32 return {
33 ok: false,
34 error: `Cannot initiate handshake to a lattice at localhost. Provided handshake target's DID was ${did}`,
35 };
36 } else {
37 // do proxy
38 // for now we return error
39 // FIXME: actually do service proxying.
40 return { ok: false, error: "Service proxying not yet implemented" };
41 }
42
43 const latticeBaseUrl = latticeUrlResult.data.origin;
44
45 const handshakeReq = new Request(`${latticeBaseUrl}/handshake`, {
46 method: "POST",
47 body: JSON.stringify({
48 interServiceJwt: jwt,
49 memberships,
50 }),
51 headers: {
52 "Content-Type": "application/json",
53 },
54 });
55 const handshakeRes = await fetch(handshakeReq);
56 const handshakeResponseData: unknown = await handshakeRes.json();
57
58 const {
59 success: httpResponseParseSuccess,
60 error: httpResponseParseError,
61 data: handshakeResponseDataParsed,
62 } = httpSuccessResponseSchema.safeParse(handshakeResponseData);
63 if (!httpResponseParseSuccess)
64 return {
65 ok: false,
66 error: z.treeifyError(httpResponseParseError),
67 };
68
69 const { data: handshakeData } = handshakeResponseDataParsed;
70
71 const {
72 success: handshakeDataParseSuccess,
73 error: handshakeDataParseError,
74 data: handshakeDataParsed,
75 } = latticeHandshakeResponseSchema.safeParse(handshakeData);
76 if (!handshakeDataParseSuccess)
77 return { ok: false, error: z.treeifyError(handshakeDataParseError) };
78
79 const { sessionInfo } = handshakeDataParsed;
80
81 return { ok: true, data: sessionInfo };
82};