94 lines
3.3 KiB
TypeScript
94 lines
3.3 KiB
TypeScript
import { contentTypes } from "./content-types";
|
|
import { httpCodes } from "./http-codes";
|
|
import express, {
|
|
type NextFunction,
|
|
type Request as ExpressRequest,
|
|
type Response as ExpressResponse,
|
|
} from "express";
|
|
|
|
import {isRedirect, InternalHandler, AuthenticationRequired,
|
|
AuthorizationDenied, Call,type Method, type ProcessedRoute,methodParser, type Result, type Route,massageMethod } from "./types";
|
|
import { runWithContext } from "./context";
|
|
import { Session } from "./auth";import { request } from "./request";
|
|
import { match } from "path-to-regexp";
|
|
|
|
type ProcessedRoutes= {[K in Method]: ProcessedRoute[] }
|
|
const processRoutes=(routes:Route[]) :ProcessedRoutes => {
|
|
const retval:ProcessedRoutes= {
|
|
GET: [],
|
|
POST: [],
|
|
PUT: [],
|
|
PATCH: [],
|
|
DELETE: [],
|
|
};
|
|
|
|
routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => {
|
|
// const pattern /*: URLPattern */ = new URLPattern({ pathname: route.path });
|
|
const matcher = match<Record<string, string>>(route.path);
|
|
const methodList = route.methods;
|
|
|
|
const handler: InternalHandler = async (
|
|
expressRequest: ExpressRequest,
|
|
): Promise<Result> => {
|
|
const method = massageMethod(expressRequest.method);
|
|
|
|
console.log("method", method);
|
|
|
|
if (!methodList.includes(method)) {
|
|
// XXX: Worth asserting this?
|
|
}
|
|
|
|
console.log("request.originalUrl", expressRequest.originalUrl);
|
|
|
|
// Authenticate the request
|
|
const auth = await request.auth.validateRequest(expressRequest);
|
|
|
|
const req: Call = {
|
|
pattern: route.path,
|
|
path: expressRequest.originalUrl,
|
|
method,
|
|
parameters: { one: 1, two: 2 },
|
|
request: expressRequest,
|
|
user: auth.user,
|
|
session: new Session(auth.session, auth.user),
|
|
};
|
|
|
|
try {
|
|
const retval = await runWithContext({ user: auth.user }, () =>
|
|
route.handler(req),
|
|
);
|
|
return retval;
|
|
} catch (error) {
|
|
// Handle authentication errors
|
|
if (error instanceof AuthenticationRequired) {
|
|
return {
|
|
code: httpCodes.clientErrors.Unauthorized,
|
|
contentType: contentTypes.application.json,
|
|
result: JSON.stringify({
|
|
error: "Authentication required",
|
|
}),
|
|
};
|
|
}
|
|
if (error instanceof AuthorizationDenied) {
|
|
return {
|
|
code: httpCodes.clientErrors.Forbidden,
|
|
contentType: contentTypes.application.json,
|
|
result: JSON.stringify({ error: "Access denied" }),
|
|
};
|
|
}
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
for (const [_idx, method] of methodList.entries()) {
|
|
const pr: ProcessedRoute = { matcher, method, handler };
|
|
|
|
retval[method].push(pr);
|
|
}
|
|
});
|
|
|
|
return retval;
|
|
}
|
|
|
|
export{processRoutes}
|