h3
Version:
1,547 lines • 94.3 kB
JavaScript
import "./h3-DagAgogP.mjs";
import { NullProtoObj as EmptyObject, addRoute, createRouter, findRoute, removeRoute, routeToRegExp } from "rou3";
import { FastResponse, FastURL } from "srvx";
function freezeApp(app) {
app.config = Object.freeze(app.config);
app["~addRoute"] = () => {
throw new Error("Cannot add routes after the server init.");
};
}
function withLeadingSlash(path) {
if (!path || path === "/") return "/";
return path[0] === "/" ? path : `/${path}`;
}
function withoutTrailingSlash(path) {
if (!path || path === "/") return "/";
return path[path.length - 1] === "/" ? path.slice(0, -1) : path;
}
function withoutBase(input = "", base = "") {
if (!base || base === "/") return input;
const _base = withoutTrailingSlash(base);
if (!input.startsWith(_base) || input.length > _base.length && input[_base.length] !== "/") return input;
return "/" + input.slice(_base.length).replace(/^\/+/, "");
}
function decodePathname(pathname) {
return decodeURI(pathname.includes("%25") ? pathname.replace(/%25/g, "%2525") : pathname);
}
function resolveDotSegments(path) {
if (!path.includes(".") && !path.includes("%2")) return path;
const segments = path.replaceAll("\\", "/").split("/");
const resolved = [];
for (const segment of segments) {
const normalized = segment.replace(/%2e/gi, ".");
if (normalized === "..") {
if (resolved.length > 1) resolved.pop();
} else if (normalized !== ".") resolved.push(segment);
}
return resolved.join("/") || "/";
}
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`);
var H3Event = class {
app;
req;
url;
context;
static __is_event__ = true;
constructor(req, context, app) {
this.context = context || req.context || new EmptyObject();
this.req = req;
this.app = app;
const _url = req._url;
const url = _url && _url instanceof URL ? _url : new FastURL(req.url);
if (url.pathname.includes("%")) url.pathname = decodePathname(url.pathname);
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 (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 hasProp(obj, prop) {
try {
return prop in obj;
} catch {
return false;
}
}
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 EmptyObject) 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) 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 defineMiddleware(input) {
return input;
}
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) 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 toMiddleware(input) {
let h = input.handler || input;
let isFunction = typeof h === "function";
if (!isFunction && typeof input?.fetch === "function") {
isFunction = true;
h = function _fetchHandler(event) {
return input.fetch(event.req);
};
}
if (!isFunction) return function noopMiddleware(event, next) {
return next();
};
if (h.length === 2) return h;
return function _middlewareHandler(event, next) {
const res = h(event);
return typeof res?.then === "function" ? res.then((r) => {
return is404(r) ? next() : r;
}) : is404(res) ? next() : res;
};
}
function is404(val) {
return isUnhandledResponse(val) || val?.status === 404 && val instanceof Response;
}
const plusRegex = /\+/g;
function parseQuery(input) {
const params = new EmptyObject();
if (!input || input === "?") return params;
const inputLength = input.length;
let key = "";
let value = "";
let startingIndex = -1;
let equalityIndex = -1;
let shouldDecodeKey = false;
let shouldDecodeValue = false;
let keyHasPlus = false;
let valueHasPlus = false;
let hasBothKeyValuePair = false;
let c = 0;
for (let i = 0; i < inputLength + 1; i++) {
c = i === inputLength ? 38 : input.charCodeAt(i);
switch (c) {
case 38:
hasBothKeyValuePair = equalityIndex > startingIndex;
if (!hasBothKeyValuePair) equalityIndex = i;
key = input.slice(startingIndex + 1, equalityIndex);
if (hasBothKeyValuePair || key.length > 0) {
if (keyHasPlus) key = key.replace(plusRegex, " ");
if (shouldDecodeKey) try {
key = decodeURIComponent(key);
} catch {}
if (hasBothKeyValuePair) {
value = input.slice(equalityIndex + 1, i);
if (valueHasPlus) value = value.replace(plusRegex, " ");
if (shouldDecodeValue) try {
value = decodeURIComponent(value);
} catch {}
}
const currentValue = params[key];
if (currentValue === void 0) params[key] = value;
else if (Array.isArray(currentValue)) currentValue.push(value);
else params[key] = [currentValue, value];
}
value = "";
startingIndex = i;
equalityIndex = i;
shouldDecodeKey = false;
shouldDecodeValue = false;
keyHasPlus = false;
valueHasPlus = false;
break;
case 61:
if (equalityIndex <= startingIndex) equalityIndex = i;
else shouldDecodeValue = true;
break;
case 43:
if (equalityIndex > startingIndex) valueHasPlus = true;
else keyHasPlus = true;
break;
case 37:
if (equalityIndex > startingIndex) shouldDecodeValue = true;
else shouldDecodeKey = true;
break;
}
}
return params;
}
const VALIDATION_FAILED = "Validation failed";
async function validateData(data, fn, options) {
if ("~standard" in fn) {
const result = await fn["~standard"].validate(data);
if (result.issues) throw createValidationError(options?.onError?.(result) || {
message: VALIDATION_FAILED,
issues: result.issues
});
return result.value;
}
try {
const res = await fn(data);
if (res === false) throw createValidationError(options?.onError?.({ issues: [{ message: VALIDATION_FAILED }] }) || { message: VALIDATION_FAILED });
if (res === true) return data;
return res ?? data;
} catch (error) {
throw createValidationError(error);
}
}
const reqBodyKeys = new Set([
"body",
"text",
"formData",
"arrayBuffer"
]);
function validatedRequest(req, validate) {
if (validate.headers) {
const validatedheaders = syncValidate("headers", Object.fromEntries(req.headers.entries()), validate.headers, validate.onError);
for (const [key, value] of Object.entries(validatedheaders)) req.headers.set(key, value);
}
if (!validate.body) return req;
return new Proxy(req, { get(_target, prop) {
if (validate.body) {
if (prop === "json") return function _validatedJson() {
return req.json().then((data) => validate.body["~standard"].validate(data)).then((result) => {
if (result.issues) throw createValidationError(validate.onError?.({
_source: "body",
...result
}) || {
message: VALIDATION_FAILED,
issues: result.issues
});
return result.value;
});
};
else if (reqBodyKeys.has(prop)) throw new TypeError(`Cannot access .${prop} on request with JSON validation enabled. Use .json() instead.`);
}
return Reflect.get(req, prop);
} });
}
function validatedURL(url, validate) {
if (!validate.query) return url;
const validatedQuery = syncValidate("query", Object.fromEntries(url.searchParams.entries()), validate.query, validate.onError);
for (const [key, value] of Object.entries(validatedQuery)) url.searchParams.set(key, value);
return url;
}
function syncValidate(source, data, fn, onError) {
const result = fn["~standard"].validate(data);
if (result instanceof Promise) throw new TypeError(`Asynchronous validation is not supported for ${source}`);
if (result.issues) throw createValidationError(onError?.({
_source: source,
...result
}) || {
message: VALIDATION_FAILED,
issues: result.issues
});
return result.value;
}
function createValidationError(cause) {
return HTTPError.isError(cause) ? cause : new HTTPError({
cause,
status: cause?.status || 400,
statusText: cause?.statusText || VALIDATION_FAILED,
message: cause?.message || VALIDATION_FAILED,
data: {
issues: cause?.issues,
message: cause instanceof Error ? VALIDATION_FAILED : cause?.message || VALIDATION_FAILED
}
});
}
function isEvent(input) {
return input instanceof H3Event || input?.constructor?.__is_event__;
}
function isHTTPEvent(input) {
return input?.req instanceof Request;
}
function getEventContext(event) {
if (event.context) return event.context;
event.req.context ??= {};
return event.req.context;
}
function mockEvent(_request, options) {
let request;
if (options?.body && !options.duplex) options.duplex = "half";
if (typeof _request === "string") {
let url = _request;
if (url[0] === "/") url = `http://localhost${url}`;
request = new Request(url, options);
} else if (options || _request instanceof URL) request = new Request(_request, options);
else request = _request;
return new H3Event(request);
}
function requestWithURL(req, url) {
const cache = { url };
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);
url.pathname = decodePathname(url.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") === "https" ? "https" : "http"}://${host}${url}`;
}
return new Request(url, options);
} else if (options || input instanceof URL) return new Request(input, options);
return input;
}
function getQuery(event) {
return parseQuery((event.url || new URL(event.req.url)).search.slice(1));
}
function getValidatedQuery(event, validate, options) {
return validateData(getQuery(event), validate, options);
}
function getRouterParams(event, opts = {}) {
let params = getEventContext(event).params || {};
if (opts.decode) {
params = { ...params };
for (const key in params) params[key] = decodeURIComponent(params[key]);
}
return params;
}
function getValidatedRouterParams(event, validate, options = {}) {
const { decode, ...opts } = options;
return validateData(getRouterParams(event, { decode }), validate, opts);
}
function getRouterParam(event, name, opts = {}) {
return getRouterParams(event, opts)[name];
}
function isMethod(event, expected, allowHead) {
if (allowHead && event.req.method === "HEAD") return true;
if (typeof expected === "string") {
if (event.req.method === expected) return true;
} else if (expected.includes(event.req.method)) return true;
return false;
}
function assertMethod(event, expected, allowHead) {
if (!isMethod(event, expected, allowHead)) {
const allowed = Array.isArray(expected) ? expected : [expected];
throw new HTTPError({
status: 405,
headers: { Allow: allowHead ? [...allowed, "HEAD"].join(", ") : allowed.join(", ") }
});
}
}
function getRequestHost(event, opts = {}) {
if (opts.xForwardedHost) {
const xForwardedHost = (event.req.headers.get("x-forwarded-host") || "").split(",").shift()?.trim();
if (xForwardedHost) return xForwardedHost;
}
return event.req.headers.get("host") || "";
}
function getRequestProtocol(event, opts = {}) {
if (opts.xForwardedProto !== false) {
const forwardedProto = event.req.headers.get("x-forwarded-proto");
if (forwardedProto === "https") return "https";
if (forwardedProto === "http") return "http";
}
return (event.url || new URL(event.req.url)).protocol.slice(0, -1);
}
function getRequestURL(event, opts = {}) {
const url = new URL(event.url || event.req.url);
url.protocol = getRequestProtocol(event, opts);
if (opts.xForwardedHost) {
const host = getRequestHost(event, opts);
if (host) {
url.host = host;
if (!/:\d+$/.test(host)) url.port = "";
}
}
return url;
}
function getRequestIP(event, opts = {}) {
if (opts.xForwardedFor) {
const _header = event.req.headers.get("x-forwarded-for");
if (_header) {
const xForwardedFor = _header.split(",")[0].trim();
if (xForwardedFor) return xForwardedFor;
}
}
return event.req.context?.clientAddress || event.req.ip || void 0;
}
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 defineValidatedHandler(def) {
if (!def.validate) return defineHandler(def);
return defineHandler({
...def,
handler: function _validatedHandler(event) {
event.req = validatedRequest(event.req, def.validate);
event.url = validatedURL(event.url, def.validate);
return def.handler(event);
}
});
}
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 dynamicEventHandler(initial) {
let current = toEventHandler(initial);
return Object.assign(defineHandler(function _dynamicEventHandler(event) {
return current?.(event);
}), { set: (handler) => {
current = toEventHandler(handler);
} });
}
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") return handler.handler;
if (typeof handler?.fetch === "function") return function _fetchHandler(event) {
return handler.fetch(event.req);
};
}
const NoHandler = () => kNotFound;
var H3Core = class {
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 (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) || "/";
return callMiddleware(event, input["~middleware"], () => {
event.url.pathname = originalPathname;
return next();
});
});
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) {
return findRoute(this["~rou3"], _event.req.method, _event.url.pathname);
}
"~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"
]) H3Core.prototype[method.toLowerCase()] = function(route, handler, opts) {
return this.on(method, route, handler, opts);
};
return H3;
})();
function toWebHandler(app) {
return (request, context) => {
return Promise.resolve(app.request(request, void 0, context || request.context));
};
}
function fromWebHandler(handler) {
return function _webHandler(event) {
return handler(event.req, event.context);
};
}
function fromNodeHandler(handler) {
if (typeof handler !== "function") throw new TypeError(`Invalid handler. It should be a function: ${handler}`);
return function _nodeHandler(event) {
if (!event.runtime?.node?.res) throw new Error("[h3] Executing Node.js middleware is not supported in this server!");
return callNodeHandler(handler, event.runtime?.node.req, event.runtime?.node.res);
};
}
function defineNodeHandler(handler) {
return handler;
}
function defineNodeMiddleware(handler) {
return handler;
}
function callNodeHandler(handler, req, res) {
const isMiddleware = handler.length > 2;
return new Promise((resolve, reject) => {
res.once("close", () => resolve(kHandled));
res.once("finish", () => resolve(kHandled));
res.once("error", (error) => reject(error));
res.once("pipe", (stream) => {
resolve(new Promise((resolve, reject) => {
stream.once("close", () => resolve(kHandled));
stream.once("error", (error) => {
console.error("[h3] Stream error in Node.js handler", { cause: error });
reject(kHandled);
});
}));
});
try {
if (isMiddleware) Promise.resolve(handler(req, res, (error) => error ? reject(new HTTPError({
cause: error,
unhandled: true
})) : resolve(void 0))).catch((error) => reject(new HTTPError({
cause: error,
unhandled: true
})));
else return Promise.resolve(handler(req, res)).then(() => resolve(kHandled)).catch((error) => reject(new HTTPError({
cause: error,
unhandled: true
})));
} catch (error) {
reject(new HTTPError({
cause: error,
unhandled: true
}));
}
});
}
function defineRoute(def) {
const handler = defineValidatedHandler(def);
return (h3) => {
h3.on(def.method, def.route, handler);
};
}
function removeRoute$1(app, method, route) {
const _method = method ? method.toUpperCase() : void 0;
route = new URL(route, "http://_").pathname;
removeRoute(app["~rou3"], _method || "", route);
const idx = app["~routes"].findIndex((r) => r.route === route && (_method == null || r.method === _method));
if (idx !== -1) app["~routes"].splice(idx, 1);
}
const textEncoder = /* @__PURE__ */ new TextEncoder();
const textDecoder = /* @__PURE__ */ new TextDecoder();
const base64Code = [
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
45,
95
];
function base64Encode(data) {
const buff = validateBinaryLike(data);
if (globalThis.Buffer) return globalThis.Buffer.from(buff).toString("base64url");
const bytes = [];
let i;
const len = buff.length;
for (i = 2; i < len; i += 3) bytes.push(base64Code[buff[i - 2] >> 2], base64Code[(buff[i - 2] & 3) << 4 | buff[i - 1] >> 4], base64Code[(buff[i - 1] & 15) << 2 | buff[i] >> 6], base64Code[buff[i] & 63]);
if (i === len + 1) bytes.push(base64Code[buff[i - 2] >> 2], base64Code[(buff[i - 2] & 3) << 4]);
if (i === len) bytes.push(base64Code[buff[i - 2] >> 2], base64Code[(buff[i - 2] & 3) << 4 | buff[i - 1] >> 4], base64Code[(buff[i - 1] & 15) << 2]);
return String.fromCharCode(...bytes);
}
function base64Decode(b64Url) {
if (globalThis.Buffer) return new Uint8Array(globalThis.Buffer.from(b64Url, "base64url"));
const b64 = b64Url.replace(/-/g, "+").replace(/_/g, "/");
const binString = atob(b64);
const size = binString.length;
const bytes = new Uint8Array(size);
for (let i = 0; i < size; i++) bytes[i] = binString.charCodeAt(i);
return bytes;
}
function validateBinaryLike(source) {
if (typeof source === "string") return textEncoder.encode(source);
else if (source instanceof Uint8Array) return source;
else if (source instanceof ArrayBuffer) return new Uint8Array(source);
throw new TypeError(`The input must be a Uint8Array, a string, or an ArrayBuffer.`);
}
function serializeIterableValue(value) {
switch (typeof value) {
case "string": return textEncoder.encode(value);
case "boolean":
case "number":
case "bigint":
case "symbol": return textEncoder.encode(value.toString());
case "object":
if (value instanceof Uint8Array) return value;
return textEncoder.encode(JSON.stringify(value));
}
return new Uint8Array();
}
function coerceIterable(iterable) {
if (typeof iterable === "function") iterable = iterable();
if (Symbol.iterator in iterable) return iterable[Symbol.iterator]();
if (Symbol.asyncIterator in iterable) return iterable[Symbol.asyncIterator]();
return iterable;
}
function noContent(status = 204) {
return new HTTPResponse(null, {
status,
statusText: "No Content"
});
}
function redirect(location, status = 302, statusText) {
return new HTTPResponse(`<html><head><meta http-equiv="refresh" content="0; url=${location.replace(/[&"<>]/g, (c) => ({
"&": "&",
"\"": """,
"<": "<",
">": ">"
})[c])}" /></head></html>`, {
status,
statusText: statusText || (status === 301 ? "Moved Permanently" : "Found"),
headers: {
"content-type": "text/html; charset=utf-8",
location
}
});
}
function redirectBack(event, opts = {}) {
const referer = event.req.headers.get("referer");
let location = opts.fallback ?? "/";
if (referer && URL.canParse(referer)) {
const refererURL = new URL(referer);
if (refererURL.origin === event.url.origin) {
let pathname = refererURL.pathname;
if (pathname.startsWith("//")) pathname = "/" + pathname.replace(/^\/+/, "");
location = pathname + (opts.allowQuery ? refererURL.search : "");
}
}
return redirect(location, opts.status);
}
function writeEarlyHints(event, hints) {
if (event.runtime?.node?.res?.writeEarlyHints) return new Promise((resolve) => {
event.runtime?.node?.res?.writeEarlyHints(hints, () => resolve());
});
for (const [name, value] of Object.entries(hints)) {
if (name.toLowerCase() !== "link") continue;
if (Array.isArray(value)) for (const v of value) event.res.headers.append("link", v);
else event.res.headers.append("link", value);
}
}
function iterable(iterable, options) {
const serializer = options?.serializer ?? serializeIterableValue;
const iterator = coerceIterable(iterable);
return new HTTPResponse(new ReadableStream({
async pull(controller) {
const { value, done } = await iterator.next();
if (value !== void 0) {
const chunk = serializer(value);
if (chunk !== void 0) controller.enqueue(chunk);
}
if (done) controller.close();
},
cancel() {
iterator.return?.();
}
}));
}
function html(first, ...values) {
return new HTTPResponse(typeof first === "string" ? first : first.reduce((out, str, i) => out + str + (values[i] ?? ""), ""), { headers: { "content-type": "text/html; charset=utf-8" } });
}
function parseURLEncodedBody(body) {
const form = new URLSearchParams(body);
const parsedForm = new EmptyObject();
for (const [key, value] of form.entries()) if (hasProp(parsedForm, key)) {
if (!Array.isArray(parsedForm[key])) parsedForm[key] = [parsedForm[key]];
parsedForm[key].push(value);
} else parsedForm[key] = value;
return parsedForm;
}
async function readBody(event) {
const text = await event.req.text();
if (!text) return;
if ((event.req.headers.get("content-type") || "").startsWith("application/x-www-form-urlencoded")) return parseURLEncodedBody(text);
try {
return JSON.parse(text);
} catch {
throw new HTTPError({
status: 400,
statusText: "Bad Request",
message: "Invalid JSON body"
});
}
}
async function readValidatedBody(event, validate, options) {
return validateData(await readBody(event), validate, options);
}
async function assertBodySize(event, limit) {
if (!await isBodySizeWithin(event, limit)) throw new HTTPError({
status: 413,
statusText: "Request Entity Too Large",
message: `Request body size exceeds the limit of ${limit} bytes`
});
}
async function isBodySizeWithin(event, limit) {
const req = event.req;
if (req.body === null) return true;
const contentLength = req.headers.get("content-length");
if (contentLength) {
if (req.headers.get("transfer-encoding")) throw new HTTPError({ status: 400 });
if (+contentLength > limit) return false;
}
const reader = req.clone().body.getReader();
let chunk = await reader.read();
let size = 0;
while (!chunk.done) {
size += chunk.value.byteLength;
if (size > limit) {
reader.cancel();
return false;
}
chunk = await reader.read();
}
return true;
}
function onRequest(hook) {
return async function _onRequestMiddleware(event) {
await hook(event);
};
}
function onResponse(hook) {
return async function _onResponseMiddleware(event, next) {
const response = await toResponse(await next(), event);
return await hook(response, event) || response;
};
}
function onError(hook) {
return async (event, next) => {
try {
return await next();
} catch (rawError) {
const isHTTPError = HTTPError.isError(rawError);
const error = isHTTPError ? rawError : new HTTPError(rawError);
if (!isHTTPError) {
error.unhandled = true;
if (rawError?.stack) error.stack = rawError.stack;
}
const hookResponse = await hook(error, event);
if (hookResponse !== void 0) return hookResponse;
throw error;
}
};
}
function bodyLimit(limit) {
return async (event, next) => {
await assertBodySize(event, limit);
return next();
};
}
const PayloadMethods = new Set([
"PATCH",
"POST",
"PUT",
"DELETE"
]);
const ignoredHeaders = new Set([
"transfer-encoding",
"connection",
"keep-alive",
"upgrade",
"expect",
"host",
"accept"
]);
function rewriteCookieProperty(header, map, property) {
const _map = typeof map === "string" ? { "*": map } : map;
return header.replace(new RegExp(`(;\\s*${property}=)([^;]+)`, "gi"), (match, prefix, previousValue) => {
let newValue;
if (previousValue in _map) newValue = _map[previousValue];
else if ("*" in _map) newValue = _map["*"];
else return match;
return newValue ? prefix + newValue : "";
});
}
function mergeHeaders(defaults, ...inputs) {
const _inputs = inputs.filter(Boolean);
if (_inputs.length === 0) return defaults;
const merged = new Headers(defaults);
for (const input of _inputs) {
const entries = Array.isArray(input) ? input : typeof input.entries === "function" ? input.entries() : Object.entries(input);
for (const [key, value] of entries) if (value !== void 0) merged.set(key, value);
}
return merged;
}
async function proxyRequest(event, target, opts = {}) {
const requestBody = PayloadMethods.has(event.req.method) ? event.req.body : void 0;
const method = opts.fetchOptions?.method || event.req.method;
const fetchHeaders = mergeHeaders(getProxyRequestHeaders(event, {
host: target.startsWith("/"),
forwardHeaders: opts.forwardHeaders,
filterHeaders: opts.filterHeaders
}), opts.fetchOptions?.headers, opts.headers);
return proxy(event, target, {
...opts,
fetchOptions: {
method,
body: requestBody,
duplex: requestBody ? "half" : void 0,
...opts.fetchOptions,
headers: fetchHeaders
}
});
}
async function proxy(event, target, opts = {}) {
const fetchOptions = {
headers: opts.headers,
...opts.fetchOptions
};
let response;
try {
response = target[0] === "/" ? await event.app.fetch(createSubRequest(event, target, fetchOptions)) : await fetch(target, fetchOptions);
} catch (error) {
throw new HTTPError({
status: 502,
cause: error
});
}
const headers = new Headers();
const cookies = [];
for (const [key, value] of response.headers.entries()) {
if (key === "content-encoding" || key === "content-length" || key === "transfer-encoding") continue;
if (key === "set-cookie") {
cookies.push(value);
continue;
}
headers.append(key, value);
}
if (cookies.length > 0) {
const _cookies = cookies.map((cookie) => {
if (opts.cookieDomainRewrite) cookie = rewriteCookieProperty(cookie, opts.cookieDomainRewrite, "domain");
if (opts.cookiePathRewrite) cookie = rewriteCookieProperty(cookie, opts.cookiePathRewrite, "path");
return cookie;
});
for (const cookie of _cookies) headers.append("set-cookie", cookie);
}
if (opts.onResponse) await opts.onResponse(event, response);
return new HTTPResponse(response.body, {
status: response.status,
statusText: response.statusText,
headers
});
}
function getProxyRequestHeaders(event, opts) {
const headers = new EmptyObject();
for (const [name, value] of event.req.headers.entries()) {
if (opts?.filterHeaders?.includes(name)) continue;
if (opts?.forwardHeaders?.includes(name)) {
headers[name] = value;
continue;
}
if (!ignoredHeaders.has(name) || name === "host" && opts?.host) {
headers[name] = value;
continue;
}
}
return headers;
}
async function fetchWithEvent(event, url, init) {
if (url[0] !== "/") return fetch(url, init);
return event.app.fetch(createSubRequest(event, url, {
...init,
headers: mergeHeaders(getProxyRequestHeaders(event, { host: true }), init?.headers)
}));
}
function createSubRequest(event, path, init) {
const url = new URL(path, event.url);
const req = new Request(url, init);
req.runtime = event.req.runtime;
req.waitUntil = event.req.waitUntil;
req.ip = event.req.ip;
return req;
}
const COOKIE_MAX_AGE_LIMIT = 3456e4;
function endIndex(str, min, len) {
const index = str.indexOf(";", min);
return index === -1 ? len : index;
}
function eqIndex(str, min, max) {
const index = str.indexOf("=", min);
return index < max ? index : -1;
}
function valueSlice(str, min, max) {
if (min === max) return "";
let start = min;
let end = max;
do {
const code = str.charCodeAt(start);
if (code !== 32 && code !== 9) break;
} while (++start < end);
while (end > start) {
const code = str.charCodeAt(end - 1);
if (code !== 32 && code !== 9) break;
end--;
}
return str.slice(start, end);
}
const NullObject = /* @__PURE__ */ (() => {
const C = function() {};
C.prototype = Object.create(null);
return C;
})();
function parse(str, options) {
const obj = new NullObject();
const len = str.length;
if (len < 2) return obj;
const dec = options?.decode || decode;
const allowMultiple = options?.allowMultiple || false;
let index = 0;
do {
const eqIdx = eqIndex(str, index, len);
if (eqIdx === -1) break;
const endIdx = endIndex(str, index, len);
if (eqIdx > endIdx) {
index = str.lastIndexOf(";", eqIdx - 1) + 1;
continue;
}
const key = valueSlice(str, index, eqIdx);
if (options?.filter && !options.filter(key)) {
index = endIdx + 1;
continue;
}
const val = dec(valueSlice(str, eqIdx + 1, endIdx));
if (allowMultiple) {
const existing = obj[key];
if (existing === void 0) obj[key] = val;
else if (Array.isArray(existing)) existing.push(val);
else obj[key] = [existing, val];
} else if (obj[key] === void 0) obj[key] = val;
index = endIdx + 1;
} while (index < len);
return obj;
}
function decode(str) {
if (!str.includes("%")) return str;
try {
return decodeURIComponent(str);
} catch {
return str;
}
}
const cookieNameRegExp = /^[\u0021-\u003A\u003C\u003E-\u007E]+$/;
const cookieValueRegExp = /^[\u0021-\u003A\u003C-\u007E]*$/;
const domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
const pathValueRegExp = /^[\u0020-\u003A\u003C-\u007E]*$/;
const __toString = Object.prototype.toString;
function serialize(_a0, _a1, _a2) {
const isObj = typeof _a0 === "object" && _a0 !== null;
const options = isObj ? _a1 : _a2;
const stringify = options?.stringify || JSON.stringify;
const cookie = isObj ? _a0 : {
..._a2,
name: _a0,
value: _a1 == void 0 ? "" : typeof _a1 === "string" ? _a1 : stringify(_a1)
};
const enc = options?.encode || encodeURIComponent;
if (!cookieNameRegExp.test(cookie.name)) throw new TypeError(`argument name is invalid: ${cookie.name}`);
const value = cookie.value ? enc(cookie.value) : "";
if (!cookieValueRegExp.test(value)) throw new TypeError(`argument val is invalid: ${cookie.value}`);
if (!cookie.secure) {
if (cookie.partitioned) throw new TypeError(`Partitioned cookies must have the Secure attribute`);
if (cookie.sameSite && String(cookie.sameSite).toLowerCase() === "none") throw new TypeError(`SameSite=None cookies must have the Secure attribute`);
if (cookie.name.length > 9 && cookie.name.charCodeAt(0) === 95 && cookie.name.charCodeAt(1) === 95) {
const nameLower = cookie.name.toLowerCase();
if (nameLower.startsWith("__secure-") || nameLower.startsWith("__host-")) throw new TypeError(`${cookie.name} cookies must have the Secure attribute`);
}
}
if (cookie.name.length > 7 && cookie.name.charCodeAt(0) === 95 && cookie.name.charCodeAt(1) === 95 && cookie.name.toLowerCase().startsWith("__host-")) {
if (cookie.path !== "/") throw new TypeError(`__Host- cookies must have Path=/`);
if (cookie.domain) throw new TypeError(`__Host- cookies must not have a Domain attribute`);
}
let str = cookie.name + "=" + value;
if (cookie.maxAge !== void 0) {
if (!Number.isInteger(cookie.maxAge)) throw new TypeError(`option maxAge is invalid: ${cookie.maxAge}`);
str += "; Max-Age=" + Math.max(0, Math.min(cookie.maxAge, COOKIE_MAX_AGE_LIMIT));
}
if (cookie.domain) {
if (!domainValueRegExp.test(cookie.domain)) throw new TypeError(`option domain is invalid: ${cookie.domain}`);
str += "; Domain=" + cookie.domain;
}
if (cookie.path) {
if (!pathValueRegExp.test(cookie.path)) throw new TypeError(`option path is invalid: ${cookie.path}`);
str += "; Path=" + cookie.path;
}
if (cookie.expires) {
if (!isDate(cookie.expires) || !Number.isFinite(cookie.expires.valueOf())) throw new TypeError(`option expires is invalid: ${cookie.expires}`);
str += "; Expires=" + cookie.expires.toUTCString();
}
if (cookie.httpOnly) str += "; HttpOnly";
if (cookie.secure) str += "; Secure";
if (cookie.partitioned) str += "; Partitioned";
if (cookie.priority) switch (typeof cookie.priority === "string" ? cookie.priority.toLowerCase() : void 0) {
case "low":
str += "; Priority=Low";
break;
case "medium":
str += "; Priority=Medium";
break;
case "high":
str += "; Priority=High";
break;
default: throw new TypeError(`option priority is invalid: ${cookie.priority}`);
}
if (cookie.sameSite) switch (typeof cookie.sameSite === "string" ? cookie.sameSite.toLowerCase() : cookie.sameSite) {
case true:
case "strict":
str += "; SameSite=Strict";
break;
case "lax":
str += "; SameSite=Lax";
break;
case "none":
str += "; SameSite=None";
break;
default: throw new TypeError(`option sameSite is invalid: ${cookie.sameSite}`);
}
return str;
}
function isDate(val) {
return __toString.call(val) === "[object Date]";
}
const maxAgeRegExp = /^-?\d+$/;
const _nullProto = /* @__PURE__ */ Object.getPrototypeOf({});
function parseSetCookie(str, options) {
const len = str.length;
let _endIdx = len;
let eqIdx = -1;
for (let i = 0; i < len; i++) {
const c = str.charCodeAt(i);
if (c === 59) {
_endIdx = i;
break;
}
if (c === 61 && eqIdx === -1) eqIdx = i;
}
if (eqIdx >= _endIdx) eqIdx = -1;
const name = eqIdx === -1 ? "" : _trim(str, 0, eqIdx);
if (name && name in _nullProto) return void 0;
let value = eqIdx === -1 ? _trim(str, 0, _endIdx) : _trim(str, eqIdx + 1, _endIdx);
if (!name && !value) return void 0;
if (name.length + value.length > 4096) return void 0;
if (options?.decode !== false) value = _decode(value, options?.decode);
const setCookie = {
name,
value
};
let index = _endIdx + 1;
while (index < len) {
let endIdx = len;
let attrEqIdx = -1;
for (let i = index; i < len; i++) {
const c = str.charCodeAt(i);
if (c === 59) {
endIdx = i;
break;
}
if (c === 61 && attrEqIdx === -1) attrEqIdx = i;
}
if (attrEqIdx >= endIdx) attrEqIdx = -1;
const attr = attrEqIdx === -1 ? _trim(str, index, endIdx) : _trim(str, index, attrEqIdx);
const val = attrEqIdx === -1 ? void 0 : _trim(str, attrEqIdx + 1, endIdx);
if (val === void 0 || val.length <= 1024) switch (attr.toLowerCase()) {
case "httponly":
setCookie.httpOnly = true;
break;
case "secure":
setCookie.secure = true;
break;
case "partitioned":
setCookie.partitioned = true;
break;
case "domain":
if (val) setCookie.domain = (val.charCodeAt(0) === 46 ? val.slice(1) : val).toLowerCase();
break;
case "path":
setCookie.path = val;
break;
case "max-age":
if (val && maxAgeRegExp.test(val)) setCookie.maxAge = Math.min(Number(val), COOKIE_MAX_AGE_LIMIT);
break;
case "expires": {
if (!val) break;
const date = new Date(val);
if (Number.isFinite(date.valueOf())) {
const maxDate = new Date(Date.now() + COOKIE_MAX_AGE_LIMIT * 1e3);
setCookie.expires = date > maxDate ? maxDate : date;
}
break;
}
case "priority": {
if (!val) break;
const priority = val.toLowerCase();
if (priority === "low" || priority === "medium" || priority === "high") setCookie.priority = priority;
break;
}
case "samesite": {
if (!val) break;
const sameSite = val.toLowerCase();
if (sameSite === "lax" || sameSite === "strict" || sameSite === "none") setCookie.sameSite = sam