+95
src/pds.js
+95
src/pds.js
···
380
380
return importPrivateKey(hexToBytes(hex))
381
381
}
382
382
383
+
async createRecord(collection, record, rkey = null) {
384
+
const did = await this.getDid()
385
+
if (!did) throw new Error('PDS not initialized')
386
+
387
+
rkey = rkey || createTid()
388
+
const uri = `at://${did}/${collection}/${rkey}`
389
+
390
+
// Encode and hash record
391
+
const recordBytes = cborEncode(record)
392
+
const recordCid = await createCid(recordBytes)
393
+
const recordCidStr = cidToString(recordCid)
394
+
395
+
// Store block
396
+
this.sql.exec(
397
+
`INSERT OR REPLACE INTO blocks (cid, data) VALUES (?, ?)`,
398
+
recordCidStr, recordBytes
399
+
)
400
+
401
+
// Store record index
402
+
this.sql.exec(
403
+
`INSERT OR REPLACE INTO records (uri, cid, collection, rkey, value) VALUES (?, ?, ?, ?, ?)`,
404
+
uri, recordCidStr, collection, rkey, recordBytes
405
+
)
406
+
407
+
// Rebuild MST
408
+
const mst = new MST(this.sql)
409
+
const dataRoot = await mst.computeRoot()
410
+
411
+
// Get previous commit
412
+
const prevCommits = this.sql.exec(
413
+
`SELECT cid, rev FROM commits ORDER BY seq DESC LIMIT 1`
414
+
).toArray()
415
+
const prevCommit = prevCommits.length > 0 ? prevCommits[0] : null
416
+
417
+
// Create commit
418
+
const rev = createTid()
419
+
const commit = {
420
+
did,
421
+
version: 3,
422
+
data: dataRoot,
423
+
rev,
424
+
prev: prevCommit?.cid || null
425
+
}
426
+
427
+
// Sign commit
428
+
const commitBytes = cborEncode(commit)
429
+
const signingKey = await this.getSigningKey()
430
+
const sig = await sign(signingKey, commitBytes)
431
+
432
+
const signedCommit = { ...commit, sig }
433
+
const signedBytes = cborEncode(signedCommit)
434
+
const commitCid = await createCid(signedBytes)
435
+
const commitCidStr = cidToString(commitCid)
436
+
437
+
// Store commit block
438
+
this.sql.exec(
439
+
`INSERT OR REPLACE INTO blocks (cid, data) VALUES (?, ?)`,
440
+
commitCidStr, signedBytes
441
+
)
442
+
443
+
// Store commit reference
444
+
this.sql.exec(
445
+
`INSERT INTO commits (cid, rev, prev) VALUES (?, ?, ?)`,
446
+
commitCidStr, rev, prevCommit?.cid || null
447
+
)
448
+
449
+
// Sequence event
450
+
const evt = cborEncode({
451
+
ops: [{ action: 'create', path: `${collection}/${rkey}`, cid: recordCidStr }]
452
+
})
453
+
this.sql.exec(
454
+
`INSERT INTO seq_events (did, commit_cid, evt) VALUES (?, ?, ?)`,
455
+
did, commitCidStr, evt
456
+
)
457
+
458
+
return { uri, cid: recordCidStr, commit: commitCidStr }
459
+
}
460
+
383
461
async fetch(request) {
384
462
const url = new URL(request.url)
385
463
if (url.pathname === '/test/cbor') {
···
438
516
initialized: !!did,
439
517
did: did || null
440
518
})
519
+
}
520
+
if (url.pathname === '/xrpc/com.atproto.repo.createRecord') {
521
+
if (request.method !== 'POST') {
522
+
return Response.json({ error: 'method not allowed' }, { status: 405 })
523
+
}
524
+
525
+
const body = await request.json()
526
+
if (!body.collection || !body.record) {
527
+
return Response.json({ error: 'missing collection or record' }, { status: 400 })
528
+
}
529
+
530
+
try {
531
+
const result = await this.createRecord(body.collection, body.record, body.rkey)
532
+
return Response.json(result)
533
+
} catch (err) {
534
+
return Response.json({ error: err.message }, { status: 500 })
535
+
}
441
536
}
442
537
return new Response('pds running', { status: 200 })
443
538
}