frontend client for gemstone. decentralised workplace app
1import type { Did } from "@/lib/types/atproto";
2import {
3 systemsGmstnDevelopmentShardRecordSchema,
4 type SystemsGmstnDevelopmentShard,
5} from "@/lib/types/lexicon/systems.gmstn.development.shard";
6import type { Result } from "@/lib/utils/result";
7import { Client, simpleFetchHandler } from "@atcute/client";
8import { z } from "zod";
9
10// TODO: use prism instead of direct PDS lookup
11export const getUserShards = async ({
12 pdsEndpoint,
13 did,
14}: {
15 pdsEndpoint: string;
16 did: Did;
17}): Promise<
18 Result<
19 Array<{
20 cid: string;
21 uri: string;
22 value: SystemsGmstnDevelopmentShard;
23 }>,
24 unknown
25 >
26> => {
27 const handler = simpleFetchHandler({ service: pdsEndpoint });
28 const client = new Client({ handler });
29 const shardRecordsResult = await fetchRecords({
30 client,
31 did,
32 });
33 if (!shardRecordsResult.ok)
34 return { ok: false, error: shardRecordsResult.error };
35 return { ok: true, data: shardRecordsResult.data };
36};
37
38const fetchRecords = async ({
39 client,
40 did,
41}: {
42 client: Client;
43 did: Did;
44}): Promise<
45 Result<
46 Array<{
47 cid: string;
48 uri: string;
49 value: SystemsGmstnDevelopmentShard;
50 }>,
51 unknown
52 >
53> => {
54 const allRecords: Array<{
55 cid: string;
56 uri: string;
57 value: SystemsGmstnDevelopmentShard;
58 }> = [];
59 let cursor: string | undefined;
60
61 let continueLoop = true;
62
63 while (continueLoop) {
64 const results = await client.get("com.atproto.repo.listRecords", {
65 params: {
66 repo: did,
67 collection: "systems.gmstn.development.shard",
68 limit: 100,
69 cursor,
70 },
71 });
72 if (!results.ok)
73 return {
74 ok: false,
75 error: "Failed to fetch records. Check the response from PDS.",
76 };
77 const { records, cursor: nextCursor } = results.data;
78
79 const {
80 success,
81 error,
82 data: responses,
83 } = z
84 .array(
85 z.object({
86 cid: z.string(),
87 uri: z.string(),
88 value: systemsGmstnDevelopmentShardRecordSchema,
89 }),
90 )
91 .safeParse(records);
92
93 if (!success) return { ok: false, error: z.treeifyError(error) };
94
95 allRecords.push(...responses);
96
97 if (records.length < 100) continueLoop = false;
98 cursor = nextCursor;
99 }
100 return { ok: true, data: allRecords };
101};