frontend client for gemstone. decentralised workplace app
1import type { Did } from "@/lib/types/atproto";
2import {
3 systemsGmstnDevelopmentChannelMembershipRecordSchema,
4 type SystemsGmstnDevelopmentChannelMembership,
5} from "@/lib/types/lexicon/systems.gmstn.development.channel.membership";
6import type { Result } from "@/lib/utils/result";
7import { Client, simpleFetchHandler } from "@atcute/client";
8import { z } from "zod";
9
10// NOTE: might eventually want to put this into Prism as well.
11export const getMembershipRecordsFromPds = async ({
12 pdsEndpoint,
13 did,
14}: {
15 pdsEndpoint: string;
16 did: Did;
17}): Promise<
18 Result<Array<SystemsGmstnDevelopmentChannelMembership>, unknown>
19> => {
20 const handler = simpleFetchHandler({ service: pdsEndpoint });
21 const client = new Client({ handler });
22 const membershipRecordsResult = await fetchRecords({
23 client,
24 did,
25 });
26 if (!membershipRecordsResult.ok)
27 return { ok: false, error: membershipRecordsResult.error };
28 return { ok: true, data: membershipRecordsResult.data };
29};
30
31const fetchRecords = async ({
32 client,
33 did,
34}: {
35 client: Client;
36 did: Did;
37}): Promise<
38 Result<Array<SystemsGmstnDevelopmentChannelMembership>, unknown>
39> => {
40 const allRecords: Array<SystemsGmstnDevelopmentChannelMembership> = [];
41 let cursor: string | undefined;
42
43 let continueLoop = true;
44
45 while (continueLoop) {
46 const results = await client.get("com.atproto.repo.listRecords", {
47 params: {
48 repo: did,
49 collection: "systems.gmstn.development.channel.membership",
50 limit: 100,
51 cursor,
52 },
53 });
54 if (!results.ok)
55 return {
56 ok: false,
57 error: "Failed to fetch records. Check the response from PDS.",
58 };
59 const { records, cursor: nextCursor } = results.data;
60
61 const {
62 success,
63 error,
64 data: responses,
65 } = z
66 .array(
67 z.object({
68 cid: z.string(),
69 uri: z.string(),
70 value: systemsGmstnDevelopmentChannelMembershipRecordSchema,
71 }),
72 )
73 .safeParse(records);
74
75 if (!success) return { ok: false, error: z.treeifyError(error) };
76
77 allRecords.push(...responses.map((data) => data.value));
78
79 if (records.length < 100) continueLoop = false;
80 cursor = nextCursor;
81 }
82 return { ok: true, data: allRecords };
83};