public uptime monitoring + (soon) observability with events saved to PDS
at main 2.9 kB view raw
1import { Client, ok, simpleFetchHandler } from '@atcute/client'; 2import type {} from '@atcute/atproto'; 3import type { ActorIdentifier, Did, Handle } from '@atcute/lexicons'; 4import type { UptimeCheck, UptimeCheckRecord } from './types.ts'; 5 6/** 7 * fetches uptime check records from a PDS for a given DID with cursor support 8 * 9 * @param pds the PDS URL 10 * @param did the DID or handle to fetch records for 11 * @param cursor optional cursor for pagination 12 * @returns object with records array and optional next cursor 13 */ 14export async function fetchUptimeChecks( 15 pds: string, 16 did: ActorIdentifier, 17 cursor?: string, 18): Promise<{ records: UptimeCheckRecord[]; cursor?: string }> { 19 const handler = simpleFetchHandler({ service: pds }); 20 const rpc = new Client({ handler }); 21 22 // resolve handle to DID if needed 23 let resolvedDid: Did; 24 if (!did.startsWith('did:')) { 25 const handleData = await ok( 26 rpc.get('com.atproto.identity.resolveHandle', { 27 params: { handle: did as Handle }, 28 }), 29 ); 30 resolvedDid = handleData.did; 31 } else { 32 resolvedDid = did as Did; 33 } 34 35 // fetch uptime check records with cursor 36 const response = await ok( 37 rpc.get('com.atproto.repo.listRecords', { 38 params: { 39 repo: resolvedDid, 40 collection: 'pet.nkp.uptime.check', 41 limit: 100, 42 cursor, 43 }, 44 }), 45 ); 46 47 // transform records into a more usable format 48 const records = response.records.map((record) => ({ 49 uri: record.uri, 50 cid: record.cid, 51 value: record.value as unknown as UptimeCheck, 52 indexedAt: new Date((record.value as unknown as UptimeCheck).checkedAt), 53 })); 54 55 return { 56 records, 57 cursor: response.cursor, 58 }; 59} 60 61/** 62 * fetches up to 2000 uptime check records using cursor pagination with progress callback 63 * stops early if no more records are available 64 * 65 * @param pds the PDS URL 66 * @param did the DID or handle to fetch records for 67 * @param onProgress optional callback called with each batch of records 68 * @returns array of uptime check records (max 2000) 69 */ 70export async function fetchInitialUptimeChecks( 71 pds: string, 72 did: ActorIdentifier, 73 onProgress?: (records: UptimeCheckRecord[]) => void, 74): Promise<UptimeCheckRecord[]> { 75 let allRecords: UptimeCheckRecord[] = []; 76 let cursor: string | undefined; 77 const maxRecords = 2000; 78 const batchSize = 100; 79 let totalFetched = 0; 80 81 do { 82 const result = await fetchUptimeChecks(pds, did, cursor); 83 const newRecords = result.records; 84 allRecords = allRecords.concat(newRecords); 85 totalFetched += newRecords.length; 86 cursor = result.cursor; 87 88 // Call progress callback with the accumulated records 89 if (onProgress) { 90 onProgress(allRecords); 91 } 92 93 // Stop early if we got fewer records than the batch size (indicating we've exhausted all records) 94 // or if no cursor is returned (also indicating no more records) 95 if (newRecords.length < batchSize || !cursor) { 96 break; 97 } 98 99 } while (cursor && totalFetched < maxRecords); 100 101 return allRecords; 102}