UNPKG

bun-route

Version:

A fast, Express-like router for the high-performance bun.serve() HTTP server.

926 lines (922 loc) 29.5 kB
// src/method.ts var HttpMethod; ((HttpMethod2) => { HttpMethod2[HttpMethod2["ALL"] = 1] = "ALL"; HttpMethod2[HttpMethod2["GET"] = 2] = "GET"; HttpMethod2[HttpMethod2["PUT"] = 3] = "PUT"; HttpMethod2[HttpMethod2["POST"] = 4] = "POST"; HttpMethod2[HttpMethod2["PATCH"] = 5] = "PATCH"; HttpMethod2[HttpMethod2["DELETE"] = 6] = "DELETE"; HttpMethod2[HttpMethod2["HEAD"] = 7] = "HEAD"; HttpMethod2[HttpMethod2["OPTIONS"] = 8] = "OPTIONS"; HttpMethod2[HttpMethod2["TRACE"] = 9] = "TRACE"; HttpMethod2[HttpMethod2["CONNECT"] = 10] = "CONNECT"; HttpMethod2[HttpMethod2["UNKNOWN"] = 11] = "UNKNOWN"; })(HttpMethod ||= {}); function parseHttpMethods(method) { switch (method) { case "*": return 1 /* ALL */; case "GET": return 2 /* GET */; case "PUT": return 3 /* PUT */; case "POST": return 4 /* POST */; case "PATCH": return 5 /* PATCH */; case "DELETE": return 6 /* DELETE */; case "HEAD": return 7 /* HEAD */; case "OPTIONS": return 8 /* OPTIONS */; case "TRACE": return 9 /* TRACE */; case "CONNECT": return 10 /* CONNECT */; default: return 11 /* UNKNOWN */; } } function stringifyHttpMethods(method) { switch (method) { case 1 /* ALL */: return "ALL"; case 2 /* GET */: return "GET"; case 3 /* PUT */: return "PUT"; case 4 /* POST */: return "POST"; case 5 /* PATCH */: return "PATCH"; case 6 /* DELETE */: return "DELETE"; case 7 /* HEAD */: return "HEAD"; case 8 /* OPTIONS */: return "OPTIONS"; case 9 /* TRACE */: return "TRACE"; case 10 /* CONNECT */: return "CONNECT"; case undefined: return "ALL"; default: return "UNKNOWN"; } } // src/middleware.ts function unmergeRequestMiddleware(...middlewares) { const foundMiddlewares = []; for (const middleware of middlewares) { if (isMergedRequestMiddleware(middleware)) { foundMiddlewares.push(...unmergeRequestMiddleware(...middleware.base)); } else { foundMiddlewares.push(middleware); } } return foundMiddlewares; } function mergeRequestMiddlewares(...middlewares) { if (middlewares.length == 0) { throw new Error("no middlewares specified"); } else if (middlewares.length == 1) { return middlewares[0]; } middlewares = unmergeRequestMiddleware(...middlewares); const mergedAsync = async (initialDefIndex, promise, req, res) => { await promise; if (res.submit === true || req.upgraded === true) { return; } for (let i = initialDefIndex + 1;i < middlewares.length; i++) { const middleware = middlewares[i]; const p = middleware(req, res); if (p && p.then != null) { await p; } if (res.submit === true || req.upgraded === true) { return; } } }; const baseMerged = (req, res) => { for (let i = 0;i < middlewares.length; i++) { const middleware = middlewares[i]; const p = middleware(req, res); if (p && p.then != null) { return mergedAsync(i, p, req, res); } if (res.submit === true || req.upgraded === true) { return; } } }; const merged = baseMerged; merged.base = middlewares; return merged; } function isMergedRequestMiddleware(middleware) { return Array.isArray(middleware.base); } function isMergeableEndpointRoute(route, route2) { if (route.method !== route2.method) { return false; } if (route.splitPath == undefined && route2.splitPath == undefined) { return true; } else if (route.splitPath != null && route2.splitPath != null && route.splitPath.join("/") == route2.splitPath.join("/")) { return true; } return false; } // src/responseBuilder.ts var notFoundResponse = new Response("Not Found", { status: 404, statusText: "Not Found" }); class ResponseBuilder { submit = false; statusCode = 200; statusText; bodyInit = null; headers = []; beforeSentHooks; beforeSent(hook) { if (!this.beforeSentHooks) { this.beforeSentHooks = []; } this.beforeSentHooks.push(hook); return this; } async startBeforeSentHookAsync(p) { await p; let hook = this.beforeSentHooks?.shift(); while (hook != null) { const p2 = hook(this); if (p2 && p2.then != null) { await p2; } } } startBeforeSentHook() { if (this.beforeSentHooks) { let hook = this.beforeSentHooks.pop(); while (hook != null) { const p = hook(this); if (p && p.then != null) { return this.startBeforeSentHookAsync(p); } hook = this.beforeSentHooks.pop(); } } } build() { return new Response(this.bodyInit, { status: this.statusCode, statusText: this.statusText, headers: this.headers }); } reset() { this.submit = false; this.statusCode = 200; this.statusText = undefined; this.bodyInit = null; this.headers = []; return this; } status(statusCode, statusText) { this.statusCode = statusCode; if (statusText) { this.statusText = statusText; } return this; } unsetHeader(name) { this.headers = this.headers.filter((header) => header[0].toLowerCase() !== name.toLowerCase()); return this; } setHeader(name, value, overwrite = true) { if (overwrite) { this.unsetHeader(name); } this.headers.push([name, value]); return this; } setCookie(name, value, options = {}) { const cookieParts = [`${name}=${encodeURIComponent(value)}`]; if (options.MaxAge) { cookieParts.push(`Max-Age=${options.MaxAge}`); } if (options.Path) { cookieParts.push(`Path=${options.Path}`); } if (options.HttpOnly) { cookieParts.push(`HttpOnly`); } if (options.Secure) { cookieParts.push(`Secure`); } if (options.SameSite) { cookieParts.push(`SameSite=${options.SameSite}`); } this.setHeader("Set-Cookie", cookieParts.join("; "), false); return this; } unsetCookie(name) { this.setHeader("Set-Cookie", name + "=; Expires=Thu, 01 Jan 1970 00:00:00 GMT", false); return this; } body(bodyInit = null) { this.bodyInit = bodyInit; return this; } send(bodyInit = null) { this.bodyInit = bodyInit; this.submit = true; } sendRedirect(url, perma = false) { this.reset(); this.statusCode = perma ? 308 : 307; this.headers.push(["location", url]); this.submit = true; } sendRedirectCustom(url, status) { this.reset(); this.statusCode = status; this.headers.push(["location", url]); this.submit = true; } sendBasicAuth(bodyInit = null, realm = "User Visible Realm", charset = "UTF-8") { this.reset(); this.statusCode = 401; this.setHeader("WWW-Authenticate", 'Basic realm="' + realm + '", charset="' + charset + '"'); this.bodyInit = bodyInit; this.submit = true; } } // src/router.ts var {statSync} = (() => ({})); // node:path var L = Object.create; var h = Object.defineProperty; var D = Object.getOwnPropertyDescriptor; var T = Object.getOwnPropertyNames; var _ = Object.getPrototypeOf; var E = Object.prototype.hasOwnProperty; var R = (s, e) => () => (e || s((e = { exports: {} }).exports, e), e.exports); var N = (s, e, r, t) => { if (e && typeof e == "object" || typeof e == "function") for (let i of T(e)) !E.call(s, i) && i !== r && h(s, i, { get: () => e[i], enumerable: !(t = D(e, i)) || t.enumerable }); return s; }; var j = (s, e, r) => (r = s != null ? L(_(s)) : {}, N(e || !s || !s.__esModule ? h(r, "default", { value: s, enumerable: true }) : r, s)); var k = R((W, w) => { function v(s) { if (typeof s != "string") throw new TypeError("Path must be a string. Received " + JSON.stringify(s)); } function C(s, e) { for (var r = "", t = 0, i = -1, a = 0, n, l = 0;l <= s.length; ++l) { if (l < s.length) n = s.charCodeAt(l); else { if (n === 47) break; n = 47; } if (n === 47) { if (!(i === l - 1 || a === 1)) if (i !== l - 1 && a === 2) { if (r.length < 2 || t !== 2 || r.charCodeAt(r.length - 1) !== 46 || r.charCodeAt(r.length - 2) !== 46) { if (r.length > 2) { var f = r.lastIndexOf("/"); if (f !== r.length - 1) { f === -1 ? (r = "", t = 0) : (r = r.slice(0, f), t = r.length - 1 - r.lastIndexOf("/")), i = l, a = 0; continue; } } else if (r.length === 2 || r.length === 1) { r = "", t = 0, i = l, a = 0; continue; } } e && (r.length > 0 ? r += "/.." : r = "..", t = 2); } else r.length > 0 ? r += "/" + s.slice(i + 1, l) : r = s.slice(i + 1, l), t = l - i - 1; i = l, a = 0; } else n === 46 && a !== -1 ? ++a : a = -1; } return r; } function F(s, e) { var r = e.dir || e.root, t = e.base || (e.name || "") + (e.ext || ""); return r ? r === e.root ? r + t : r + s + t : t; } var m = { resolve: function() { for (var e = "", r = false, t, i = arguments.length - 1;i >= -1 && !r; i--) { var a; i >= 0 ? a = arguments[i] : (t === undefined && (t = process.cwd()), a = t), v(a), a.length !== 0 && (e = a + "/" + e, r = a.charCodeAt(0) === 47); } return e = C(e, !r), r ? e.length > 0 ? "/" + e : "/" : e.length > 0 ? e : "."; }, normalize: function(e) { if (v(e), e.length === 0) return "."; var r = e.charCodeAt(0) === 47, t = e.charCodeAt(e.length - 1) === 47; return e = C(e, !r), e.length === 0 && !r && (e = "."), e.length > 0 && t && (e += "/"), r ? "/" + e : e; }, isAbsolute: function(e) { return v(e), e.length > 0 && e.charCodeAt(0) === 47; }, join: function() { if (arguments.length === 0) return "."; for (var e, r = 0;r < arguments.length; ++r) { var t = arguments[r]; v(t), t.length > 0 && (e === undefined ? e = t : e += "/" + t); } return e === undefined ? "." : m.normalize(e); }, relative: function(e, r) { if (v(e), v(r), e === r || (e = m.resolve(e), r = m.resolve(r), e === r)) return ""; for (var t = 1;t < e.length && e.charCodeAt(t) === 47; ++t) ; for (var i = e.length, a = i - t, n = 1;n < r.length && r.charCodeAt(n) === 47; ++n) ; for (var l = r.length, f = l - n, c = a < f ? a : f, d = -1, o = 0;o <= c; ++o) { if (o === c) { if (f > c) { if (r.charCodeAt(n + o) === 47) return r.slice(n + o + 1); if (o === 0) return r.slice(n + o); } else a > c && (e.charCodeAt(t + o) === 47 ? d = o : o === 0 && (d = 0)); break; } var A = e.charCodeAt(t + o), z = r.charCodeAt(n + o); if (A !== z) break; A === 47 && (d = o); } var b = ""; for (o = t + d + 1;o <= i; ++o) (o === i || e.charCodeAt(o) === 47) && (b.length === 0 ? b += ".." : b += "/.."); return b.length > 0 ? b + r.slice(n + d) : (n += d, r.charCodeAt(n) === 47 && ++n, r.slice(n)); }, _makeLong: function(e) { return e; }, dirname: function(e) { if (v(e), e.length === 0) return "."; for (var r = e.charCodeAt(0), t = r === 47, i = -1, a = true, n = e.length - 1;n >= 1; --n) if (r = e.charCodeAt(n), r === 47) { if (!a) { i = n; break; } } else a = false; return i === -1 ? t ? "/" : "." : t && i === 1 ? "//" : e.slice(0, i); }, basename: function(e, r) { if (r !== undefined && typeof r != "string") throw new TypeError('"ext" argument must be a string'); v(e); var t = 0, i = -1, a = true, n; if (r !== undefined && r.length > 0 && r.length <= e.length) { if (r.length === e.length && r === e) return ""; var l = r.length - 1, f = -1; for (n = e.length - 1;n >= 0; --n) { var c = e.charCodeAt(n); if (c === 47) { if (!a) { t = n + 1; break; } } else f === -1 && (a = false, f = n + 1), l >= 0 && (c === r.charCodeAt(l) ? --l === -1 && (i = n) : (l = -1, i = f)); } return t === i ? i = f : i === -1 && (i = e.length), e.slice(t, i); } else { for (n = e.length - 1;n >= 0; --n) if (e.charCodeAt(n) === 47) { if (!a) { t = n + 1; break; } } else i === -1 && (a = false, i = n + 1); return i === -1 ? "" : e.slice(t, i); } }, extname: function(e) { v(e); for (var r = -1, t = 0, i = -1, a = true, n = 0, l = e.length - 1;l >= 0; --l) { var f = e.charCodeAt(l); if (f === 47) { if (!a) { t = l + 1; break; } continue; } i === -1 && (a = false, i = l + 1), f === 46 ? r === -1 ? r = l : n !== 1 && (n = 1) : r !== -1 && (n = -1); } return r === -1 || i === -1 || n === 0 || n === 1 && r === i - 1 && r === t + 1 ? "" : e.slice(r, i); }, format: function(e) { if (e === null || typeof e != "object") throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof e); return F("/", e); }, parse: function(e) { v(e); var r = { root: "", dir: "", base: "", ext: "", name: "" }; if (e.length === 0) return r; var t = e.charCodeAt(0), i = t === 47, a; i ? (r.root = "/", a = 1) : a = 0; for (var n = -1, l = 0, f = -1, c = true, d = e.length - 1, o = 0;d >= a; --d) { if (t = e.charCodeAt(d), t === 47) { if (!c) { l = d + 1; break; } continue; } f === -1 && (c = false, f = d + 1), t === 46 ? n === -1 ? n = d : o !== 1 && (o = 1) : n !== -1 && (o = -1); } return n === -1 || f === -1 || o === 0 || o === 1 && n === f - 1 && n === l + 1 ? f !== -1 && (l === 0 && i ? r.base = r.name = e.slice(1, f) : r.base = r.name = e.slice(l, f)) : (l === 0 && i ? (r.name = e.slice(1, n), r.base = e.slice(1, f)) : (r.name = e.slice(l, n), r.base = e.slice(l, f)), r.ext = e.slice(n, f)), l > 0 ? r.dir = e.slice(0, l - 1) : i && (r.dir = "/"), r; }, sep: "/", delimiter: ":", win32: null, posix: null }; m.posix = m; w.exports = m; }); var x = j(k()); var u = x; var J = x; var P = function(s) { return s; }; var S = function() { throw new Error("Not implemented"); }; u.parse ??= S; J.parse ??= S; var g = { resolve: u.resolve.bind(u), normalize: u.normalize.bind(u), isAbsolute: u.isAbsolute.bind(u), join: u.join.bind(u), relative: u.relative.bind(u), toNamespacedPath: P, dirname: u.dirname.bind(u), basename: u.basename.bind(u), extname: u.extname.bind(u), format: u.format.bind(u), parse: u.parse.bind(u), sep: "/", delimiter: ":", win32: undefined, posix: undefined, _makeLong: P }; var y = { sep: "\\", delimiter: ";", win32: undefined, ...g, posix: g }; g.win32 = y.win32 = y; g.posix = g; var { resolve: B, normalize: G, isAbsolute: H, join: K, relative: Q, toNamespacedPath: U, dirname: V, basename: X, extname: Y, format: Z, parse: $, sep: I, delimiter: O } = g; // src/router.ts class Router { routes = []; mergeHandlers = true; static parseCookies(req, forceReload = false) { if (!req.originCookies) { req.cookies = {}; const cookieHeader = req.headers.get("cookie"); if (!cookieHeader) { return; } const pairs = cookieHeader.split(/; */); for (const pair of pairs) { const splitted = pair.split("="); const name = trimSpaces(splitted[0]); if (name.length != 0) { req.cookies[name] = decodeURIComponent(splitted.slice(1).join("=")); } } req.originCookies = { ...req.cookies }; } else if (forceReload) { req.cookies = { ...req.originCookies }; } } static storeCookies(req, res) { if (!req.cookies) { res.reset().status(500).send("Request cookies store error"); return; } const newCookies = req.cookies; const oldCookies = req.originCookies ?? {}; const newCookieKeys = Object.keys(newCookies); for (const cookieKey of newCookieKeys) { if (newCookies[cookieKey] && (!oldCookies[cookieKey] || oldCookies[cookieKey] !== newCookies[cookieKey])) { res.setCookie(cookieKey, newCookies[cookieKey]); } } for (const cookieKey of Object.keys(oldCookies)) { if (!newCookieKeys.includes(cookieKey)) { res.unsetCookie(cookieKey); } } req.cookies = newCookies; } static getDefinitionString(route, handler, mergedToTop) { let parts = ["/", "X", "/"]; if (mergedToTop) { parts[0] = "^ (M)"; } else { parts[0] = stringifyHttpMethods(route.method); } if (route.splitPath) { parts[1] = "/" + route.splitPath.join("/"); } else { parts[1] = "/"; } if (isMergedRequestMiddleware(handler)) { parts[2] = "[merged]"; } else if (handler && typeof handler.name == "string" && handler.name.length != 0) { parts[2] = handler.name; } else if (handler && handler.prototype && typeof handler.prototype.name == "string" && handler.prototype.name.length != 0) { parts[2] = handler.prototype.name; } else { parts[2] = "[anonym]"; } return parts; } dump(...servers) { if (this.routes.length == 0) { throw new Error("No endpoint routes defined"); } let unmergedParts = []; let mergedParts = []; for (const route of this.routes) { mergedParts.push(Router.getDefinitionString(route, route.handler, false)); unmergedParts.push(...unmergeRequestMiddleware(route.handler).map((middleware, index) => Router.getDefinitionString(route, middleware, index != 0))); } const both = [ ...unmergedParts, ...mergedParts ]; const part1MinLen = both.sort((a, b) => b[0].length - a[0].length)[0][0].length; const part2MinLen = both.sort((a, b) => b[1].length - a[1].length)[0][1].length; const part3MinLen = both.sort((a, b) => b[2].length - a[2].length)[0][2].length; const lines = []; if (servers && servers.length != 0) { if (servers.length == 1) { lines.push("Server is listening on " + servers[0].url); } else { lines.push("Server is listening on:"); lines.push(...servers.map((server) => "- " + server.url)); } } lines.push("", "# Defined endpoints:", ...unmergedParts.map(([part1, part2, part3]) => "| " + part1.padEnd(part1MinLen) + " | " + part2.padEnd(part2MinLen) + " | " + part3.padEnd(part3MinLen) + " |"), ""); if (unmergedParts.length != mergedParts.length) { lines.push("# Merged endpoints:", ...mergedParts.map(([part1, part2, part3]) => "| " + part1.padEnd(part1MinLen) + " | " + part2.padEnd(part2MinLen) + " | " + part3.padEnd(part3MinLen) + " |"), ""); } return lines.join(` `); } handle = (request, server) => this.innerHandle(request, server); innerHandle(request, server) { const res = new ResponseBuilder; const req = request; req.httpMethod = parseHttpMethods(req.method); req.server = server; req.cookies = {}; req.path = new URL(req.url).pathname; req.splitPath = splitPath(req.path); const sock = req.server.requestIP(req); if (!sock) { return new Response("Request closed to early", { status: 500 }); } req.sock = sock; const p = this.route(req, res); if (p && p.then != null) { return p.then(() => { if (req.upgraded) { return; } const p3 = res.startBeforeSentHook(); if (p3 && p3.then != null) { return p3.then(() => { return res.build(); }); } return res.build(); }); } if (req.upgraded) { return; } const p2 = res.startBeforeSentHook(); if (p2 && p2.then != null) { return p2.then(() => { return res.build(); }); } return res.build(); } route(req, res) { for (let i = 0;i < this.routes.length; i++) { if (this.routes[i].method != 1 /* ALL */ && this.routes[i].method != req.httpMethod) { continue; } const pathParams = requestPathMatchesRouteDefinition(req.splitPath, this.routes[i].splitPath); if (pathParams === false) { continue; } else if (pathParams !== true) { req.pathParams = pathParams; } const p = this.routes[i].handler(req, res); if (p != null && p.then != null) { return this.routeAsync(i, p, req, res); } if (res.submit === true || req.upgraded === true) { return; } } if (req.upgraded) { return; } res.reset().status(404).body("Not found"); } async routeAsync(initialDefIndex, promise, req, res) { await promise; if (res.submit === true || req.upgraded === true) { return; } for (let i = initialDefIndex + 1;i < this.routes.length; i++) { if (this.routes[i].method != null && this.routes[i].method != req.httpMethod) { continue; } const pathParams = requestPathMatchesRouteDefinition(req.splitPath, this.routes[i].splitPath); if (pathParams === false) { continue; } else if (pathParams !== true) { req.pathParams = pathParams; } const p = this.routes[i].handler(req, res); if (p && p.then != null) { await p; } if (res.submit === true || req.upgraded === true) { return; } } if (req.upgraded) { return; } res.reset().status(404).body("Not found"); } use(method, path, handler, ...handlers) { if (typeof handler != "function") { throw new Error("no handler provided, type: " + typeof handler); } handlers = [ handler, ...handlers ]; const route = { splitPath: splitRoutePath(path), method: parseHttpMethods(method), handler }; if (this.mergeHandlers) { const lastDef = this.routes.pop(); if (lastDef) { if (isMergeableEndpointRoute(lastDef, route)) { handlers.unshift(lastDef.handler); } else { this.routes.push(lastDef); } } } route.handler = mergeRequestMiddlewares(...unmergeRequestMiddleware(...handlers)); this.routes.push(route); return this; } get(path, handler, ...handlers) { return this.use("GET", path, handler, ...handlers); } post(path, handler, ...handlers) { return this.use("POST", path, handler, ...handlers); } put(path, handler, ...handlers) { return this.use("PUT", path, handler, ...handlers); } delete(path, handler, ...handlers) { return this.use("DELETE", path, handler, ...handlers); } patch(path, handler, ...handlers) { return this.use("PATCH", path, handler, ...handlers); } trace(path, handler, ...handlers) { return this.use("TRACE", path, handler, ...handlers); } head(path, handler, ...handlers) { return this.use("HEAD", path, handler, ...handlers); } connect(path, handler, ...handlers) { return this.use("CONNECT", path, handler, ...handlers); } options(path, handler, ...handlers) { return this.use("OPTIONS", path, handler, ...handlers); } ws(path) { const wsMiddleware = (req, res) => { if (req.server.upgrade(req)) { req.upgraded = true; } }; this.use("GET", path, wsMiddleware); return this; } redirect(method, path, redirectTarget, perma = false) { const redirectMiddleware = (_2, res) => res.sendRedirect(redirectTarget, perma); this.use(method, path, redirectMiddleware); return this; } static(path, targetDir, indexFile = "index.html", deepestLevel = 10) { if (!statSync(targetDir).isDirectory()) { throw new Error("static target is not a directory: " + targetDir); } const staticMiddleware = (req, res) => { if (req.path.endsWith("/" + indexFile)) { res.sendRedirect(req.path.slice(0, -indexFile.length), true); return; } let targetPath = K(targetDir, req.splitPath == undefined ? "/" : req.path); if (targetPath.endsWith("/")) { targetPath += indexFile; } if (req.splitPath != null && req.splitPath?.length > deepestLevel) { return; } try { const file = Bun.file(targetPath); return file.exists().then(async (exist) => { if (exist) { res.send(await file.arrayBuffer()); } else { res.status(404); } }).catch(() => { res.status(500, "Error while loading response content"); }); } catch (_2) { res.status(500, "Error while init response content"); } }; this.use("GET", path, staticMiddleware); return this; } basicAuth(method, path, validator, realm = "User Visible Realm", charset = "UTF-8") { const basicAuthMiddleware = (req, res) => { const auth = req.headers.get("authorization"); if (!auth) { res.sendBasicAuth("Missing authorization header", realm, charset); return; } let splitIndex = auth.indexOf(" "); if (splitIndex === -1) { res.sendBasicAuth("Unprocessable authorization header", realm, charset); return; } const schema = auth.slice(0, splitIndex); if (schema !== "Basic") { res.sendBasicAuth("Unprocessable basic auth schema", realm, charset); return; } const credentials = atob(auth.slice(splitIndex + 1)); splitIndex = credentials.indexOf(":"); if (splitIndex === -1) { res.sendBasicAuth("Unprocessable basic auth credentials", realm, charset); return; } if (!validator(credentials.slice(0, splitIndex), credentials.slice(splitIndex + 1))) { res.sendBasicAuth("Invalid credentials", realm, charset); return; } }; this.use(method, path, basicAuthMiddleware); return this; } cookies(method, path, autoResponseHeaders = false) { const cookiesMiddleware = autoResponseHeaders ? (req, res) => { res.beforeSent((res2) => Router.storeCookies(req, res2)); Router.parseCookies(req); } : (req) => Router.parseCookies(req); this.use(method, path, cookiesMiddleware); return this; } } function trimSpaces(value) { while (value.startsWith(" ") || value.startsWith("\t") || value.startsWith(` `)) { value = value.slice(1); } if (value.length == 0) { return ""; } while (value.endsWith(" ") || value.endsWith("\t") || value.endsWith(` `)) { value = value.slice(0, -1); } return value; } function splitPath(path) { if (path == undefined) { return; } while (path.startsWith("/") || path.startsWith(" ")) { path = path.slice(1); } if (path.length == 0) { return; } while (path.endsWith("/") || path.endsWith(" ")) { path = path.slice(0, -1); } const splitPath2 = path.split("/").map((part) => { while (part.startsWith("/") || part.startsWith(" ")) { part = part.slice(1); } if (part.length == 0) { return ""; } while (part.endsWith("/") || part.endsWith(" ")) { part = part.slice(0, -1); } return part; }).filter((v) => v.length != 0); if (splitPath2.length == 0) { return; } return splitPath2; } function splitRoutePath(path) { const splittedPath = splitPath(path); if (splittedPath && splittedPath.length > 1 && splittedPath.slice(0, -1).includes("**")) { throw new Error("Invalid router path, ** must be the last part"); } return splittedPath; } function requestPathMatchesRouteDefinition(requestPath, routeSelector) { if (requestPath == undefined && routeSelector == undefined) { return []; } else if (routeSelector == undefined) { return false; } else if (requestPath == undefined) { if (routeSelector[0] == "**") { return true; } return false; } else if (requestPath.length == 0) { throw new Error("Invalid requestPath SplitPath length, got 0, expected at least 1"); } else if (routeSelector.length == 0) { throw new Error("Invalid routeSelector SplitPath length, got 0, expected at least 1"); } else if (routeSelector[0] == "**") { return requestPath; } else if (routeSelector.length < requestPath.length) { if (routeSelector[routeSelector.length - 1] != "**") { return false; } } let pathParams = true; for (let i = 0;i < routeSelector.length; i++) { switch (routeSelector[i]) { case "*": if (requestPath.length <= i) { return false; } if (pathParams === true) { pathParams = []; } pathParams.push(requestPath[i]); break; case "**": if (requestPath.length - i > 0) { if (pathParams === true) { pathParams = []; } pathParams.push(...requestPath.slice(i)); } return pathParams; case requestPath[i]: break; default: return false; } } return pathParams; } export { unmergeRequestMiddleware, trimSpaces, stringifyHttpMethods, splitRoutePath, splitPath, requestPathMatchesRouteDefinition, parseHttpMethods, notFoundResponse, mergeRequestMiddlewares, isMergedRequestMiddleware, isMergeableEndpointRoute, Router, ResponseBuilder, HttpMethod };