-
Notifications
You must be signed in to change notification settings - Fork 30
/
routes.ts
126 lines (114 loc) · 3.73 KB
/
routes.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import express from 'express'
import { cborEncode, check } from '@atproto/common'
import * as plc from '@did-plc/lib'
import { ServerError } from './error'
import { AppContext } from './context'
export const createRouter = (ctx: AppContext): express.Router => {
const router = express.Router()
router.get('/_health', async function (req, res) {
const { db, version } = ctx
try {
await db.healthCheck()
} catch (err) {
req.log.error(err, 'failed health check')
return res.status(503).send({ version, error: 'Service Unavailable' })
}
res.send({ version })
})
// Export ops in the form of paginated json lines
router.get('/export', async function (req, res) {
const parsedCount = req.query.count ? parseInt(req.query.count, 10) : 1000
if (isNaN(parsedCount) || parsedCount < 1) {
throw new ServerError(400, 'Invalid count parameter')
}
const count = Math.min(parsedCount, 1000)
const after = req.query.after ? new Date(req.query.after) : undefined
const ops = await ctx.db.exportOps(count, after)
res.setHeader('content-type', 'application/jsonlines')
res.status(200)
for (let i = 0; i < ops.length; i++) {
if (i > 0) {
res.write('\n')
}
const line = JSON.stringify(ops[i])
res.write(line)
}
res.end()
})
// Get data for a DID document
router.get('/:did', async function (req, res) {
const { did } = req.params
const last = await ctx.db.lastOpForDid(did)
if (!last) {
throw new ServerError(404, `DID not registered: ${did}`)
}
const data = plc.opToData(did, last)
if (data === null) {
throw new ServerError(404, `DID not available: ${did}`)
}
const doc = await plc.formatDidDoc(data)
res.type('application/did+ld+json')
res.send(JSON.stringify(doc))
})
// Get data for a DID document
router.get('/:did/data', async function (req, res) {
const { did } = req.params
const last = await ctx.db.lastOpForDid(did)
if (!last) {
throw new ServerError(404, `DID not registered: ${did}`)
}
const data = plc.opToData(did, last)
if (data === null) {
throw new ServerError(404, `DID not available: ${did}`)
}
res.json(data)
})
// Get operation log for a DID
router.get('/:did/log', async function (req, res) {
const { did } = req.params
const log = await ctx.db.opsForDid(did)
if (log.length === 0) {
throw new ServerError(404, `DID not registered: ${did}`)
}
res.json(log)
})
// Get operation log for a DID
router.get('/:did/log/audit', async function (req, res) {
const { did } = req.params
const ops = await ctx.db.indexedOpsForDid(did, true)
if (ops.length === 0) {
throw new ServerError(404, `DID not registered: ${did}`)
}
const log = ops.map((op) => ({
...op,
cid: op.cid.toString(),
createdAt: op.createdAt.toISOString(),
}))
res.json(log)
})
// Get the most recent operation in the log for a DID
router.get('/:did/log/last', async function (req, res) {
const { did } = req.params
const last = await ctx.db.lastOpForDid(did)
if (!last) {
throw new ServerError(404, `DID not registered: ${did}`)
}
res.json(last)
})
// Update or create a DID doc
router.post('/:did', async function (req, res) {
const { did } = req.params
const op = req.body
const byteLength = cborEncode(op).byteLength
if (byteLength > 7500) {
throw new ServerError(400, 'Operation too large')
}
if (!check.is(op, plc.def.compatibleOpOrTombstone)) {
throw new ServerError(400, `Not a valid operation: ${JSON.stringify(op)}`)
}
await ctx.db.validateAndAddOp(did, op)
res.sendStatus(200)
})
return router
}
export default createRouter