1165 lines
38 KiB
JavaScript
1165 lines
38 KiB
JavaScript
|
|
import { a as legacyRootDirArgs, i as extendsArgs, n as dotEnvArgs, o as logLevelArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs";
|
|||
|
|
import { n as logger } from "./logger-C1qVsppt.mjs";
|
|||
|
|
import { t as overrideEnv } from "./env-BfWVBvy7.mjs";
|
|||
|
|
import { r as relativeToProcess, t as loadKit } from "./kit-gdbmFADU.mjs";
|
|||
|
|
import { n as clearDir } from "./fs-B0HqP3GX.mjs";
|
|||
|
|
import process from "node:process";
|
|||
|
|
import { defineCommand } from "citty";
|
|||
|
|
import { colors } from "consola/utils";
|
|||
|
|
import { intro, note, outro, taskLog } from "@clack/prompts";
|
|||
|
|
import { defu as defu$1 } from "defu";
|
|||
|
|
import { promises } from "node:fs";
|
|||
|
|
import { join, resolve } from "pathe";
|
|||
|
|
import { FastResponse, FastURL, serve } from "srvx";
|
|||
|
|
//#region ../../node_modules/.pnpm/rou3@0.9.1/node_modules/rou3/dist/index.mjs
|
|||
|
|
const NullProtoObj = /* @__PURE__ */ (() => {
|
|||
|
|
const e = function() {};
|
|||
|
|
return e.prototype = Object.create(null), Object.freeze(e.prototype), e;
|
|||
|
|
})();
|
|||
|
|
function createRouter() {
|
|||
|
|
return {
|
|||
|
|
root: { key: "" },
|
|||
|
|
static: new NullProtoObj()
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function scanFirstGroup(path) {
|
|||
|
|
let i = 0;
|
|||
|
|
let depth = 0;
|
|||
|
|
for (; i < path.length; i++) {
|
|||
|
|
const c = path.charCodeAt(i);
|
|||
|
|
if (c === 92) i++;
|
|||
|
|
else if (c === 40) depth++;
|
|||
|
|
else if (c === 41 && depth > 0) depth--;
|
|||
|
|
else if (c === 123 && depth === 0) break;
|
|||
|
|
}
|
|||
|
|
if (i >= path.length) return;
|
|||
|
|
let j = i + 1;
|
|||
|
|
depth = 0;
|
|||
|
|
for (; j < path.length; j++) {
|
|||
|
|
const c = path.charCodeAt(j);
|
|||
|
|
if (c === 92) j++;
|
|||
|
|
else if (c === 40) depth++;
|
|||
|
|
else if (c === 41 && depth > 0) depth--;
|
|||
|
|
else if (c === 125 && depth === 0) break;
|
|||
|
|
}
|
|||
|
|
if (j >= path.length) return;
|
|||
|
|
const mod = path[j + 1];
|
|||
|
|
const hasMod = mod === "?" || mod === "+" || mod === "*";
|
|||
|
|
return [
|
|||
|
|
path.slice(0, i),
|
|||
|
|
path.slice(i + 1, j),
|
|||
|
|
path.slice(j + (hasMod ? 2 : 1)),
|
|||
|
|
hasMod ? mod : void 0
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
function expandGroupDelimiters(path) {
|
|||
|
|
if (!path.includes("{")) return;
|
|||
|
|
const group = scanFirstGroup(path);
|
|||
|
|
if (!group) return;
|
|||
|
|
const [pre, body, suf, mod] = group;
|
|||
|
|
if (!mod) return [pre + body + suf];
|
|||
|
|
if (mod === "?") return [pre + body + suf, pre + suf];
|
|||
|
|
if (body.includes("/")) throw new Error("unsupported group repetition across segments");
|
|||
|
|
return [`${pre}(?:${body})${mod}${suf}`];
|
|||
|
|
}
|
|||
|
|
const UNNAMED_GROUP_PREFIX = "__rou3_unnamed_";
|
|||
|
|
const _unnamedGroupPrefixLength = 15;
|
|||
|
|
function hasSegmentWildcard(segment) {
|
|||
|
|
let depth = 0;
|
|||
|
|
for (let i = 0; i < segment.length; i++) {
|
|||
|
|
const ch = segment.charCodeAt(i);
|
|||
|
|
if (ch === 92) {
|
|||
|
|
i++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (ch === 40) {
|
|||
|
|
depth++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (ch === 41 && depth > 0) {
|
|||
|
|
depth--;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (ch === 42 && depth === 0) return true;
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
function replaceSegmentWildcards(segment, unnamedStart, toGroupKey = toUnnamedGroupKey) {
|
|||
|
|
let depth = 0;
|
|||
|
|
let nextIndex = unnamedStart;
|
|||
|
|
let replaced = "";
|
|||
|
|
for (let i = 0; i < segment.length; i++) {
|
|||
|
|
const ch = segment.charCodeAt(i);
|
|||
|
|
if (ch === 92) {
|
|||
|
|
replaced += segment[i];
|
|||
|
|
if (i + 1 < segment.length) replaced += segment[++i];
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (ch === 40) {
|
|||
|
|
depth++;
|
|||
|
|
replaced += segment[i];
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (ch === 41 && depth > 0) {
|
|||
|
|
depth--;
|
|||
|
|
replaced += segment[i];
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (ch === 42 && depth === 0) {
|
|||
|
|
replaced += `(?<${toGroupKey(nextIndex++)}>[^/]*)`;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
replaced += segment[i];
|
|||
|
|
}
|
|||
|
|
return [replaced, nextIndex];
|
|||
|
|
}
|
|||
|
|
function toUnnamedGroupKey(index) {
|
|||
|
|
return `${UNNAMED_GROUP_PREFIX}${index}`;
|
|||
|
|
}
|
|||
|
|
function normalizeUnnamedGroupKey(key) {
|
|||
|
|
return key.startsWith("__rou3_unnamed_") ? key.slice(_unnamedGroupPrefixLength) : key;
|
|||
|
|
}
|
|||
|
|
function encodeEscapes(path) {
|
|||
|
|
if (!path.includes("\\")) return path;
|
|||
|
|
return path.replace(/\\([:(){}])/g, (_, c) => "<22>" + "ABCDE"[":(){}".indexOf(c)]);
|
|||
|
|
}
|
|||
|
|
function decodeEscaped(segment) {
|
|||
|
|
if (!segment.includes("<22>")) return segment;
|
|||
|
|
return segment.replace(/\uFFFD([A-E])/g, (_, c) => c === "A" ? ":" : c === "B" ? "(" : c === "C" ? ")" : c === "D" ? "{" : "}");
|
|||
|
|
}
|
|||
|
|
function expandModifiers(segments) {
|
|||
|
|
for (let i = 0; i < segments.length; i++) {
|
|||
|
|
const last = segments[i].charCodeAt(segments[i].length - 1);
|
|||
|
|
if (last !== 63 && last !== 43 && last !== 42) continue;
|
|||
|
|
const m = segments[i].match(/^(.*:[\w-]+(?:\([^)]*\))?)([?+*])$/);
|
|||
|
|
if (!m) continue;
|
|||
|
|
const pre = segments.slice(0, i);
|
|||
|
|
const suf = segments.slice(i + 1);
|
|||
|
|
if (m[2] === "?") return ["/" + pre.concat(m[1]).concat(suf).join("/"), "/" + pre.concat(suf).join("/")];
|
|||
|
|
const name = m[1].match(/:([\w-]+)/)?.[1] || "_";
|
|||
|
|
const wc = "/" + [
|
|||
|
|
...pre,
|
|||
|
|
`**:${name}`,
|
|||
|
|
...suf
|
|||
|
|
].join("/");
|
|||
|
|
const without = "/" + [...pre, ...suf].join("/");
|
|||
|
|
return m[2] === "+" ? [wc] : [wc, without];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function normalizePath(path) {
|
|||
|
|
if (!path.includes("/.")) return path;
|
|||
|
|
const r = [];
|
|||
|
|
for (const s of path.split("/")) if (s === ".") continue;
|
|||
|
|
else if (s === ".." && r.length > 1) r.pop();
|
|||
|
|
else r.push(s);
|
|||
|
|
return r.join("/") || "/";
|
|||
|
|
}
|
|||
|
|
function splitPath(path) {
|
|||
|
|
const s = path.split("/");
|
|||
|
|
s.shift();
|
|||
|
|
if (s[s.length - 1] === "") s.pop();
|
|||
|
|
return s;
|
|||
|
|
}
|
|||
|
|
function getMatchParams(segments, paramsMap) {
|
|||
|
|
const params = new NullProtoObj();
|
|||
|
|
for (const [index, name] of paramsMap) {
|
|||
|
|
const segment = index < 0 ? segments.slice(-(index + 1)).join("/") : segments[index];
|
|||
|
|
if (typeof name === "string") params[name] = segment;
|
|||
|
|
else {
|
|||
|
|
const match = segment.match(name);
|
|||
|
|
if (match) for (const key in match.groups) params[normalizeUnnamedGroupKey(key)] = match.groups[key];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return params;
|
|||
|
|
}
|
|||
|
|
function addRoute(ctx, method = "", path, data) {
|
|||
|
|
method = method.toUpperCase();
|
|||
|
|
if (path.charCodeAt(0) !== 47) path = `/${path}`;
|
|||
|
|
const groupExpanded = expandGroupDelimiters(path);
|
|||
|
|
if (groupExpanded) {
|
|||
|
|
for (const expandedPath of groupExpanded) addRoute(ctx, method, expandedPath, data);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
path = encodeEscapes(path);
|
|||
|
|
const segments = splitPath(path);
|
|||
|
|
const expanded = expandModifiers(segments);
|
|||
|
|
if (expanded) {
|
|||
|
|
for (const p of expanded) addRoute(ctx, method, p, data);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
let node = ctx.root;
|
|||
|
|
let _unnamedParamIndex = 0;
|
|||
|
|
const paramsMap = [];
|
|||
|
|
const paramsRegexp = [];
|
|||
|
|
for (let i = 0; i < segments.length; i++) {
|
|||
|
|
let segment = segments[i];
|
|||
|
|
if (segment.startsWith("**")) {
|
|||
|
|
if (!node.wildcard) node.wildcard = { key: "**" };
|
|||
|
|
node = node.wildcard;
|
|||
|
|
paramsMap.push([
|
|||
|
|
-(i + 1),
|
|||
|
|
segment.split(":")[1] || "_",
|
|||
|
|
segment.length === 2
|
|||
|
|
]);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
const hasParen = segment.includes("(");
|
|||
|
|
const hasWildcard = !hasParen && hasSegmentWildcard(segment);
|
|||
|
|
if (segment === "*" || hasParen || hasWildcard || segment.includes(":")) {
|
|||
|
|
if (!node.param) node.param = { key: "*" };
|
|||
|
|
node = node.param;
|
|||
|
|
if (segment === "*") paramsMap.push([
|
|||
|
|
i,
|
|||
|
|
String(_unnamedParamIndex++),
|
|||
|
|
true
|
|||
|
|
]);
|
|||
|
|
else if (hasParen || hasWildcard || segment.includes(":", 1) || !/^:[\w-]+$/.test(segment)) {
|
|||
|
|
const [regexp, nextIndex] = getParamRegexp(segment, _unnamedParamIndex);
|
|||
|
|
_unnamedParamIndex = nextIndex;
|
|||
|
|
paramsRegexp[i] = regexp;
|
|||
|
|
node.hasRegexParam = true;
|
|||
|
|
paramsMap.push([
|
|||
|
|
i,
|
|||
|
|
regexp,
|
|||
|
|
false
|
|||
|
|
]);
|
|||
|
|
} else paramsMap.push([
|
|||
|
|
i,
|
|||
|
|
segment.slice(1),
|
|||
|
|
false
|
|||
|
|
]);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (segment === "\\*") segment = segments[i] = "*";
|
|||
|
|
else if (segment === "\\*\\*") segment = segments[i] = "**";
|
|||
|
|
segment = segments[i] = decodeEscaped(segment);
|
|||
|
|
const child = node.static?.[segment];
|
|||
|
|
if (child) node = child;
|
|||
|
|
else {
|
|||
|
|
const staticNode = { key: segment };
|
|||
|
|
if (!node.static) node.static = new NullProtoObj();
|
|||
|
|
node.static[segment] = staticNode;
|
|||
|
|
node = staticNode;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const hasParams = paramsMap.length > 0;
|
|||
|
|
const methods = node.methods ??= new NullProtoObj();
|
|||
|
|
(methods[method] ??= []).push({
|
|||
|
|
data: data || null,
|
|||
|
|
paramsRegexp,
|
|||
|
|
paramsMap: hasParams ? paramsMap : void 0
|
|||
|
|
});
|
|||
|
|
if (!hasParams) ctx.static["/" + segments.join("/")] = node;
|
|||
|
|
}
|
|||
|
|
function getParamRegexp(segment, unnamedStart = 0) {
|
|||
|
|
let _i = unnamedStart;
|
|||
|
|
let _s = "", _d = 0;
|
|||
|
|
for (let j = 0; j < segment.length; j++) {
|
|||
|
|
const c = segment.charCodeAt(j);
|
|||
|
|
if (c === 40) _d++;
|
|||
|
|
else if (c === 41 && _d > 0) _d--;
|
|||
|
|
else if (c === 92 && _d === 0 && j + 1 < segment.length) {
|
|||
|
|
const n = segment[j + 1];
|
|||
|
|
if (n !== ":" && n !== "(" && n !== "*" && n !== "\\") {
|
|||
|
|
_s += "" + n;
|
|||
|
|
j++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
} else if (c === 46 && _d === 0) {
|
|||
|
|
_s += "\\.";
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
_s += segment[j];
|
|||
|
|
}
|
|||
|
|
[_s, _i] = replaceSegmentWildcards(_s, _i);
|
|||
|
|
const regex = _s.replace(/:([\w-]+)(?:\(([^)]*)\))?/g, (_, id, p) => `(?<${id}>${p || "[^/]+"})`).replace(/\((?![?<])/g, () => `(?<${toUnnamedGroupKey(_i++)}>`).replace(/\uFFFE(.)/g, (_, c) => /[.*+?^${}()|[\]\\]/.test(c) ? `\\${c}` : c);
|
|||
|
|
return [new RegExp(`^${regex}$`), _i];
|
|||
|
|
}
|
|||
|
|
function findRoute(ctx, method = "", path, opts) {
|
|||
|
|
if (opts?.normalize) path = normalizePath(path);
|
|||
|
|
if (path.charCodeAt(path.length - 1) === 47) path = path.slice(0, -1);
|
|||
|
|
const staticNode = ctx.static[path];
|
|||
|
|
if (staticNode && staticNode.methods) {
|
|||
|
|
const staticMatch = staticNode.methods[method] || staticNode.methods[""];
|
|||
|
|
if (staticMatch !== void 0) return staticMatch[0];
|
|||
|
|
}
|
|||
|
|
const segments = splitPath(path);
|
|||
|
|
const match = _lookupTree(ctx.root, method, segments, 0);
|
|||
|
|
if (match === void 0) return;
|
|||
|
|
if (opts?.params === false) return match;
|
|||
|
|
return {
|
|||
|
|
data: match.data,
|
|||
|
|
params: match.paramsMap ? getMatchParams(segments, match.paramsMap) : void 0
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function _lookupTree(node, method, segments, index) {
|
|||
|
|
if (index === segments.length) {
|
|||
|
|
if (node.methods) {
|
|||
|
|
const match = _selectMatcher(node.methods, method, segments, node.key === "*", false);
|
|||
|
|
if (match) return match;
|
|||
|
|
}
|
|||
|
|
return node.param?.methods && _selectMatcher(node.param.methods, method, segments, true, true) || node.wildcard?.methods && _selectMatcher(node.wildcard.methods, method, segments, true, true) || void 0;
|
|||
|
|
}
|
|||
|
|
const segment = segments[index];
|
|||
|
|
if (node.static) {
|
|||
|
|
const staticChild = node.static[segment];
|
|||
|
|
if (staticChild) {
|
|||
|
|
const match = _lookupTree(staticChild, method, segments, index + 1);
|
|||
|
|
if (match) return match;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (node.param) {
|
|||
|
|
const match = _lookupTree(node.param, method, segments, index + 1);
|
|||
|
|
if (match) return match;
|
|||
|
|
}
|
|||
|
|
if (node.wildcard && node.wildcard.methods) return _selectMatcher(node.wildcard.methods, method, segments, true, false);
|
|||
|
|
}
|
|||
|
|
function _selectMatcher(methods, method, segments, dynamicTerminal, optionalOnly) {
|
|||
|
|
const match = methods[method] || methods[""];
|
|||
|
|
if (!match) return;
|
|||
|
|
const first = match[0];
|
|||
|
|
if (match.length === 1 && first.paramsRegexp.length === 0) {
|
|||
|
|
if (!optionalOnly) return first;
|
|||
|
|
const pMap = first.paramsMap;
|
|||
|
|
return pMap?.[pMap.length - 1]?.[2] ? first : void 0;
|
|||
|
|
}
|
|||
|
|
let best;
|
|||
|
|
let bestWeight = -1;
|
|||
|
|
for (const m of match) {
|
|||
|
|
const pMap = m.paramsMap;
|
|||
|
|
const lastOptional = pMap?.[pMap.length - 1]?.[2];
|
|||
|
|
if (optionalOnly && !lastOptional) continue;
|
|||
|
|
let weight = dynamicTerminal && pMap && !lastOptional ? 1 : 0;
|
|||
|
|
const regexps = m.paramsRegexp;
|
|||
|
|
for (let i = 0; i < regexps.length; i++) if (regexps[i]) {
|
|||
|
|
if (!regexps[i].test(segments[i])) {
|
|||
|
|
weight = -1;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
weight++;
|
|||
|
|
}
|
|||
|
|
if (weight > bestWeight) {
|
|||
|
|
best = m;
|
|||
|
|
bestWeight = weight;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return best;
|
|||
|
|
}
|
|||
|
|
const _P = "";
|
|||
|
|
function replaceEscapesOutsideGroups(segment) {
|
|||
|
|
let r = "", d = 0;
|
|||
|
|
for (let i = 0; i < segment.length; i++) {
|
|||
|
|
const c = segment.charCodeAt(i);
|
|||
|
|
if (c === 40) d++;
|
|||
|
|
else if (c === 41 && d > 0) d--;
|
|||
|
|
else if (c === 92 && d === 0 && i + 1 < segment.length) {
|
|||
|
|
const n = segment[i + 1];
|
|||
|
|
if (n !== ":" && n !== "(" && n !== "*" && n !== "\\") {
|
|||
|
|
r += _P + n;
|
|||
|
|
i++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
r += segment[i];
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
function resolveEscapePlaceholders(str) {
|
|||
|
|
return str.replace(/\uFFFE(.)/g, (_, c) => /[.*+?^${}()|[\]\\]/.test(c) ? `\\${c}` : c);
|
|||
|
|
}
|
|||
|
|
function escapeBareDots(str) {
|
|||
|
|
let r = "", d = 0;
|
|||
|
|
for (let i = 0; i < str.length; i++) {
|
|||
|
|
const c = str.charCodeAt(i);
|
|||
|
|
if (c === 92 || c === 65534) {
|
|||
|
|
r += str[i] + (str[i + 1] || "");
|
|||
|
|
i++;
|
|||
|
|
} else if (c === 40) {
|
|||
|
|
d++;
|
|||
|
|
r += str[i];
|
|||
|
|
} else if (c === 41) {
|
|||
|
|
if (d > 0) d--;
|
|||
|
|
r += str[i];
|
|||
|
|
} else if (c === 46 && d === 0) r += "\\.";
|
|||
|
|
else r += str[i];
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
function routeToRegExp(route = "/") {
|
|||
|
|
const inlineOptional = inlineOptionalGroup(route);
|
|||
|
|
if (inlineOptional) return inlineOptional;
|
|||
|
|
const groupExpanded = expandGroupDelimiters(route);
|
|||
|
|
if (groupExpanded) {
|
|||
|
|
const sources = groupExpanded.map((expandedRoute) => routeToRegExp(expandedRoute).source.slice(1, -1));
|
|||
|
|
return new RegExp(`^(?:${sources.join("|")})$`);
|
|||
|
|
}
|
|||
|
|
return _routeToRegExp(route);
|
|||
|
|
}
|
|||
|
|
function inlineOptionalGroup(route) {
|
|||
|
|
const group = scanFirstGroup(route);
|
|||
|
|
if (!group) return;
|
|||
|
|
const [pre, body, suf, mod] = group;
|
|||
|
|
if (mod !== "?" || suf !== "" || body === "" || scanFirstGroup(pre) || scanFirstGroup(body)) return;
|
|||
|
|
const baseSegs = routeToRegExpSegments(pre);
|
|||
|
|
const fullSegs = routeToRegExpSegments(pre + body);
|
|||
|
|
const baseLen = baseSegs.length;
|
|||
|
|
if (baseLen === 0 || fullSegs.length < baseLen) return;
|
|||
|
|
const midSegment = fullSegs.length === baseLen;
|
|||
|
|
const sharedLen = midSegment ? baseLen - 1 : baseLen;
|
|||
|
|
for (let i = 0; i < sharedLen; i++) if (fullSegs[i] !== baseSegs[i]) return;
|
|||
|
|
if (midSegment) {
|
|||
|
|
const prefix = baseSegs[baseLen - 1];
|
|||
|
|
const last = fullSegs[baseLen - 1];
|
|||
|
|
if (!last.startsWith(prefix)) return;
|
|||
|
|
if (/(?:\[\^\/\]|\.)[*+]\)?$/.test(prefix)) return;
|
|||
|
|
const k = prefix.length;
|
|||
|
|
const inlineSegs = fullSegs.slice(0, baseLen - 1);
|
|||
|
|
inlineSegs.push(`${last.slice(0, k)}(?:${last.slice(k)})?`);
|
|||
|
|
return new RegExp(`^/${inlineSegs.join("/")}/?$`);
|
|||
|
|
}
|
|||
|
|
const head = fullSegs.slice(0, baseLen).join("/");
|
|||
|
|
const tail = fullSegs.slice(baseLen).join("/");
|
|||
|
|
return new RegExp(`^/${head}(?:/${tail})?/?$`);
|
|||
|
|
}
|
|||
|
|
function _routeToRegExp(route) {
|
|||
|
|
return new RegExp(`^/${routeToRegExpSegments(route).join("/")}/?$`);
|
|||
|
|
}
|
|||
|
|
function routeToRegExpSegments(route) {
|
|||
|
|
const reSegments = [];
|
|||
|
|
let idCtr = 0;
|
|||
|
|
for (const segment of route.split("/")) {
|
|||
|
|
if (!segment) continue;
|
|||
|
|
if (segment === "*") reSegments.push(`(?<${toRegExpUnnamedKey(idCtr++)}>[^/]*)`);
|
|||
|
|
else if (segment.startsWith("**")) reSegments.push(segment === "**" ? "?(?<_>.*)" : `?(?<${segment.slice(3)}>.+)`);
|
|||
|
|
else if (segment.includes(":") || /(^|[^\\])\(/.test(segment) || hasSegmentWildcard(segment)) {
|
|||
|
|
const modMatch = segment.match(/^(.*:[\w-]+(?:\([^)]*\))?)([?+*])$/);
|
|||
|
|
if (modMatch) {
|
|||
|
|
const [, base, mod] = modMatch;
|
|||
|
|
const name = base.match(/:([\w-]+)/)?.[1] || `_${idCtr++}`;
|
|||
|
|
if (mod === "?") {
|
|||
|
|
const inner = escapeBareDots(base.replace(/:([\w-]+)(?:\(([^)]*)\))?/g, (_, id, pattern) => `(?<${id}>${pattern || "[^/]+"})`));
|
|||
|
|
if (reSegments.length > 0) {
|
|||
|
|
const prevQ = reSegments.pop();
|
|||
|
|
reSegments.push(`${prevQ}(?:/${inner})?`);
|
|||
|
|
} else reSegments.push(`?${inner}?`);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
const pattern = base.match(/:(\w+)(?:\(([^)]*)\))?/)?.[2];
|
|||
|
|
if (reSegments.length > 0) {
|
|||
|
|
const prevMod = reSegments.pop();
|
|||
|
|
if (pattern) {
|
|||
|
|
const repeated = `${pattern}(?:/${pattern})*`;
|
|||
|
|
reSegments.push(mod === "+" ? `${prevMod}/(?<${name}>${repeated})` : `${prevMod}(?:/(?<${name}>${repeated}))?`);
|
|||
|
|
} else reSegments.push(mod === "+" ? `${prevMod}/(?<${name}>.+)` : `${prevMod}(?:/(?<${name}>.*))?`);
|
|||
|
|
} else if (pattern) {
|
|||
|
|
const repeated = `${pattern}(?:/${pattern})*`;
|
|||
|
|
reSegments.push(mod === "+" ? `?(?<${name}>${repeated})` : `?(?<${name}>${repeated})?`);
|
|||
|
|
} else reSegments.push(mod === "+" ? `?(?<${name}>.+)` : `?(?<${name}>.*)`);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
let dynamicSegment = replaceEscapesOutsideGroups(segment);
|
|||
|
|
[dynamicSegment, idCtr] = replaceSegmentWildcards(dynamicSegment, idCtr, toRegExpUnnamedKey);
|
|||
|
|
reSegments.push(resolveEscapePlaceholders(escapeBareDots(dynamicSegment.replace(/:([\w-]+)(?:\(([^)]*)\))?/g, (_, id, pattern) => `(?<${id}>${pattern || "[^/]+"})`).replace(/(^|[^\\])\((?![?<])/g, (_, p) => `${p}(?<${toRegExpUnnamedKey(idCtr++)}>`))));
|
|||
|
|
} else reSegments.push(segment.replace(/\\(.)/g, "$1").replace(/[.*+?^${}()|[\]]/g, "\\$&"));
|
|||
|
|
}
|
|||
|
|
return reSegments;
|
|||
|
|
}
|
|||
|
|
function toRegExpUnnamedKey(index) {
|
|||
|
|
return `_${index}`;
|
|||
|
|
}
|
|||
|
|
//#endregion
|
|||
|
|
//#region ../../node_modules/.pnpm/h3@2.0.1-rc.25_crossws@0.4.5_srvx@0.11.22_/node_modules/h3/dist/h3.mjs
|
|||
|
|
function decodePathname(pathname) {
|
|||
|
|
return decodeURI(pathname.includes("%25") ? pathname.replace(/%25/g, "%2525") : pathname);
|
|||
|
|
}
|
|||
|
|
const kEventNS = "h3.internal.event.";
|
|||
|
|
const kEventRes = /* @__PURE__ */ Symbol.for(`${kEventNS}res`);
|
|||
|
|
const kEventResHeaders = /* @__PURE__ */ Symbol.for(`${kEventNS}res.headers`);
|
|||
|
|
const kEventResErrHeaders = /* @__PURE__ */ Symbol.for(`${kEventNS}res.err.headers`);
|
|||
|
|
const kMalformedURL = /* @__PURE__ */ Symbol.for(`${kEventNS}malformed`);
|
|||
|
|
var H3Event = class {
|
|||
|
|
app;
|
|||
|
|
req;
|
|||
|
|
url;
|
|||
|
|
context;
|
|||
|
|
static __is_event__ = true;
|
|||
|
|
constructor(req, context, app) {
|
|||
|
|
this.context = context || req.context || new NullProtoObj();
|
|||
|
|
this.req = req;
|
|||
|
|
this.app = app;
|
|||
|
|
const _url = req._url;
|
|||
|
|
let url = _url && _url instanceof URL ? _url : new FastURL(req.url);
|
|||
|
|
if (url.pathname.includes("%")) try {
|
|||
|
|
const pathname = decodePathname(url.pathname);
|
|||
|
|
if (pathname !== url.pathname) url = new FastURL(`${url.protocol}//${url.host}${pathname}${url.search}`);
|
|||
|
|
} catch {
|
|||
|
|
this[kMalformedURL] = true;
|
|||
|
|
}
|
|||
|
|
this.url = url;
|
|||
|
|
}
|
|||
|
|
get res() {
|
|||
|
|
return this[kEventRes] ||= new H3EventResponse();
|
|||
|
|
}
|
|||
|
|
get runtime() {
|
|||
|
|
return this.req.runtime;
|
|||
|
|
}
|
|||
|
|
waitUntil(promise) {
|
|||
|
|
this.req.waitUntil?.(promise);
|
|||
|
|
}
|
|||
|
|
toString() {
|
|||
|
|
return `[${this.req.method}] ${this.req.url}`;
|
|||
|
|
}
|
|||
|
|
toJSON() {
|
|||
|
|
return this.toString();
|
|||
|
|
}
|
|||
|
|
get node() {
|
|||
|
|
return this.req.runtime?.node;
|
|||
|
|
}
|
|||
|
|
get headers() {
|
|||
|
|
return this.req.headers;
|
|||
|
|
}
|
|||
|
|
get path() {
|
|||
|
|
return this.url.pathname + this.url.search;
|
|||
|
|
}
|
|||
|
|
get method() {
|
|||
|
|
return this.req.method;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
var H3EventResponse = class {
|
|||
|
|
status;
|
|||
|
|
statusText;
|
|||
|
|
get headers() {
|
|||
|
|
return this[kEventResHeaders] ||= new Headers();
|
|||
|
|
}
|
|||
|
|
get errHeaders() {
|
|||
|
|
return this[kEventResErrHeaders] ||= new Headers();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
const DISALLOWED_STATUS_CHARS = /[^\u0009\u0020-\u007E]/g;
|
|||
|
|
function sanitizeStatusMessage(statusMessage = "") {
|
|||
|
|
return statusMessage.replace(DISALLOWED_STATUS_CHARS, "");
|
|||
|
|
}
|
|||
|
|
function sanitizeStatusCode(statusCode, defaultStatusCode = 200) {
|
|||
|
|
if (!statusCode) return defaultStatusCode;
|
|||
|
|
if (typeof statusCode === "string") statusCode = +statusCode;
|
|||
|
|
if (Number.isNaN(statusCode) || statusCode < 100 || statusCode > 599) return defaultStatusCode;
|
|||
|
|
return statusCode;
|
|||
|
|
}
|
|||
|
|
var HTTPError = class HTTPError extends Error {
|
|||
|
|
get name() {
|
|||
|
|
return "HTTPError";
|
|||
|
|
}
|
|||
|
|
status;
|
|||
|
|
statusText;
|
|||
|
|
headers;
|
|||
|
|
cause;
|
|||
|
|
data;
|
|||
|
|
body;
|
|||
|
|
unhandled;
|
|||
|
|
static isError(input) {
|
|||
|
|
return input instanceof Error && input?.name === "HTTPError";
|
|||
|
|
}
|
|||
|
|
static status(status, statusText, details) {
|
|||
|
|
return new HTTPError({
|
|||
|
|
...details,
|
|||
|
|
statusText,
|
|||
|
|
status
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
constructor(arg1, arg2) {
|
|||
|
|
let messageInput;
|
|||
|
|
let details;
|
|||
|
|
if (typeof arg1 === "string") {
|
|||
|
|
messageInput = arg1;
|
|||
|
|
details = arg2;
|
|||
|
|
} else details = arg1;
|
|||
|
|
const status = sanitizeStatusCode(details?.status || details?.statusCode || (details?.cause)?.status || (details?.cause)?.statusCode, 500);
|
|||
|
|
const statusText = sanitizeStatusMessage(details?.statusText || details?.statusMessage || (details?.cause)?.statusText || (details?.cause)?.statusMessage);
|
|||
|
|
const message = messageInput || details?.message || (details?.cause)?.message || details?.statusText || details?.statusMessage || [
|
|||
|
|
"HTTPError",
|
|||
|
|
status,
|
|||
|
|
statusText
|
|||
|
|
].filter(Boolean).join(" ");
|
|||
|
|
super(message, { cause: details });
|
|||
|
|
this.cause = details;
|
|||
|
|
this.status = status;
|
|||
|
|
this.statusText = statusText || void 0;
|
|||
|
|
const rawHeaders = details?.headers || (details?.cause)?.headers;
|
|||
|
|
this.headers = rawHeaders ? new Headers(rawHeaders) : void 0;
|
|||
|
|
this.unhandled = details?.unhandled ?? (details?.cause)?.unhandled ?? void 0;
|
|||
|
|
this.data = details?.data;
|
|||
|
|
this.body = details?.body;
|
|||
|
|
}
|
|||
|
|
get statusCode() {
|
|||
|
|
return this.status;
|
|||
|
|
}
|
|||
|
|
get statusMessage() {
|
|||
|
|
return this.statusText;
|
|||
|
|
}
|
|||
|
|
toJSON() {
|
|||
|
|
const unhandled = this.unhandled;
|
|||
|
|
return {
|
|||
|
|
status: this.status,
|
|||
|
|
statusText: this.statusText,
|
|||
|
|
unhandled,
|
|||
|
|
message: unhandled ? "HTTPError" : this.message,
|
|||
|
|
data: unhandled ? void 0 : this.data,
|
|||
|
|
...unhandled ? void 0 : this.body
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
function isJSONSerializable(value, _type) {
|
|||
|
|
if (value === null || value === void 0) return true;
|
|||
|
|
if (_type !== "object") return _type === "boolean" || _type === "number" || _type === "string";
|
|||
|
|
if (typeof value.toJSON === "function") return true;
|
|||
|
|
if (Array.isArray(value)) return true;
|
|||
|
|
if (typeof value.pipe === "function" || typeof value.pipeTo === "function") return false;
|
|||
|
|
if (value instanceof NullProtoObj) return true;
|
|||
|
|
const proto = Object.getPrototypeOf(value);
|
|||
|
|
return proto === Object.prototype || proto === null;
|
|||
|
|
}
|
|||
|
|
const kNotFound = /* @__PURE__ */ Symbol.for("h3.notFound");
|
|||
|
|
const kHandled = /* @__PURE__ */ Symbol.for("h3.handled");
|
|||
|
|
function toResponse(val, event, config = {}) {
|
|||
|
|
if (typeof val?.then === "function") return val.then((resolvedVal) => toResponse(resolvedVal, event, config), (r) => toResponse(typeof r === "number" ? new HTTPError({ status: r }) : r, event, config));
|
|||
|
|
const response = prepareResponse(val, event, config);
|
|||
|
|
if (typeof response?.then === "function") return toResponse(response, event, config);
|
|||
|
|
const { onResponse } = config;
|
|||
|
|
return onResponse ? Promise.resolve(onResponse(response, event)).then(() => response) : response;
|
|||
|
|
}
|
|||
|
|
var HTTPResponse = class {
|
|||
|
|
#headers;
|
|||
|
|
#init;
|
|||
|
|
body;
|
|||
|
|
constructor(body, init) {
|
|||
|
|
this.body = body;
|
|||
|
|
this.#init = init;
|
|||
|
|
}
|
|||
|
|
get status() {
|
|||
|
|
return this.#init?.status || 200;
|
|||
|
|
}
|
|||
|
|
get statusText() {
|
|||
|
|
return this.#init?.statusText || "OK";
|
|||
|
|
}
|
|||
|
|
get headers() {
|
|||
|
|
return this.#headers ||= new Headers(this.#init?.headers);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
function prepareResponse(val, event, config, nested) {
|
|||
|
|
if (val === kHandled) return new FastResponse(null);
|
|||
|
|
if (val === kNotFound) val = new HTTPError({
|
|||
|
|
status: 404,
|
|||
|
|
message: `Cannot find any route matching [${event.req.method}] ${event.url}`
|
|||
|
|
});
|
|||
|
|
if (val && val instanceof Error) {
|
|||
|
|
const isHTTPError = HTTPError.isError(val);
|
|||
|
|
const error = isHTTPError ? val : new HTTPError(val);
|
|||
|
|
if (!isHTTPError) {
|
|||
|
|
error.unhandled = true;
|
|||
|
|
if (val?.stack) error.stack = val.stack;
|
|||
|
|
}
|
|||
|
|
if (error.unhandled && !config.silent) console.error(error);
|
|||
|
|
const { onError } = config;
|
|||
|
|
const errHeaders = event[kEventRes]?.[kEventResErrHeaders];
|
|||
|
|
return onError && !nested ? Promise.resolve(onError(error, event)).catch((error) => error).then((newVal) => prepareResponse(newVal ?? val, event, config, true)) : errorResponse(error, config.debug, errHeaders);
|
|||
|
|
}
|
|||
|
|
const preparedRes = event[kEventRes];
|
|||
|
|
const preparedHeaders = preparedRes?.[kEventResHeaders];
|
|||
|
|
event[kEventRes] = void 0;
|
|||
|
|
if (!(val instanceof Response)) {
|
|||
|
|
const res = prepareResponseBody(val, event, config);
|
|||
|
|
const status = res.status || preparedRes?.status;
|
|||
|
|
return new FastResponse(nullBody(event.req.method, status) ? null : res.body, {
|
|||
|
|
status,
|
|||
|
|
statusText: res.statusText || preparedRes?.statusText,
|
|||
|
|
headers: res.headers && preparedHeaders ? mergeHeaders$1(res.headers, preparedHeaders) : res.headers || preparedHeaders
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (!preparedHeaders || nested || !val.ok) {
|
|||
|
|
if (event.req.method === "HEAD" && val.body !== null) return new FastResponse(null, {
|
|||
|
|
status: val.status,
|
|||
|
|
statusText: val.statusText,
|
|||
|
|
headers: val.headers
|
|||
|
|
});
|
|||
|
|
return val;
|
|||
|
|
}
|
|||
|
|
try {
|
|||
|
|
mergeHeaders$1(val.headers, preparedHeaders, val.headers);
|
|||
|
|
return val;
|
|||
|
|
} catch {
|
|||
|
|
return new FastResponse(nullBody(event.req.method, val.status) ? null : val.body, {
|
|||
|
|
status: val.status,
|
|||
|
|
statusText: val.statusText,
|
|||
|
|
headers: mergeHeaders$1(val.headers, preparedHeaders)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function mergeHeaders$1(base, overrides, target = new Headers(base)) {
|
|||
|
|
for (const [name, value] of overrides) if (name === "set-cookie") target.append(name, value);
|
|||
|
|
else target.set(name, value);
|
|||
|
|
return target;
|
|||
|
|
}
|
|||
|
|
const frozen = (name) => (...args) => {
|
|||
|
|
throw new Error(`Headers are frozen (${name} ${args.join(", ")})`);
|
|||
|
|
};
|
|||
|
|
var FrozenHeaders = class extends Headers {
|
|||
|
|
set = frozen("set");
|
|||
|
|
append = frozen("append");
|
|||
|
|
delete = frozen("delete");
|
|||
|
|
};
|
|||
|
|
const emptyHeaders = /* @__PURE__ */ new FrozenHeaders({ "content-length": "0" });
|
|||
|
|
const jsonHeaders = /* @__PURE__ */ new FrozenHeaders({ "content-type": "application/json;charset=UTF-8" });
|
|||
|
|
function prepareResponseBody(val, event, config) {
|
|||
|
|
if (val === null || val === void 0) return {
|
|||
|
|
body: "",
|
|||
|
|
headers: emptyHeaders
|
|||
|
|
};
|
|||
|
|
const valType = typeof val;
|
|||
|
|
if (valType === "string") return { body: val };
|
|||
|
|
if (val instanceof Uint8Array) {
|
|||
|
|
event.res.headers.set("content-length", val.byteLength.toString());
|
|||
|
|
return { body: val };
|
|||
|
|
}
|
|||
|
|
if (val instanceof HTTPResponse || val?.constructor?.name === "HTTPResponse") return val;
|
|||
|
|
if (isJSONSerializable(val, valType)) return {
|
|||
|
|
body: JSON.stringify(val, void 0, config.debug ? 2 : void 0),
|
|||
|
|
headers: jsonHeaders
|
|||
|
|
};
|
|||
|
|
if (valType === "bigint") return {
|
|||
|
|
body: val.toString(),
|
|||
|
|
headers: jsonHeaders
|
|||
|
|
};
|
|||
|
|
if (val instanceof Blob) {
|
|||
|
|
const headers = new Headers({
|
|||
|
|
"content-type": val.type,
|
|||
|
|
"content-length": val.size.toString()
|
|||
|
|
});
|
|||
|
|
let filename = val.name;
|
|||
|
|
if (filename) {
|
|||
|
|
filename = encodeURIComponent(filename);
|
|||
|
|
headers.set("content-disposition", `filename="${filename}"; filename*=UTF-8''${filename}`);
|
|||
|
|
}
|
|||
|
|
return {
|
|||
|
|
body: val.stream(),
|
|||
|
|
headers
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
if (valType === "symbol") return { body: val.toString() };
|
|||
|
|
if (valType === "function") return { body: `${val.name}()` };
|
|||
|
|
return { body: val };
|
|||
|
|
}
|
|||
|
|
function nullBody(method, status) {
|
|||
|
|
return method === "HEAD" || status === 100 || status === 101 || status === 102 || status === 204 || status === 205 || status === 304;
|
|||
|
|
}
|
|||
|
|
function errorResponse(error, debug, errHeaders) {
|
|||
|
|
let headers = error.headers ? mergeHeaders$1(jsonHeaders, error.headers) : new Headers(jsonHeaders);
|
|||
|
|
if (errHeaders) headers = mergeHeaders$1(headers, errHeaders);
|
|||
|
|
return new FastResponse(JSON.stringify({
|
|||
|
|
...error.toJSON(),
|
|||
|
|
stack: debug && error.stack ? error.stack.split("\n").map((l) => l.trim()) : void 0
|
|||
|
|
}, void 0, debug ? 2 : void 0), {
|
|||
|
|
status: error.status,
|
|||
|
|
statusText: error.statusText,
|
|||
|
|
headers
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function normalizeMiddleware(input, opts = {}) {
|
|||
|
|
const matcher = createMatcher(opts);
|
|||
|
|
if (!matcher && (input.length > 1 || input.constructor?.name === "AsyncFunction")) return input;
|
|||
|
|
return (event, next) => {
|
|||
|
|
if (matcher && !matcher(event)) return next();
|
|||
|
|
const res = input(event, next);
|
|||
|
|
return res === void 0 || res === kNotFound ? next() : res;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function createMatcher(opts) {
|
|||
|
|
if (!opts.route && !opts.method && !opts.match) return;
|
|||
|
|
const routeMatcher = opts.route ? routeToRegExp(opts.route) : void 0;
|
|||
|
|
const method = opts.method?.toUpperCase();
|
|||
|
|
return function _middlewareMatcher(event) {
|
|||
|
|
if (method && event.req.method !== method) {
|
|||
|
|
if (!(method === "GET" && event.req.method === "HEAD")) return false;
|
|||
|
|
}
|
|||
|
|
if (opts.match && !opts.match(event)) return false;
|
|||
|
|
if (!routeMatcher) return true;
|
|||
|
|
const match = event.url.pathname.match(routeMatcher);
|
|||
|
|
if (!match) return false;
|
|||
|
|
if (match.groups) event.context.middlewareParams = {
|
|||
|
|
...event.context.middlewareParams,
|
|||
|
|
...match.groups
|
|||
|
|
};
|
|||
|
|
return true;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function callMiddleware(event, middleware, handler, index = 0) {
|
|||
|
|
if (index === middleware.length) return handler(event);
|
|||
|
|
const fn = middleware[index];
|
|||
|
|
let nextCalled;
|
|||
|
|
let nextResult;
|
|||
|
|
const next = () => {
|
|||
|
|
if (nextCalled) return nextResult;
|
|||
|
|
nextCalled = true;
|
|||
|
|
nextResult = callMiddleware(event, middleware, handler, index + 1);
|
|||
|
|
return nextResult;
|
|||
|
|
};
|
|||
|
|
const ret = fn(event, next);
|
|||
|
|
return isUnhandledResponse(ret) ? next() : typeof ret?.then === "function" ? ret.then((resolved) => isUnhandledResponse(resolved) ? next() : resolved) : ret;
|
|||
|
|
}
|
|||
|
|
function isUnhandledResponse(val) {
|
|||
|
|
return val === void 0 || val === kNotFound;
|
|||
|
|
}
|
|||
|
|
function requestWithURL(req, url) {
|
|||
|
|
const cache = {
|
|||
|
|
url,
|
|||
|
|
_url: void 0
|
|||
|
|
};
|
|||
|
|
return new Proxy(req, { get(target, prop) {
|
|||
|
|
if (prop in cache) return cache[prop];
|
|||
|
|
const value = Reflect.get(target, prop);
|
|||
|
|
cache[prop] = typeof value === "function" ? value.bind(target) : value;
|
|||
|
|
return cache[prop];
|
|||
|
|
} });
|
|||
|
|
}
|
|||
|
|
function requestWithBaseURL(req, base) {
|
|||
|
|
const url = new URL(req.url);
|
|||
|
|
let pathname;
|
|||
|
|
try {
|
|||
|
|
pathname = decodePathname(url.pathname);
|
|||
|
|
} catch {
|
|||
|
|
pathname = url.pathname;
|
|||
|
|
}
|
|||
|
|
url.pathname = pathname.slice(base.length) || "/";
|
|||
|
|
return requestWithURL(req, url.href);
|
|||
|
|
}
|
|||
|
|
function toRequest(input, options) {
|
|||
|
|
if (typeof input === "string") {
|
|||
|
|
let url = input;
|
|||
|
|
if (url[0] === "/") {
|
|||
|
|
const headers = options?.headers ? new Headers(options.headers) : void 0;
|
|||
|
|
const host = headers?.get("host") || "localhost";
|
|||
|
|
url = `${(headers?.get("x-forwarded-proto") || "").split(",")[0].trim() === "https" ? "https" : "http"}://${host}${url}`;
|
|||
|
|
}
|
|||
|
|
return new Request(url, options);
|
|||
|
|
} else if (options || input instanceof URL) return new Request(input, options);
|
|||
|
|
return input;
|
|||
|
|
}
|
|||
|
|
function defineHandler(input) {
|
|||
|
|
if (typeof input === "function") return handlerWithFetch(input);
|
|||
|
|
const handler = input.handler || (input.fetch ? function _fetchHandler(event) {
|
|||
|
|
return input.fetch(event.req);
|
|||
|
|
} : NoHandler);
|
|||
|
|
return Object.assign(handlerWithFetch(input.middleware?.length ? function _handlerMiddleware(event) {
|
|||
|
|
return callMiddleware(event, input.middleware, handler);
|
|||
|
|
} : handler), input);
|
|||
|
|
}
|
|||
|
|
function handlerWithFetch(handler) {
|
|||
|
|
if ("fetch" in handler) return handler;
|
|||
|
|
return Object.assign(handler, { fetch: (req) => {
|
|||
|
|
if (typeof req === "string") req = new URL(req, "http://_");
|
|||
|
|
if (req instanceof URL) req = new Request(req);
|
|||
|
|
const event = new H3Event(req);
|
|||
|
|
try {
|
|||
|
|
return Promise.resolve(toResponse(handler(event), event));
|
|||
|
|
} catch (error) {
|
|||
|
|
return Promise.resolve(toResponse(error, event));
|
|||
|
|
}
|
|||
|
|
} });
|
|||
|
|
}
|
|||
|
|
function defineLazyEventHandler(loader) {
|
|||
|
|
let handler;
|
|||
|
|
let promise;
|
|||
|
|
return defineHandler(function lazyHandler(event) {
|
|||
|
|
return handler ? handler(event) : (promise ??= Promise.resolve(loader()).then(function resolveLazyHandler(r) {
|
|||
|
|
handler = toEventHandler(r) || toEventHandler(r.default);
|
|||
|
|
if (typeof handler !== "function") throw new TypeError("Invalid lazy handler", { cause: { resolved: r } });
|
|||
|
|
return handler;
|
|||
|
|
})).then((r) => r(event));
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function toEventHandler(handler) {
|
|||
|
|
if (typeof handler === "function") return handler;
|
|||
|
|
if (typeof handler?.handler === "function" && handler.constructor?.["~h3"]) return handler.handler;
|
|||
|
|
if (typeof handler?.fetch === "function") return function _fetchHandler(event) {
|
|||
|
|
return handler.fetch(event.req);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const NoHandler = () => kNotFound;
|
|||
|
|
var H3Core = class {
|
|||
|
|
static "~h3" = true;
|
|||
|
|
config;
|
|||
|
|
"~middleware";
|
|||
|
|
"~routes" = [];
|
|||
|
|
constructor(config = {}) {
|
|||
|
|
this["~middleware"] = [];
|
|||
|
|
this.config = config;
|
|||
|
|
this.fetch = this.fetch.bind(this);
|
|||
|
|
this.handler = this.handler.bind(this);
|
|||
|
|
}
|
|||
|
|
fetch(request) {
|
|||
|
|
return this["~request"](request);
|
|||
|
|
}
|
|||
|
|
handler(event) {
|
|||
|
|
const route = this["~findRoute"](event);
|
|||
|
|
if (route) {
|
|||
|
|
event.context.params = route.params;
|
|||
|
|
event.context.matchedRoute = route.data;
|
|||
|
|
}
|
|||
|
|
const routeHandler = route?.data.handler || NoHandler;
|
|||
|
|
const middleware = this["~getMiddleware"](event, route);
|
|||
|
|
return middleware.length > 0 ? callMiddleware(event, middleware, routeHandler) : routeHandler(event);
|
|||
|
|
}
|
|||
|
|
"~request"(request, context) {
|
|||
|
|
const event = new H3Event(request, context, this);
|
|||
|
|
let handlerRes;
|
|||
|
|
try {
|
|||
|
|
if (event[kMalformedURL] && !this.config.allowMalformedURL) throw new HTTPError({
|
|||
|
|
status: 400,
|
|||
|
|
message: "Bad Request"
|
|||
|
|
});
|
|||
|
|
if (this.config.onRequest) {
|
|||
|
|
const hookRes = this.config.onRequest(event);
|
|||
|
|
handlerRes = typeof hookRes?.then === "function" ? hookRes.then(() => this.handler(event)) : this.handler(event);
|
|||
|
|
} else handlerRes = this.handler(event);
|
|||
|
|
} catch (error) {
|
|||
|
|
handlerRes = Promise.reject(error);
|
|||
|
|
}
|
|||
|
|
return toResponse(handlerRes, event, this.config);
|
|||
|
|
}
|
|||
|
|
"~findRoute"(_event) {}
|
|||
|
|
"~addRoute"(_route) {
|
|||
|
|
this["~routes"].push(_route);
|
|||
|
|
}
|
|||
|
|
"~getMiddleware"(_event, route) {
|
|||
|
|
const routeMiddleware = route?.data.middleware;
|
|||
|
|
const globalMiddleware = this["~middleware"];
|
|||
|
|
return routeMiddleware ? [...globalMiddleware, ...routeMiddleware] : globalMiddleware;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
const H3 = /* @__PURE__ */ (() => {
|
|||
|
|
class H3 extends H3Core {
|
|||
|
|
"~rou3";
|
|||
|
|
constructor(config = {}) {
|
|||
|
|
super(config);
|
|||
|
|
this["~rou3"] = createRouter();
|
|||
|
|
this.request = this.request.bind(this);
|
|||
|
|
config.plugins?.forEach((plugin) => plugin(this));
|
|||
|
|
}
|
|||
|
|
register(plugin) {
|
|||
|
|
plugin(this);
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
request(_req, _init, context) {
|
|||
|
|
return this["~request"](toRequest(_req, _init), context);
|
|||
|
|
}
|
|||
|
|
mount(base, input) {
|
|||
|
|
if ("handler" in input) {
|
|||
|
|
if (input["~middleware"].length > 0) this["~middleware"].push((event, next) => {
|
|||
|
|
const originalPathname = event.url.pathname;
|
|||
|
|
if (!originalPathname.startsWith(base) || originalPathname.length > base.length && originalPathname[base.length] !== "/") return next();
|
|||
|
|
event.url.pathname = event.url.pathname.slice(base.length) || "/";
|
|||
|
|
const restore = () => {
|
|||
|
|
event.url.pathname = originalPathname;
|
|||
|
|
};
|
|||
|
|
try {
|
|||
|
|
const result = callMiddleware(event, input["~middleware"], () => {
|
|||
|
|
restore();
|
|||
|
|
return next();
|
|||
|
|
});
|
|||
|
|
if (typeof result?.then === "function") return Promise.resolve(result).finally(restore);
|
|||
|
|
restore();
|
|||
|
|
return result;
|
|||
|
|
} catch (err) {
|
|||
|
|
restore();
|
|||
|
|
throw err;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
for (const r of input["~routes"]) this["~addRoute"]({
|
|||
|
|
...r,
|
|||
|
|
route: base + r.route
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
const fetchHandler = "fetch" in input ? input.fetch : input;
|
|||
|
|
this.all(`${base}/**`, function _mountedMiddleware(event) {
|
|||
|
|
return fetchHandler(requestWithBaseURL(event.req, base));
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
on(method, route, handler, opts) {
|
|||
|
|
const _method = (method || "").toUpperCase();
|
|||
|
|
route = new URL(route, "http://_").pathname;
|
|||
|
|
this["~addRoute"]({
|
|||
|
|
method: _method,
|
|||
|
|
route,
|
|||
|
|
handler: toEventHandler(handler),
|
|||
|
|
middleware: opts?.middleware,
|
|||
|
|
meta: {
|
|||
|
|
...handler.meta,
|
|||
|
|
...opts?.meta
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
all(route, handler, opts) {
|
|||
|
|
return this.on("", route, handler, opts);
|
|||
|
|
}
|
|||
|
|
"~findRoute"(_event) {
|
|||
|
|
const match = findRoute(this["~rou3"], _event.req.method, _event.url.pathname);
|
|||
|
|
if (match === void 0 && _event.req.method === "HEAD") return findRoute(this["~rou3"], "GET", _event.url.pathname);
|
|||
|
|
return match;
|
|||
|
|
}
|
|||
|
|
"~addRoute"(_route) {
|
|||
|
|
addRoute(this["~rou3"], _route.method, _route.route, _route);
|
|||
|
|
super["~addRoute"](_route);
|
|||
|
|
}
|
|||
|
|
use(arg1, arg2, arg3) {
|
|||
|
|
let route;
|
|||
|
|
let fn;
|
|||
|
|
let opts;
|
|||
|
|
if (typeof arg1 === "string") {
|
|||
|
|
route = arg1;
|
|||
|
|
fn = arg2;
|
|||
|
|
opts = arg3;
|
|||
|
|
} else {
|
|||
|
|
fn = arg1;
|
|||
|
|
opts = arg2;
|
|||
|
|
}
|
|||
|
|
if (typeof fn !== "function" && "handler" in fn) return this.mount(route || "", fn);
|
|||
|
|
this["~middleware"].push(normalizeMiddleware(fn, {
|
|||
|
|
...opts,
|
|||
|
|
route
|
|||
|
|
}));
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for (const method of [
|
|||
|
|
"GET",
|
|||
|
|
"POST",
|
|||
|
|
"PUT",
|
|||
|
|
"DELETE",
|
|||
|
|
"PATCH",
|
|||
|
|
"HEAD",
|
|||
|
|
"OPTIONS",
|
|||
|
|
"CONNECT",
|
|||
|
|
"TRACE",
|
|||
|
|
"QUERY"
|
|||
|
|
]) H3Core.prototype[method.toLowerCase()] = function(route, handler, opts) {
|
|||
|
|
return this.on(method, route, handler, opts);
|
|||
|
|
};
|
|||
|
|
return H3;
|
|||
|
|
})();
|
|||
|
|
/%(?:25)*(?:2f|5c)/i.source;
|
|||
|
|
const lazyEventHandler = defineLazyEventHandler;
|
|||
|
|
//#endregion
|
|||
|
|
//#region ../nuxi/src/commands/analyze.ts
|
|||
|
|
const NON_WORD_RE = /[^\w-]/g;
|
|||
|
|
const indexHtml = `
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="utf-8">
|
|||
|
|
<title>Nuxt Bundle Stats (experimental)</title>
|
|||
|
|
</head>
|
|||
|
|
<h1>Nuxt Bundle Stats (experimental)</h1>
|
|||
|
|
<ul>
|
|||
|
|
<li>
|
|||
|
|
<a href="/nitro">Nitro server bundle stats</a>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<a href="/client">Client bundle stats</a>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
</html>
|
|||
|
|
`.trim();
|
|||
|
|
var analyze_default = defineCommand({
|
|||
|
|
meta: {
|
|||
|
|
name: "analyze",
|
|||
|
|
description: "Build Nuxt and analyze production bundle (experimental)"
|
|||
|
|
},
|
|||
|
|
args: {
|
|||
|
|
...cwdArgs,
|
|||
|
|
...logLevelArgs,
|
|||
|
|
...legacyRootDirArgs,
|
|||
|
|
...dotEnvArgs,
|
|||
|
|
...extendsArgs,
|
|||
|
|
name: {
|
|||
|
|
type: "string",
|
|||
|
|
description: "Name of the analysis",
|
|||
|
|
default: "default",
|
|||
|
|
valueHint: "name"
|
|||
|
|
},
|
|||
|
|
serve: {
|
|||
|
|
type: "boolean",
|
|||
|
|
description: "Serve the analysis results",
|
|||
|
|
negativeDescription: "Skip serving the analysis results",
|
|||
|
|
default: true
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
async run(ctx) {
|
|||
|
|
overrideEnv("production");
|
|||
|
|
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
|||
|
|
const name = ctx.args.name || "default";
|
|||
|
|
const slug = name.trim().replace(NON_WORD_RE, "_");
|
|||
|
|
intro(colors.cyan("Analyzing bundle size..."));
|
|||
|
|
const startTime = Date.now();
|
|||
|
|
const { loadNuxt, buildNuxt } = await loadKit(cwd);
|
|||
|
|
const nuxt = await loadNuxt({
|
|||
|
|
cwd,
|
|||
|
|
dotenv: {
|
|||
|
|
cwd,
|
|||
|
|
fileName: ctx.args.dotenv
|
|||
|
|
},
|
|||
|
|
overrides: defu$1(ctx.data?.overrides, {
|
|||
|
|
...ctx.args.extends && { extends: ctx.args.extends },
|
|||
|
|
build: { analyze: { enabled: true } },
|
|||
|
|
vite: { build: { rollupOptions: { output: {
|
|||
|
|
chunkFileNames: "_nuxt/[name].js",
|
|||
|
|
entryFileNames: "_nuxt/[name].js"
|
|||
|
|
} } } },
|
|||
|
|
logLevel: ctx.args.logLevel
|
|||
|
|
})
|
|||
|
|
});
|
|||
|
|
const analyzeDir = nuxt.options.analyzeDir;
|
|||
|
|
const buildDir = nuxt.options.buildDir;
|
|||
|
|
const outDir = nuxt.options.nitro.output?.dir || join(nuxt.options.rootDir, ".output");
|
|||
|
|
nuxt.options.build.analyze = defu$1(nuxt.options.build.analyze, { filename: join(analyzeDir, "client.html") });
|
|||
|
|
const tasklog = taskLog({
|
|||
|
|
title: "Building Nuxt with analysis enabled",
|
|||
|
|
retainLog: false,
|
|||
|
|
limit: 1
|
|||
|
|
});
|
|||
|
|
tasklog.message("Clearing analyze directory...");
|
|||
|
|
await clearDir(analyzeDir);
|
|||
|
|
tasklog.message("Building Nuxt...");
|
|||
|
|
await buildNuxt(nuxt);
|
|||
|
|
tasklog.success("Build complete");
|
|||
|
|
const meta = {
|
|||
|
|
name,
|
|||
|
|
slug,
|
|||
|
|
startTime,
|
|||
|
|
endTime: Date.now(),
|
|||
|
|
analyzeDir,
|
|||
|
|
buildDir,
|
|||
|
|
outDir
|
|||
|
|
};
|
|||
|
|
await nuxt.callHook("build:analyze:done", meta);
|
|||
|
|
await promises.writeFile(join(analyzeDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
|
|||
|
|
note(`${relativeToProcess(analyzeDir)}\n\nDo not deploy analyze results! Use ${colors.cyan("nuxt build")} before deploying.`, "Build location");
|
|||
|
|
if (ctx.args.serve !== false && !process.env.CI) {
|
|||
|
|
const app = new H3();
|
|||
|
|
const opts = { headers: { "content-type": "text/html" } };
|
|||
|
|
const serveFile = (filePath) => lazyEventHandler(async () => {
|
|||
|
|
const contents = await promises.readFile(filePath, "utf-8");
|
|||
|
|
return () => new Response(contents, opts);
|
|||
|
|
});
|
|||
|
|
logger.step("Starting stats server...");
|
|||
|
|
app.use("/client", serveFile(join(analyzeDir, "client.html")));
|
|||
|
|
app.use("/nitro", serveFile(join(analyzeDir, "nitro.html")));
|
|||
|
|
app.use(() => new Response(indexHtml, opts));
|
|||
|
|
await serve(app).serve();
|
|||
|
|
} else outro("✨ Analysis build complete!");
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
//#endregion
|
|||
|
|
export { analyze_default as default };
|