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