UNPKG

@tbd54566975/dwn-proxy-js

Version:

Bidirectional proxy between DWM's <> RESTful

81 lines (70 loc) 2.87 kB
import express from 'express' import type { Express, Request, Response } from 'express' import cors from 'cors' import { DwnRequest, DwnResponse } from './dwn-types.js' import { Dwn } from '@tbd54566975/dwn-sdk-js' import { parseRequest, createResponse } from './dwn-json-rpc.js' export interface IHandler { (req: DwnRequest): Promise<DwnResponse | void> } type Options = { dwn: Dwn handler?: (req: DwnRequest) => Promise<DwnResponse | void> // [kw] can parameterize the json-rpc parsing } export const readReq = async <T = any>(req: Request): Promise<T | void> => { let chunks = '' for await (const chunk of req) chunks += chunk if (chunks) return JSON.parse(chunks) } export class DwnHttpServer { #options: Options api: Express constructor(options: Options) { this.#options = options this.api = express() this.api.use(cors({ exposedHeaders: 'dwn-response' })) this.api.get('/health', (_, res) => res.json({ ok: true })) this.api.get('/', (_req, res) => { // return a plain text string res.setHeader('content-type', 'text/plain') return res.send('please use a web5 client, for example: https://github.com/TBD54566975/web5-js ') }) this.api.post('/', async (req: Request, res: Response) => { try { let dwnRequest: DwnRequest try { dwnRequest = parseRequest(JSON.parse(req.headers['dwn-request'] as string)) if (!dwnRequest.payload) { const contentLength = req.headers['content-length'] const transferEncoding = req.headers['transfer-encoding'] const requestDataStream = (parseInt(contentLength) > 0 || transferEncoding !== undefined) ? req : undefined dwnRequest.payload = requestDataStream } } catch (err) { // todo integrate w/ web5-js expected response console.error('Failed to parse client request', err) res.status(400).end(err.message) return } const dwnResponse = this.#options.handler ? await this.#options.handler(dwnRequest) : undefined if (!dwnResponse) { const reply = await this.#options.dwn.processMessage(dwnRequest.target, dwnRequest.message, dwnRequest.payload as any) res.json(reply) } else if (dwnResponse.payload) { res.setHeader('content-type', 'application/octet-stream') res.setHeader('dwn-response', JSON.stringify(createResponse(dwnResponse))) dwnResponse.payload.pipe(res) } else { res.json(createResponse(dwnResponse)) } } catch (err) { // todo integrate w/ web5-js expected response console.error('Failed to process message', err) res.status(500).end(err.message) return } }) } listen = (port: number, callback?: () => void) => this.api.listen(port, callback) }