@oada/well-known-json
Version:
Middleware for JSON Well-Known resources
95 lines (79 loc) • 3 kB
text/typescript
/**
* @license
* Copyright 2014-2022 Open Ag Data Alliance
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import util from 'node:util';
import type { Request, RequestHandler, Response } from 'express';
import allow from 'allow-methods';
import cors from 'cors';
import { type Options as BaseOptions, WellKnownJSON } from './WellKnownJSON.js';
export interface Options extends BaseOptions {
methods?: readonly string[];
forceProtocol?: string;
headers?: Record<string, string>;
cors?: Parameters<typeof cors>[0];
}
const WELL_KNOWN = /^\/\.well-known\/(.*)/;
const METHODS = ['OPTIONS', 'GET', 'HEAD'];
export function wellKnownJSON(
resources: Record<string, Record<string, unknown>>,
options: Options = {}
) {
const wkj = new WellKnownJSON<Request, Response>(resources, options);
const c = options.cors ?? {};
const corsOptions =
typeof c === 'function'
? (function (request, callback) {
c(request, (error, opt) => {
callback(error, { methods: METHODS, ...opt });
});
} as cors.CorsOptionsDelegate)
: { methods: METHODS, ...c };
const allowMiddleware = util.promisify(allow(options.methods ?? METHODS));
const corsMiddleware = util.promisify(cors(corsOptions));
const middleware: RequestHandler = (request, response, next) => {
async function handler() {
const m = WELL_KNOWN.exec(request.path);
const base = `${
options.forceProtocol ??
request.headers['x-forwarded-proto'] ??
request.protocol
}://${request.headers['x-forwarded-host'] ?? request.headers.host}`;
const match = m?.[1] && wkj.getResource(m[1], base, request, response);
if (match === undefined) {
// Pass to next middleware
return;
}
await allowMiddleware(request, response);
await corsMiddleware(request, response);
if (!request.accepts('json')) {
return response.status(406).send('Not Acceptable');
}
if (options.headers) {
response.set(options.headers);
}
return response.json(match);
}
handler()
// eslint-disable-next-line github/no-then, promise/always-return
.then(() => {
// eslint-disable-next-line promise/no-callback-in-promise
next();
})
// eslint-disable-next-line github/no-then, promise/no-callback-in-promise
.catch(next);
};
return Object.assign(middleware, { addResource: wkj.addResource.bind(wkj) });
}