A zero-dependency AT Protocol Personal Data Server written in JavaScript
atproto pds

feat: add com.atproto.repo.listRecords endpoint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Changed files
+33 -2
src
+33 -2
src/pds.js
··· 888 888 '/xrpc/com.atproto.repo.describeRepo': { 889 889 handler: (pds, req, url) => pds.handleDescribeRepo() 890 890 }, 891 + '/xrpc/com.atproto.repo.listRecords': { 892 + handler: (pds, req, url) => pds.handleListRecords(url) 893 + }, 891 894 '/xrpc/com.atproto.sync.getLatestCommit': { 892 895 handler: (pds, req, url) => pds.handleGetLatestCommit() 893 896 }, ··· 1318 1321 }) 1319 1322 } 1320 1323 1324 + async handleListRecords(url) { 1325 + const collection = url.searchParams.get('collection') 1326 + if (!collection) { 1327 + return Response.json({ error: 'InvalidRequest', message: 'missing collection' }, { status: 400 }) 1328 + } 1329 + const limit = Math.min(parseInt(url.searchParams.get('limit') || '50'), 100) 1330 + const reverse = url.searchParams.get('reverse') === 'true' 1331 + const cursor = url.searchParams.get('cursor') 1332 + 1333 + const did = await this.getDid() 1334 + let query = `SELECT uri, cid, value FROM records WHERE collection = ? ORDER BY rkey ${reverse ? 'DESC' : 'ASC'} LIMIT ?` 1335 + const params = [collection, limit + 1] 1336 + 1337 + const rows = this.sql.exec(query, ...params).toArray() 1338 + const hasMore = rows.length > limit 1339 + const records = rows.slice(0, limit).map(r => ({ 1340 + uri: r.uri, 1341 + cid: r.cid, 1342 + value: cborDecode(new Uint8Array(r.value)) 1343 + })) 1344 + 1345 + return Response.json({ 1346 + records, 1347 + cursor: hasMore ? records[records.length - 1]?.uri : undefined 1348 + }) 1349 + } 1350 + 1321 1351 handleGetLatestCommit() { 1322 1352 const commits = this.sql.exec( 1323 1353 `SELECT cid, rev FROM commits ORDER BY seq DESC LIMIT 1` ··· 1465 1495 return Response.json({ repos, cursor: undefined }) 1466 1496 } 1467 1497 1468 - // describeRepo uses ?repo= param instead of ?did= 1469 - if (url.pathname === '/xrpc/com.atproto.repo.describeRepo') { 1498 + // Repo endpoints use ?repo= param instead of ?did= 1499 + if (url.pathname === '/xrpc/com.atproto.repo.describeRepo' || 1500 + url.pathname === '/xrpc/com.atproto.repo.listRecords') { 1470 1501 const repo = url.searchParams.get('repo') 1471 1502 if (!repo) { 1472 1503 return Response.json({ error: 'InvalidRequest', message: 'missing repo param' }, { status: 400 })