'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const ufo = require('ufo'); const destr = require('destr'); const cookieEs = require('cookie-es'); const radix3 = require('radix3'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; } const destr__default = /*#__PURE__*/_interopDefaultLegacy(destr); class H3Error extends Error { constructor() { super(...arguments); this.statusCode = 500; this.fatal = false; this.unhandled = false; this.statusMessage = "Internal Server Error"; } } H3Error.__h3_error__ = true; function createError(input) { if (typeof input === "string") { return new H3Error(input); } if (isError(input)) { return input; } const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0); if ("stack" in input) { try { Object.defineProperty(err, "stack", { get() { return input.stack; } }); } catch { try { err.stack = input.stack; } catch { } } } if (input.statusCode) { err.statusCode = input.statusCode; } if (input.statusMessage) { err.statusMessage = input.statusMessage; } if (input.data) { err.data = input.data; } if (input.fatal !== void 0) { err.fatal = input.fatal; } if (input.unhandled !== void 0) { err.unhandled = input.unhandled; } return err; } function sendError(event, error, debug) { if (event.res.writableEnded) { return; } const h3Error = isError(error) ? error : createError(error); const responseBody = { statusCode: h3Error.statusCode, statusMessage: h3Error.statusMessage, stack: [], data: h3Error.data }; if (debug) { responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim()); } if (event.res.writableEnded) { return; } event.res.statusCode = h3Error.statusCode; event.res.statusMessage = h3Error.statusMessage; event.res.setHeader("Content-Type", MIMES.json); event.res.end(JSON.stringify(responseBody, null, 2)); } function isError(input) { return input?.constructor?.__h3_error__ === true; } function getQuery(event) { return ufo.getQuery(event.req.url || ""); } const useQuery = getQuery; function getRouterParams(event) { return event.context.params || {}; } function getRouterParam(event, name) { const params = getRouterParams(event); return params[name]; } function getMethod(event, defaultMethod = "GET") { return (event.req.method || defaultMethod).toUpperCase(); } const useMethod = getMethod; function isMethod(event, expected, allowHead) { const method = getMethod(event); if (allowHead && method === "HEAD") { return true; } if (typeof expected === "string") { if (method === expected) { return true; } } else if (expected.includes(method)) { return true; } return false; } function assertMethod(event, expected, allowHead) { if (!isMethod(event, expected, allowHead)) { throw createError({ statusCode: 405, statusMessage: "HTTP method is not allowed." }); } } function getRequestHeaders(event) { return event.req.headers; } const getHeaders = getRequestHeaders; function getRequestHeader(event, name) { const headers = getRequestHeaders(event); const value = headers[name.toLowerCase()]; return value; } const getHeader = getRequestHeader; const RawBodySymbol = Symbol.for("h3RawBody"); const ParsedBodySymbol = Symbol.for("h3ParsedBody"); const PayloadMethods = ["PATCH", "POST", "PUT", "DELETE"]; function readRawBody(event, encoding = "utf-8") { assertMethod(event, PayloadMethods); if (RawBodySymbol in event.req) { const promise2 = Promise.resolve(event.req[RawBodySymbol]); return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2; } if ("body" in event.req) { return Promise.resolve(event.req.body); } const promise = event.req[RawBodySymbol] = new Promise((resolve, reject) => { const bodyData = []; event.req.on("error", (err) => { reject(err); }).on("data", (chunk) => { bodyData.push(chunk); }).on("end", () => { resolve(Buffer.concat(bodyData)); }); }); return encoding ? promise.then((buff) => buff.toString(encoding)) : promise; } const useRawBody = readRawBody; async function readBody(event) { if (ParsedBodySymbol in event.req) { return event.req[ParsedBodySymbol]; } const body = await readRawBody(event); if (event.req.headers["content-type"] === "application/x-www-form-urlencoded") { const parsedForm = Object.fromEntries(new URLSearchParams(body)); return parsedForm; } const json = destr__default(body); event.req[ParsedBodySymbol] = json; return json; } const useBody = readBody; function handleCacheHeaders(event, opts) { const cacheControls = ["public"].concat(opts.cacheControls || []); let cacheMatched = false; if (opts.maxAge !== void 0) { cacheControls.push(`max-age=${+opts.maxAge}`, `s-maxage=${+opts.maxAge}`); } if (opts.modifiedTime) { const modifiedTime = new Date(opts.modifiedTime); const ifModifiedSince = event.req.headers["if-modified-since"]; event.res.setHeader("Last-Modified", modifiedTime.toUTCString()); if (ifModifiedSince) { if (new Date(ifModifiedSince) >= opts.modifiedTime) { cacheMatched = true; } } } if (opts.etag) { event.res.setHeader("Etag", opts.etag); const ifNonMatch = event.req.headers["if-none-match"]; if (ifNonMatch === opts.etag) { cacheMatched = true; } } event.res.setHeader("Cache-Control", cacheControls.join(", ")); if (cacheMatched) { event.res.statusCode = 304; event.res.end(""); return true; } return false; } const MIMES = { html: "text/html", json: "application/json" }; const defer = typeof setImmediate !== "undefined" ? setImmediate : (fn) => fn(); function send(event, data, type) { if (type) { defaultContentType(event, type); } return new Promise((resolve) => { defer(() => { event.res.end(data); resolve(void 0); }); }); } function defaultContentType(event, type) { if (type && !event.res.getHeader("Content-Type")) { event.res.setHeader("Content-Type", type); } } function sendRedirect(event, location, code = 302) { event.res.statusCode = code; event.res.setHeader("Location", location); const encodedLoc = location.replace(/"/g, "%22"); const html = ``; return send(event, html, MIMES.html); } function getResponseHeaders(event) { return event.res.getHeaders(); } function getResponseHeader(event, name) { return event.res.getHeader(name); } function setResponseHeaders(event, headers) { Object.entries(headers).forEach(([name, value]) => event.res.setHeader(name, value)); } const setHeaders = setResponseHeaders; function setResponseHeader(event, name, value) { event.res.setHeader(name, value); } const setHeader = setResponseHeader; function appendResponseHeaders(event, headers) { Object.entries(headers).forEach(([name, value]) => appendResponseHeader(event, name, value)); } const appendHeaders = appendResponseHeaders; function appendResponseHeader(event, name, value) { let current = event.res.getHeader(name); if (!current) { event.res.setHeader(name, value); return; } if (!Array.isArray(current)) { current = [current.toString()]; } event.res.setHeader(name, current.concat(value)); } const appendHeader = appendResponseHeader; function isStream(data) { return data && typeof data === "object" && typeof data.pipe === "function" && typeof data.on === "function"; } function sendStream(event, data) { return new Promise((resolve, reject) => { data.pipe(event.res); data.on("end", () => resolve(void 0)); data.on("error", (error) => reject(createError(error))); }); } function parseCookies(event) { return cookieEs.parse(event.req.headers.cookie || ""); } const useCookies = parseCookies; function getCookie(event, name) { return parseCookies(event)[name]; } const useCookie = getCookie; function setCookie(event, name, value, serializeOptions) { const cookieStr = cookieEs.serialize(name, value, { path: "/", ...serializeOptions }); appendHeader(event, "Set-Cookie", cookieStr); } function deleteCookie(event, name, serializeOptions) { setCookie(event, name, "", { ...serializeOptions, maxAge: 0 }); } class H3Headers { constructor(init) { if (!init) { this._headers = {}; } else if (Array.isArray(init)) { this._headers = Object.fromEntries(init.map(([key, value]) => [key.toLowerCase(), value])); } else if (init && "append" in init) { this._headers = Object.fromEntries([...init.entries()]); } else { this._headers = Object.fromEntries(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value])); } } append(name, value) { const _name = name.toLowerCase(); this.set(_name, [this.get(_name), value].filter(Boolean).join(", ")); } delete(name) { delete this._headers[name.toLowerCase()]; } get(name) { return this._headers[name.toLowerCase()]; } has(name) { return name.toLowerCase() in this._headers; } set(name, value) { this._headers[name.toLowerCase()] = String(value); } forEach(callbackfn) { Object.entries(this._headers).forEach(([key, value]) => callbackfn(value, key, this)); } } class H3Response { constructor(body = null, init = {}) { this.body = null; this.type = "default"; this.bodyUsed = false; this.headers = new H3Headers(init.headers); this.status = init.status ?? 200; this.statusText = init.statusText || ""; this.redirected = !!init.status && [301, 302, 307, 308].includes(init.status); this._body = body; this.url = ""; this.ok = this.status < 300 && this.status > 199; } clone() { return new H3Response(this.body, { headers: this.headers, status: this.status, statusText: this.statusText }); } arrayBuffer() { return Promise.resolve(this._body); } blob() { return Promise.resolve(this._body); } formData() { return Promise.resolve(this._body); } json() { return Promise.resolve(this._body); } text() { return Promise.resolve(this._body); } } class H3Event { constructor(req, res) { this["__is_event__"] = true; this.context = {}; this.req = req; this.res = res; this.event = this; req.event = this; req.context = this.context; req.req = req; req.res = res; res.event = this; res.res = res; res.req = res.req || {}; res.req.res = res; res.req.req = req; } respondWith(r) { Promise.resolve(r).then((_response) => { if (this.res.writableEnded) { return; } const response = _response instanceof H3Response ? _response : new H3Response(_response); response.headers.forEach((value, key) => { this.res.setHeader(key, value); }); if (response.status) { this.res.statusCode = response.status; } if (response.statusText) { this.res.statusMessage = response.statusText; } if (response.redirected) { this.res.setHeader("Location", response.url); } if (!response._body) { return this.res.end(); } if (typeof response._body === "string" || "buffer" in response._body || "byteLength" in response._body) { return this.res.end(response._body); } if (!response.headers.has("content-type")) { response.headers.set("content-type", MIMES.json); } this.res.end(JSON.stringify(response._body)); }); } } function isEvent(input) { return "__is_event__" in input; } function createEvent(req, res) { return new H3Event(req, res); } const defineHandler = (handler) => handler; const defineHandle = defineHandler; const defineMiddleware = (middleware) => middleware; function promisifyHandler(handler) { return function(req, res) { return callHandler(handler, req, res); }; } const promisifyHandle = promisifyHandler; function callHandler(handler, req, res) { const isMiddleware = handler.length > 2; return new Promise((resolve, reject) => { const next = (err) => { if (isMiddleware) { res.off("close", next); res.off("error", next); } return err ? reject(createError(err)) : resolve(void 0); }; try { const returned = handler(req, res, next); if (isMiddleware && returned === void 0) { res.once("close", next); res.once("error", next); } else { resolve(returned); } } catch (err) { next(err); } }); } function defineLazyHandler(handler, promisify) { let _promise; const resolve = () => { if (!_promise) { _promise = Promise.resolve(handler()).then((r) => promisify ? promisifyHandler(r.default || r) : r.default || r); } return _promise; }; return function(req, res) { return resolve().then((h) => h(req, res)); }; } const lazyHandle = defineLazyHandler; function useBase(base, handler) { base = ufo.withoutTrailingSlash(base); if (!base) { return handler; } return function(req, res) { req.originalUrl = req.originalUrl || req.url || "/"; req.url = ufo.withoutBase(req.url || "/", base); return handler(req, res); }; } function defineEventHandler(handler) { handler.__is_handler__ = true; return handler; } const eventHandler = defineEventHandler; function isEventHandler(input) { return "__is_handler__" in input; } function toEventHandler(handler) { if (isEventHandler(handler)) { return handler; } if (typeof handler !== "function") { throw new TypeError("Invalid handler. It should be a function:", handler); } return eventHandler((event) => { return callHandler(handler, event.req, event.res); }); } function dynamicEventHandler(initial) { let current = initial; const wrapper = eventHandler((event) => { if (current) { return current(event); } }); wrapper.set = (handler) => { current = handler; }; return wrapper; } function defineLazyEventHandler(factory) { let _promise; let _resolved; const resolveHandler = () => { if (_resolved) { return Promise.resolve(_resolved); } if (!_promise) { _promise = Promise.resolve(factory()).then((r) => { const handler = r.default || r; if (typeof handler !== "function") { throw new TypeError("Invalid lazy handler result. It should be a function:", handler); } _resolved = toEventHandler(r.default || r); return _resolved; }); } return _promise; }; return eventHandler((event) => { if (_resolved) { return _resolved(event); } return resolveHandler().then((handler) => handler(event)); }); } const lazyEventHandler = defineLazyEventHandler; function createApp(options = {}) { const stack = []; const handler = createAppEventHandler(stack, options); const nodeHandler = async function(req, res) { const event = createEvent(req, res); try { await handler(event); } catch (_error) { const error = createError(_error); if (!isError(_error)) { error.unhandled = true; } if (options.onError) { await options.onError(error, event); } else { if (error.unhandled || error.fatal) { console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error); } await sendError(event, error, !!options.debug); } } }; const app = nodeHandler; app.nodeHandler = nodeHandler; app.stack = stack; app.handler = handler; app.use = (arg1, arg2, arg3) => use(app, arg1, arg2, arg3); return app; } function use(app, arg1, arg2, arg3) { if (Array.isArray(arg1)) { arg1.forEach((i) => use(app, i, arg2, arg3)); } else if (Array.isArray(arg2)) { arg2.forEach((i) => use(app, arg1, i, arg3)); } else if (typeof arg1 === "string") { app.stack.push(normalizeLayer({ ...arg3, route: arg1, handler: arg2 })); } else if (typeof arg1 === "function") { app.stack.push(normalizeLayer({ ...arg2, route: "/", handler: arg1 })); } else { app.stack.push(normalizeLayer({ ...arg1 })); } return app; } function createAppEventHandler(stack, options) { const spacing = options.debug ? 2 : void 0; return eventHandler(async (event) => { event.req.originalUrl = event.req.originalUrl || event.req.url || "/"; const reqUrl = event.req.url || "/"; for (const layer of stack) { if (layer.route.length > 1) { if (!reqUrl.startsWith(layer.route)) { continue; } event.req.url = reqUrl.slice(layer.route.length) || "/"; } else { event.req.url = reqUrl; } if (layer.match && !layer.match(event.req.url, event)) { continue; } const val = await layer.handler(event); if (event.res.writableEnded) { return; } const type = typeof val; if (type === "string") { return send(event, val, MIMES.html); } else if (isStream(val)) { return sendStream(event, val); } else if (val === null) { event.res.statusCode = 204; return send(event); } else if (type === "object" || type === "boolean" || type === "number") { if (val.buffer) { return send(event, val); } else if (val instanceof Error) { throw createError(val); } else { return send(event, JSON.stringify(val, null, spacing), MIMES.json); } } } if (!event.res.writableEnded) { throw createError({ statusCode: 404, statusMessage: "Not Found" }); } }); } function normalizeLayer(input) { let handler = input.handler || input.handle; if (handler.handler) { handler = handler.handler; } if (input.lazy) { handler = lazyEventHandler(handler); } else if (!isEventHandler(handler)) { handler = toEventHandler(handler); } return { route: ufo.withoutTrailingSlash(input.route), match: input.match, handler }; } const RouterMethods = ["connect", "delete", "get", "head", "options", "post", "put", "trace", "patch"]; function createRouter() { const _router = radix3.createRouter({}); const routes = {}; const router = {}; const addRoute = (path, handler, method) => { let route = routes[path]; if (!route) { routes[path] = route = { handlers: {} }; _router.insert(path, route); } if (Array.isArray(method)) { method.forEach((m) => addRoute(path, handler, m)); } else { route.handlers[method] = toEventHandler(handler); } return router; }; router.use = router.add = (path, handler, method) => addRoute(path, handler, method || "all"); for (const method of RouterMethods) { router[method] = (path, handle) => router.add(path, handle, method); } router.handler = eventHandler((event) => { let path = event.req.url || "/"; const queryUrlIndex = path.lastIndexOf("?"); if (queryUrlIndex > -1) { path = path.substring(0, queryUrlIndex); } const matched = _router.lookup(path); if (!matched) { throw createError({ statusCode: 404, name: "Not Found", statusMessage: `Cannot find any route matching ${event.req.url || "/"}.` }); } const method = (event.req.method || "get").toLowerCase(); const handler = matched.handlers[method] || matched.handlers.all; if (!handler) { throw createError({ statusCode: 405, name: "Method Not Allowed", statusMessage: `Method ${method} is not allowed on this route.` }); } const params = matched.params || {}; event.event.context.params = params; event.req.context.params = params; return handler(event); }); return router; } exports.H3Error = H3Error; exports.H3Event = H3Event; exports.H3Headers = H3Headers; exports.H3Response = H3Response; exports.MIMES = MIMES; exports.appendHeader = appendHeader; exports.appendHeaders = appendHeaders; exports.appendResponseHeader = appendResponseHeader; exports.appendResponseHeaders = appendResponseHeaders; exports.assertMethod = assertMethod; exports.callHandler = callHandler; exports.createApp = createApp; exports.createAppEventHandler = createAppEventHandler; exports.createError = createError; exports.createEvent = createEvent; exports.createRouter = createRouter; exports.defaultContentType = defaultContentType; exports.defineEventHandler = defineEventHandler; exports.defineHandle = defineHandle; exports.defineHandler = defineHandler; exports.defineLazyEventHandler = defineLazyEventHandler; exports.defineLazyHandler = defineLazyHandler; exports.defineMiddleware = defineMiddleware; exports.deleteCookie = deleteCookie; exports.dynamicEventHandler = dynamicEventHandler; exports.eventHandler = eventHandler; exports.getCookie = getCookie; exports.getHeader = getHeader; exports.getHeaders = getHeaders; exports.getMethod = getMethod; exports.getQuery = getQuery; exports.getRequestHeader = getRequestHeader; exports.getRequestHeaders = getRequestHeaders; exports.getResponseHeader = getResponseHeader; exports.getResponseHeaders = getResponseHeaders; exports.getRouterParam = getRouterParam; exports.getRouterParams = getRouterParams; exports.handleCacheHeaders = handleCacheHeaders; exports.isError = isError; exports.isEvent = isEvent; exports.isEventHandler = isEventHandler; exports.isMethod = isMethod; exports.isStream = isStream; exports.lazyEventHandler = lazyEventHandler; exports.lazyHandle = lazyHandle; exports.parseCookies = parseCookies; exports.promisifyHandle = promisifyHandle; exports.promisifyHandler = promisifyHandler; exports.readBody = readBody; exports.readRawBody = readRawBody; exports.send = send; exports.sendError = sendError; exports.sendRedirect = sendRedirect; exports.sendStream = sendStream; exports.setCookie = setCookie; exports.setHeader = setHeader; exports.setHeaders = setHeaders; exports.setResponseHeader = setResponseHeader; exports.setResponseHeaders = setResponseHeaders; exports.toEventHandler = toEventHandler; exports.use = use; exports.useBase = useBase; exports.useBody = useBody; exports.useCookie = useCookie; exports.useCookies = useCookies; exports.useMethod = useMethod; exports.useQuery = useQuery; exports.useRawBody = useRawBody;