alinea
Version:
[](https://npmjs.org/package/alinea) [](https://packagephobia.com/result?p=alinea)
214 lines (212 loc) • 6.28 kB
JavaScript
import {
parse
} from "../../chunks/chunk-MOB7XDEU.js";
import "../../chunks/chunk-U5RRZUYZ.js";
// src/backend/router/Router.ts
import { CompressionStream, Headers, Response } from "@alinea/iso";
import { Outcome } from "alinea/core/Outcome";
var Route = class _Route {
constructor(handle) {
this.handle = handle;
}
map(next) {
return new _Route((input) => {
const result = this.handle(input);
if (result instanceof Promise)
return result.then((v) => {
return v === void 0 ? void 0 : callHandler(next, v);
});
if (result !== void 0)
return callHandler(next, result);
});
}
notFound(handler) {
return new _Route(async (input) => {
let result = this.handle(input);
if (result instanceof Promise)
result = await result;
if (result === void 0)
return handler(input);
return result;
});
}
recover(handler) {
return new _Route(async (input) => {
try {
let result = this.handle(input);
if (result instanceof Promise)
result = await result;
return result;
} catch (e) {
const error = e instanceof Error ? e : new Error(`Could not serve request: ${e}`);
return handler(error);
}
});
}
};
function router(...routes) {
return new Route(async (request) => {
for (const handler of routes) {
if (!handler)
continue;
let result = callHandler(handler, request);
if (result instanceof Promise)
result = await result;
if (result !== void 0)
return result;
}
});
}
function callHandler(handler, input) {
return typeof handler === "function" ? handler(input) : handler.handle(input);
}
((router2) => {
function use(handle) {
return new Route(handle);
}
router2.use = use;
function withMethod(method) {
return use((request) => {
if (request.method !== method)
return void 0;
return request;
});
}
function withPath(path, getPathname) {
const matcher2 = parse(path);
return use((request) => {
const url = new URL(request.url);
const match = matcher2.pattern.exec(getPathname(url));
if (match === null)
return void 0;
const params = {};
if (matcher2.keys)
for (let i = 0; i < matcher2.keys.length; i++)
params[matcher2.keys[i]] = match[i + 1];
return { request, url, params };
});
}
function matcher(getPathname = (url) => url.pathname) {
return {
get(path) {
return withMethod("GET").map(withPath(path, getPathname));
},
post(path) {
return withMethod("POST").map(withPath(path, getPathname));
},
put(path) {
return withMethod("PUT").map(withPath(path, getPathname));
},
delete(path) {
return withMethod("DELETE").map(withPath(path, getPathname));
},
all(path) {
return withPath(path, getPathname);
}
};
}
router2.matcher = matcher;
function base(url) {
const base2 = new URL(url).pathname;
const prefix = base2.endsWith("/") ? base2.slice(0, -1) : base2;
return matcher(({ pathname }) => {
if (pathname.startsWith(prefix))
return pathname.slice(prefix.length);
return pathname;
});
}
router2.base = base;
function startAt(base2) {
return matcher(({ pathname }) => {
const start = pathname.indexOf(base2);
if (start > -1)
return pathname.slice(start);
return pathname;
});
}
router2.startAt = startAt;
async function parseFormData(input) {
const body = await input.request.formData();
return { ...input, body };
}
router2.parseFormData = parseFormData;
async function parseBuffer(input) {
const body = await input.request.arrayBuffer();
return { ...input, body };
}
router2.parseBuffer = parseBuffer;
async function parseJson(input) {
const body = await input.request.json();
return { ...input, body };
}
router2.parseJson = parseJson;
function jsonResponse(output, init = {}) {
return new Response(JSON.stringify(output), {
...init,
headers: { "content-type": "application/json", ...init.headers },
status: Outcome.isOutcome(output) ? output.status : 200
});
}
router2.jsonResponse = jsonResponse;
function reportError(error) {
return router2.jsonResponse(Outcome.Failure(error));
}
router2.reportError = reportError;
function redirect(url, init = {}) {
return new Response("", {
...init,
headers: { location: url, ...init.headers },
status: init.status || 301
});
}
router2.redirect = redirect;
function cookieValue([key, value]) {
if (value === true)
return `; ${key}`;
if (value === false)
return "";
if (value instanceof Date)
return `; ${key}=${value.toUTCString()}`;
return `; ${key}=${String(value)}`;
}
function cookie(...cookies) {
return cookies.map((cookie2) => {
const { name, value, ...rest } = cookie2;
return `${name}=${value}` + Object.entries(rest).map(cookieValue).join("");
}).join(", ");
}
router2.cookie = cookie;
function compress(...routes) {
const route = router2(...routes);
return new Route(
async (request) => {
const response = await route.handle(request);
if (response === void 0)
return void 0;
const body = response.body;
if (!body)
return response;
const isCompressed = response.headers.get("content-encoding");
if (isCompressed)
return response;
const accept = request.headers.get("accept-encoding");
const method = accept?.includes("gzip") ? "gzip" : accept?.includes("deflate") ? "deflate" : void 0;
if (method === void 0)
return response;
const stream = body.pipeThrough(new CompressionStream(method));
const headers = new Headers(response.headers);
headers.set("content-encoding", method);
headers.delete("content-length");
return new Response(stream, {
headers,
status: response.status
});
}
);
}
router2.compress = compress;
})(router || (router = {}));
export {
Route,
router
};