import process from 'node:process';globalThis._importMeta_={url:import.meta.url,env:process.env};import { tmpdir } from 'node:os'; import { defineEventHandler, handleCacheHeaders, splitCookiesString, createEvent, fetchWithEvent, isEvent, eventHandler, setHeaders, sendRedirect, proxyRequest, getRequestHeader, setResponseHeaders, setResponseStatus, send, getRequestHeaders, setResponseHeader, appendResponseHeader, getRequestURL, getResponseHeader, removeResponseHeader, createError, getRequestIP, setHeader, getQuery as getQuery$1, readBody, createApp, createRouter as createRouter$1, toNodeListener, lazyEventHandler, getResponseStatus, getRouterParam, getResponseStatusText } from 'file:///home/bennet/source/vat-api/node_modules/h3/dist/index.mjs'; import { Server } from 'node:http'; import { resolve, dirname, join } from 'node:path'; import nodeCrypto from 'node:crypto'; import { parentPort, threadId } from 'node:worker_threads'; import { escapeHtml } from 'file:///home/bennet/source/vat-api/node_modules/@vue/shared/dist/shared.cjs.js'; import { createRenderer, getRequestDependencies, getPreloadLinks, getPrefetchLinks } from 'file:///home/bennet/source/vat-api/node_modules/vue-bundle-renderer/dist/runtime.mjs'; import { parseURL, withoutBase, joinURL, getQuery, withQuery, withTrailingSlash, decodePath, withLeadingSlash, withoutTrailingSlash, joinRelativeURL } from 'file:///home/bennet/source/vat-api/node_modules/ufo/dist/index.mjs'; import destr, { destr as destr$1 } from 'file:///home/bennet/source/vat-api/node_modules/destr/dist/index.mjs'; import { createHooks } from 'file:///home/bennet/source/vat-api/node_modules/hookable/dist/index.mjs'; import { createFetch, Headers as Headers$1 } from 'file:///home/bennet/source/vat-api/node_modules/ofetch/dist/node.mjs'; import { fetchNodeRequestHandler, callNodeRequestHandler } from 'file:///home/bennet/source/vat-api/node_modules/node-mock-http/dist/index.mjs'; import { createStorage, prefixStorage } from 'file:///home/bennet/source/vat-api/node_modules/unstorage/dist/index.mjs'; import unstorage_47drivers_47fs from 'file:///home/bennet/source/vat-api/node_modules/unstorage/drivers/fs.mjs'; import { digest } from 'file:///home/bennet/source/vat-api/node_modules/ohash/dist/index.mjs'; import { klona } from 'file:///home/bennet/source/vat-api/node_modules/klona/dist/index.mjs'; import defu, { defuFn } from 'file:///home/bennet/source/vat-api/node_modules/defu/dist/defu.mjs'; import { snakeCase } from 'file:///home/bennet/source/vat-api/node_modules/scule/dist/index.mjs'; import { getContext } from 'file:///home/bennet/source/vat-api/node_modules/unctx/dist/index.mjs'; import { toRouteMatcher, createRouter } from 'file:///home/bennet/source/vat-api/node_modules/radix3/dist/index.mjs'; import { readFile } from 'node:fs/promises'; import consola, { consola as consola$1 } from 'file:///home/bennet/source/vat-api/node_modules/consola/dist/index.mjs'; import { ErrorParser } from 'file:///home/bennet/source/vat-api/node_modules/youch-core/build/index.js'; import { Youch } from 'file:///home/bennet/source/vat-api/node_modules/youch/build/index.js'; import { SourceMapConsumer } from 'file:///home/bennet/source/vat-api/node_modules/source-map/source-map.js'; import { AsyncLocalStorage } from 'node:async_hooks'; import { stringify, uneval } from 'file:///home/bennet/source/vat-api/node_modules/devalue/index.js'; import { captureRawStackTrace, parseRawStackTrace } from 'file:///home/bennet/source/vat-api/node_modules/errx/dist/index.js'; import { isVNode, isRef, toValue } from 'file:///home/bennet/source/vat-api/node_modules/vue/index.mjs'; import { promises } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname as dirname$1, resolve as resolve$1 } from 'file:///home/bennet/source/vat-api/node_modules/pathe/dist/index.mjs'; import { createHead as createHead$1, propsToString, renderSSRHead } from 'file:///home/bennet/source/vat-api/node_modules/unhead/dist/server.mjs'; import { renderToString } from 'file:///home/bennet/source/vat-api/node_modules/vue/server-renderer/index.mjs'; import { walkResolver } from 'file:///home/bennet/source/vat-api/node_modules/unhead/dist/utils.mjs'; const serverAssets = [{"baseName":"server","dir":"/home/bennet/source/vat-api/server/assets"}]; const assets$1 = createStorage(); for (const asset of serverAssets) { assets$1.mount(asset.baseName, unstorage_47drivers_47fs({ base: asset.dir, ignore: (asset?.ignore || []) })); } const storage = createStorage({}); storage.mount('/assets', assets$1); storage.mount('root', unstorage_47drivers_47fs({"driver":"fs","readOnly":true,"base":"/home/bennet/source/vat-api","watchOptions":{"ignored":[null]}})); storage.mount('src', unstorage_47drivers_47fs({"driver":"fs","readOnly":true,"base":"/home/bennet/source/vat-api/server","watchOptions":{"ignored":[null]}})); storage.mount('build', unstorage_47drivers_47fs({"driver":"fs","readOnly":false,"base":"/home/bennet/source/vat-api/.nuxt"})); storage.mount('cache', unstorage_47drivers_47fs({"driver":"fs","readOnly":false,"base":"/home/bennet/source/vat-api/.nuxt/cache"})); storage.mount('data', unstorage_47drivers_47fs({"driver":"fs","base":"/home/bennet/source/vat-api/.data/kv"})); function useStorage(base = "") { return base ? prefixStorage(storage, base) : storage; } const Hasher = /* @__PURE__ */ (() => { class Hasher2 { buff = ""; #context = /* @__PURE__ */ new Map(); write(str) { this.buff += str; } dispatch(value) { const type = value === null ? "null" : typeof value; return this[type](value); } object(object) { if (object && typeof object.toJSON === "function") { return this.object(object.toJSON()); } const objString = Object.prototype.toString.call(object); let objType = ""; const objectLength = objString.length; objType = objectLength < 10 ? "unknown:[" + objString + "]" : objString.slice(8, objectLength - 1); objType = objType.toLowerCase(); let objectNumber = null; if ((objectNumber = this.#context.get(object)) === void 0) { this.#context.set(object, this.#context.size); } else { return this.dispatch("[CIRCULAR:" + objectNumber + "]"); } if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(object)) { this.write("buffer:"); return this.write(object.toString("utf8")); } if (objType !== "object" && objType !== "function" && objType !== "asyncfunction") { if (this[objType]) { this[objType](object); } else { this.unknown(object, objType); } } else { const keys = Object.keys(object).sort(); const extraKeys = []; this.write("object:" + (keys.length + extraKeys.length) + ":"); const dispatchForKey = (key) => { this.dispatch(key); this.write(":"); this.dispatch(object[key]); this.write(","); }; for (const key of keys) { dispatchForKey(key); } for (const key of extraKeys) { dispatchForKey(key); } } } array(arr, unordered) { unordered = unordered === void 0 ? false : unordered; this.write("array:" + arr.length + ":"); if (!unordered || arr.length <= 1) { for (const entry of arr) { this.dispatch(entry); } return; } const contextAdditions = /* @__PURE__ */ new Map(); const entries = arr.map((entry) => { const hasher = new Hasher2(); hasher.dispatch(entry); for (const [key, value] of hasher.#context) { contextAdditions.set(key, value); } return hasher.toString(); }); this.#context = contextAdditions; entries.sort(); return this.array(entries, false); } date(date) { return this.write("date:" + date.toJSON()); } symbol(sym) { return this.write("symbol:" + sym.toString()); } unknown(value, type) { this.write(type); if (!value) { return; } this.write(":"); if (value && typeof value.entries === "function") { return this.array( [...value.entries()], true /* ordered */ ); } } error(err) { return this.write("error:" + err.toString()); } boolean(bool) { return this.write("bool:" + bool); } string(string) { this.write("string:" + string.length + ":"); this.write(string); } function(fn) { this.write("fn:"); if (isNativeFunction(fn)) { this.dispatch("[native]"); } else { this.dispatch(fn.toString()); } } number(number) { return this.write("number:" + number); } null() { return this.write("Null"); } undefined() { return this.write("Undefined"); } regexp(regex) { return this.write("regex:" + regex.toString()); } arraybuffer(arr) { this.write("arraybuffer:"); return this.dispatch(new Uint8Array(arr)); } url(url) { return this.write("url:" + url.toString()); } map(map) { this.write("map:"); const arr = [...map]; return this.array(arr, false); } set(set) { this.write("set:"); const arr = [...set]; return this.array(arr, false); } bigint(number) { return this.write("bigint:" + number.toString()); } } for (const type of [ "uint8array", "uint8clampedarray", "unt8array", "uint16array", "unt16array", "uint32array", "unt32array", "float32array", "float64array" ]) { Hasher2.prototype[type] = function(arr) { this.write(type + ":"); return this.array([...arr], false); }; } function isNativeFunction(f) { if (typeof f !== "function") { return false; } return Function.prototype.toString.call(f).slice( -15 /* "[native code] }".length */ ) === "[native code] }"; } return Hasher2; })(); function serialize(object) { const hasher = new Hasher(); hasher.dispatch(object); return hasher.buff; } function hash(value) { return digest(typeof value === "string" ? value : serialize(value)).replace(/[-_]/g, "").slice(0, 10); } function defaultCacheOptions() { return { name: "_", base: "/cache", swr: true, maxAge: 1 }; } function defineCachedFunction(fn, opts = {}) { opts = { ...defaultCacheOptions(), ...opts }; const pending = {}; const group = opts.group || "nitro/functions"; const name = opts.name || fn.name || "_"; const integrity = opts.integrity || hash([fn, opts]); const validate = opts.validate || ((entry) => entry.value !== void 0); async function get(key, resolver, shouldInvalidateCache, event) { const cacheKey = [opts.base, group, name, key + ".json"].filter(Boolean).join(":").replace(/:\/$/, ":index"); let entry = await useStorage().getItem(cacheKey).catch((error) => { console.error(`[cache] Cache read error.`, error); useNitroApp().captureError(error, { event, tags: ["cache"] }); }) || {}; if (typeof entry !== "object") { entry = {}; const error = new Error("Malformed data read from cache."); console.error("[cache]", error); useNitroApp().captureError(error, { event, tags: ["cache"] }); } const ttl = (opts.maxAge ?? 0) * 1e3; if (ttl) { entry.expires = Date.now() + ttl; } const expired = shouldInvalidateCache || entry.integrity !== integrity || ttl && Date.now() - (entry.mtime || 0) > ttl || validate(entry) === false; const _resolve = async () => { const isPending = pending[key]; if (!isPending) { if (entry.value !== void 0 && (opts.staleMaxAge || 0) >= 0 && opts.swr === false) { entry.value = void 0; entry.integrity = void 0; entry.mtime = void 0; entry.expires = void 0; } pending[key] = Promise.resolve(resolver()); } try { entry.value = await pending[key]; } catch (error) { if (!isPending) { delete pending[key]; } throw error; } if (!isPending) { entry.mtime = Date.now(); entry.integrity = integrity; delete pending[key]; if (validate(entry) !== false) { let setOpts; if (opts.maxAge && !opts.swr) { setOpts = { ttl: opts.maxAge }; } const promise = useStorage().setItem(cacheKey, entry, setOpts).catch((error) => { console.error(`[cache] Cache write error.`, error); useNitroApp().captureError(error, { event, tags: ["cache"] }); }); if (event?.waitUntil) { event.waitUntil(promise); } } } }; const _resolvePromise = expired ? _resolve() : Promise.resolve(); if (entry.value === void 0) { await _resolvePromise; } else if (expired && event && event.waitUntil) { event.waitUntil(_resolvePromise); } if (opts.swr && validate(entry) !== false) { _resolvePromise.catch((error) => { console.error(`[cache] SWR handler error.`, error); useNitroApp().captureError(error, { event, tags: ["cache"] }); }); return entry; } return _resolvePromise.then(() => entry); } return async (...args) => { const shouldBypassCache = await opts.shouldBypassCache?.(...args); if (shouldBypassCache) { return fn(...args); } const key = await (opts.getKey || getKey)(...args); const shouldInvalidateCache = await opts.shouldInvalidateCache?.(...args); const entry = await get( key, () => fn(...args), shouldInvalidateCache, args[0] && isEvent(args[0]) ? args[0] : void 0 ); let value = entry.value; if (opts.transform) { value = await opts.transform(entry, ...args) || value; } return value; }; } function cachedFunction(fn, opts = {}) { return defineCachedFunction(fn, opts); } function getKey(...args) { return args.length > 0 ? hash(args) : ""; } function escapeKey(key) { return String(key).replace(/\W/g, ""); } function defineCachedEventHandler(handler, opts = defaultCacheOptions()) { const variableHeaderNames = (opts.varies || []).filter(Boolean).map((h) => h.toLowerCase()).sort(); const _opts = { ...opts, getKey: async (event) => { const customKey = await opts.getKey?.(event); if (customKey) { return escapeKey(customKey); } const _path = event.node.req.originalUrl || event.node.req.url || event.path; let _pathname; try { _pathname = escapeKey(decodeURI(parseURL(_path).pathname)).slice(0, 16) || "index"; } catch { _pathname = "-"; } const _hashedPath = `${_pathname}.${hash(_path)}`; const _headers = variableHeaderNames.map((header) => [header, event.node.req.headers[header]]).map(([name, value]) => `${escapeKey(name)}.${hash(value)}`); return [_hashedPath, ..._headers].join(":"); }, validate: (entry) => { if (!entry.value) { return false; } if (entry.value.code >= 400) { return false; } if (entry.value.body === void 0) { return false; } if (entry.value.headers.etag === "undefined" || entry.value.headers["last-modified"] === "undefined") { return false; } return true; }, group: opts.group || "nitro/handlers", integrity: opts.integrity || hash([handler, opts]) }; const _cachedHandler = cachedFunction( async (incomingEvent) => { const variableHeaders = {}; for (const header of variableHeaderNames) { const value = incomingEvent.node.req.headers[header]; if (value !== void 0) { variableHeaders[header] = value; } } const reqProxy = cloneWithProxy(incomingEvent.node.req, { headers: variableHeaders }); const resHeaders = {}; let _resSendBody; const resProxy = cloneWithProxy(incomingEvent.node.res, { statusCode: 200, writableEnded: false, writableFinished: false, headersSent: false, closed: false, getHeader(name) { return resHeaders[name]; }, setHeader(name, value) { resHeaders[name] = value; return this; }, getHeaderNames() { return Object.keys(resHeaders); }, hasHeader(name) { return name in resHeaders; }, removeHeader(name) { delete resHeaders[name]; }, getHeaders() { return resHeaders; }, end(chunk, arg2, arg3) { if (typeof chunk === "string") { _resSendBody = chunk; } if (typeof arg2 === "function") { arg2(); } if (typeof arg3 === "function") { arg3(); } return this; }, write(chunk, arg2, arg3) { if (typeof chunk === "string") { _resSendBody = chunk; } if (typeof arg2 === "function") { arg2(void 0); } if (typeof arg3 === "function") { arg3(); } return true; }, writeHead(statusCode, headers2) { this.statusCode = statusCode; if (headers2) { if (Array.isArray(headers2) || typeof headers2 === "string") { throw new TypeError("Raw headers is not supported."); } for (const header in headers2) { const value = headers2[header]; if (value !== void 0) { this.setHeader( header, value ); } } } return this; } }); const event = createEvent(reqProxy, resProxy); event.fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, { fetch: useNitroApp().localFetch }); event.$fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, { fetch: globalThis.$fetch }); event.waitUntil = incomingEvent.waitUntil; event.context = incomingEvent.context; event.context.cache = { options: _opts }; const body = await handler(event) || _resSendBody; const headers = event.node.res.getHeaders(); headers.etag = String( headers.Etag || headers.etag || `W/"${hash(body)}"` ); headers["last-modified"] = String( headers["Last-Modified"] || headers["last-modified"] || (/* @__PURE__ */ new Date()).toUTCString() ); const cacheControl = []; if (opts.swr) { if (opts.maxAge) { cacheControl.push(`s-maxage=${opts.maxAge}`); } if (opts.staleMaxAge) { cacheControl.push(`stale-while-revalidate=${opts.staleMaxAge}`); } else { cacheControl.push("stale-while-revalidate"); } } else if (opts.maxAge) { cacheControl.push(`max-age=${opts.maxAge}`); } if (cacheControl.length > 0) { headers["cache-control"] = cacheControl.join(", "); } const cacheEntry = { code: event.node.res.statusCode, headers, body }; return cacheEntry; }, _opts ); return defineEventHandler(async (event) => { if (opts.headersOnly) { if (handleCacheHeaders(event, { maxAge: opts.maxAge })) { return; } return handler(event); } const response = await _cachedHandler( event ); if (event.node.res.headersSent || event.node.res.writableEnded) { return response.body; } if (handleCacheHeaders(event, { modifiedTime: new Date(response.headers["last-modified"]), etag: response.headers.etag, maxAge: opts.maxAge })) { return; } event.node.res.statusCode = response.code; for (const name in response.headers) { const value = response.headers[name]; if (name === "set-cookie") { event.node.res.appendHeader( name, splitCookiesString(value) ); } else { if (value !== void 0) { event.node.res.setHeader(name, value); } } } return response.body; }); } function cloneWithProxy(obj, overrides) { return new Proxy(obj, { get(target, property, receiver) { if (property in overrides) { return overrides[property]; } return Reflect.get(target, property, receiver); }, set(target, property, value, receiver) { if (property in overrides) { overrides[property] = value; return true; } return Reflect.set(target, property, value, receiver); } }); } const cachedEventHandler = defineCachedEventHandler; const inlineAppConfig = { "nuxt": {} }; const appConfig = defuFn(inlineAppConfig); function getEnv(key, opts) { const envKey = snakeCase(key).toUpperCase(); return destr( process.env[opts.prefix + envKey] ?? process.env[opts.altPrefix + envKey] ); } function _isObject(input) { return typeof input === "object" && !Array.isArray(input); } function applyEnv(obj, opts, parentKey = "") { for (const key in obj) { const subKey = parentKey ? `${parentKey}_${key}` : key; const envValue = getEnv(subKey, opts); if (_isObject(obj[key])) { if (_isObject(envValue)) { obj[key] = { ...obj[key], ...envValue }; applyEnv(obj[key], opts, subKey); } else if (envValue === void 0) { applyEnv(obj[key], opts, subKey); } else { obj[key] = envValue ?? obj[key]; } } else { obj[key] = envValue ?? obj[key]; } if (opts.envExpansion && typeof obj[key] === "string") { obj[key] = _expandFromEnv(obj[key]); } } return obj; } const envExpandRx = /\{\{([^{}]*)\}\}/g; function _expandFromEnv(value) { return value.replace(envExpandRx, (match, key) => { return process.env[key] || match; }); } const _inlineRuntimeConfig = { "app": { "baseURL": "/", "buildId": "dev", "buildAssetsDir": "/_nuxt/", "cdnURL": "" }, "nitro": { "envPrefix": "NUXT_", "routeRules": { "/__nuxt_error": { "cache": false }, "/_nuxt/builds/meta/**": { "headers": { "cache-control": "public, max-age=31536000, immutable" } }, "/_nuxt/builds/**": { "headers": { "cache-control": "public, max-age=1, immutable" } } } }, "public": {}, "vatstackApiKey": "" }; const envOptions = { prefix: "NITRO_", altPrefix: _inlineRuntimeConfig.nitro.envPrefix ?? process.env.NITRO_ENV_PREFIX ?? "_", envExpansion: _inlineRuntimeConfig.nitro.envExpansion ?? process.env.NITRO_ENV_EXPANSION ?? false }; const _sharedRuntimeConfig = _deepFreeze( applyEnv(klona(_inlineRuntimeConfig), envOptions) ); function useRuntimeConfig(event) { if (!event) { return _sharedRuntimeConfig; } if (event.context.nitro.runtimeConfig) { return event.context.nitro.runtimeConfig; } const runtimeConfig = klona(_inlineRuntimeConfig); applyEnv(runtimeConfig, envOptions); event.context.nitro.runtimeConfig = runtimeConfig; return runtimeConfig; } _deepFreeze(klona(appConfig)); function _deepFreeze(object) { const propNames = Object.getOwnPropertyNames(object); for (const name of propNames) { const value = object[name]; if (value && typeof value === "object") { _deepFreeze(value); } } return Object.freeze(object); } new Proxy(/* @__PURE__ */ Object.create(null), { get: (_, prop) => { console.warn( "Please use `useRuntimeConfig()` instead of accessing config directly." ); const runtimeConfig = useRuntimeConfig(); if (prop in runtimeConfig) { return runtimeConfig[prop]; } return void 0; } }); getContext("nitro-app", { asyncContext: false, AsyncLocalStorage: void 0 }); const config = useRuntimeConfig(); const _routeRulesMatcher = toRouteMatcher( createRouter({ routes: config.nitro.routeRules }) ); function createRouteRulesHandler(ctx) { return eventHandler((event) => { const routeRules = getRouteRules(event); if (routeRules.headers) { setHeaders(event, routeRules.headers); } if (routeRules.redirect) { let target = routeRules.redirect.to; if (target.endsWith("/**")) { let targetPath = event.path; const strpBase = routeRules.redirect._redirectStripBase; if (strpBase) { targetPath = withoutBase(targetPath, strpBase); } target = joinURL(target.slice(0, -3), targetPath); } else if (event.path.includes("?")) { const query = getQuery(event.path); target = withQuery(target, query); } return sendRedirect(event, target, routeRules.redirect.statusCode); } if (routeRules.proxy) { let target = routeRules.proxy.to; if (target.endsWith("/**")) { let targetPath = event.path; const strpBase = routeRules.proxy._proxyStripBase; if (strpBase) { targetPath = withoutBase(targetPath, strpBase); } target = joinURL(target.slice(0, -3), targetPath); } else if (event.path.includes("?")) { const query = getQuery(event.path); target = withQuery(target, query); } return proxyRequest(event, target, { fetch: ctx.localFetch, ...routeRules.proxy }); } }); } function getRouteRules(event) { event.context._nitro = event.context._nitro || {}; if (!event.context._nitro.routeRules) { event.context._nitro.routeRules = getRouteRulesForPath( withoutBase(event.path.split("?")[0], useRuntimeConfig().app.baseURL) ); } return event.context._nitro.routeRules; } function getRouteRulesForPath(path) { return defu({}, ..._routeRulesMatcher.matchAll(path).reverse()); } function _captureError(error, type) { console.error(`[${type}]`, error); useNitroApp().captureError(error, { tags: [type] }); } function trapUnhandledNodeErrors() { process.on( "unhandledRejection", (error) => _captureError(error, "unhandledRejection") ); process.on( "uncaughtException", (error) => _captureError(error, "uncaughtException") ); } function joinHeaders(value) { return Array.isArray(value) ? value.join(", ") : String(value); } function normalizeFetchResponse(response) { if (!response.headers.has("set-cookie")) { return response; } return new Response(response.body, { status: response.status, statusText: response.statusText, headers: normalizeCookieHeaders(response.headers) }); } function normalizeCookieHeader(header = "") { return splitCookiesString(joinHeaders(header)); } function normalizeCookieHeaders(headers) { const outgoingHeaders = new Headers(); for (const [name, header] of headers) { if (name === "set-cookie") { for (const cookie of normalizeCookieHeader(header)) { outgoingHeaders.append("set-cookie", cookie); } } else { outgoingHeaders.set(name, joinHeaders(header)); } } return outgoingHeaders; } /** * Nitro internal functions extracted from https://github.com/nitrojs/nitro/blob/v2/src/runtime/internal/utils.ts */ function isJsonRequest(event) { // If the client specifically requests HTML, then avoid classifying as JSON. if (hasReqHeader(event, "accept", "text/html")) { return false; } return hasReqHeader(event, "accept", "application/json") || hasReqHeader(event, "user-agent", "curl/") || hasReqHeader(event, "user-agent", "httpie/") || hasReqHeader(event, "sec-fetch-mode", "cors") || event.path.startsWith("/api/") || event.path.endsWith(".json"); } function hasReqHeader(event, name, includes) { const value = getRequestHeader(event, name); return value && typeof value === "string" && value.toLowerCase().includes(includes); } const iframeStorageBridge = (nonce) => ` (function () { const NONCE = ${JSON.stringify(nonce)}; const memoryStore = Object.create(null); const post = (type, payload) => { window.parent.postMessage({ type, nonce: NONCE, ...payload }, '*'); }; const isValid = (data) => data && data.nonce === NONCE; const mockStorage = { getItem(key) { return Object.hasOwn(memoryStore, key) ? memoryStore[key] : null; }, setItem(key, value) { const v = String(value); memoryStore[key] = v; post('storage-set', { key, value: v }); }, removeItem(key) { delete memoryStore[key]; post('storage-remove', { key }); }, clear() { for (const key of Object.keys(memoryStore)) delete memoryStore[key]; post('storage-clear', {}); }, key(index) { const keys = Object.keys(memoryStore); return keys[index] ?? null; }, get length() { return Object.keys(memoryStore).length; } }; const defineLocalStorage = () => { try { Object.defineProperty(window, 'localStorage', { value: mockStorage, writable: false, configurable: true }); } catch { window.localStorage = mockStorage; } }; defineLocalStorage(); window.addEventListener('message', (event) => { const data = event.data; if (!isValid(data) || data.type !== 'storage-sync-data') return; const incoming = data.data || {}; for (const key of Object.keys(incoming)) memoryStore[key] = incoming[key]; if (typeof window.initTheme === 'function') window.initTheme(); window.dispatchEvent(new Event('storage-ready')); }); // Clipboard API is unavailable in data: URL iframe, so we use postMessage document.addEventListener('DOMContentLoaded', function() { window.copyErrorMessage = function(button) { post('clipboard-copy', { text: button.dataset.errorText }); button.classList.add('copied'); setTimeout(function() { button.classList.remove('copied'); }, 2000); }; }); post('storage-sync-request', {}); })(); `; const parentStorageBridge = (nonce) => ` (function () { const host = document.querySelector('nuxt-error-overlay'); if (!host) return; const NONCE = ${JSON.stringify(nonce)}; const isValid = (data) => data && data.nonce === NONCE; // Handle clipboard copy from iframe window.addEventListener('message', function(e) { if (isValid(e) && e.data.type === 'clipboard-copy') { navigator.clipboard.writeText(e.data.text).catch(function() {}); } }); const collectLocalStorage = () => { const all = {}; for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i); if (k != null) all[k] = localStorage.getItem(k); } return all; }; const attachWhenReady = () => { const root = host.shadowRoot; if (!root) return false; const iframe = root.getElementById('frame'); if (!iframe || !iframe.contentWindow) return false; const handlers = { 'storage-set': (d) => localStorage.setItem(d.key, d.value), 'storage-remove': (d) => localStorage.removeItem(d.key), 'storage-clear': () => localStorage.clear(), 'storage-sync-request': () => { iframe.contentWindow.postMessage({ type: 'storage-sync-data', data: collectLocalStorage(), nonce: NONCE }, '*'); } }; window.addEventListener('message', (event) => { const data = event.data; if (!isValid(data)) return; const fn = handlers[data.type]; if (fn) fn(data); }); return true; }; if (attachWhenReady()) return; const obs = new MutationObserver(() => { if (attachWhenReady()) obs.disconnect(); }); obs.observe(host, { childList: true, subtree: true }); })(); `; const errorCSS = ` :host { --preview-width: 240px; --preview-height: 180px; --base-width: 1200px; --base-height: 900px; --z-base: 999999998; --error-pip-left: auto; --error-pip-top: auto; --error-pip-right: 5px; --error-pip-bottom: 5px; --error-pip-origin: bottom right; --app-preview-left: auto; --app-preview-top: auto; --app-preview-right: 5px; --app-preview-bottom: 5px; all: initial; display: contents; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } #frame { position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; border: none; z-index: var(--z-base); } #frame[inert] { left: var(--error-pip-left); top: var(--error-pip-top); right: var(--error-pip-right); bottom: var(--error-pip-bottom); width: var(--base-width); height: var(--base-height); transform: scale(calc(240 / 1200)); transform-origin: var(--error-pip-origin); overflow: hidden; border-radius: calc(1200 * 8px / 240); } #preview { position: fixed; left: var(--app-preview-left); top: var(--app-preview-top); right: var(--app-preview-right); bottom: var(--app-preview-bottom); width: var(--preview-width); height: var(--preview-height); overflow: hidden; border-radius: 6px; pointer-events: none; z-index: var(--z-base); background: white; display: none; } #preview iframe { transform-origin: var(--error-pip-origin); } #frame:not([inert]) + #preview { display: block; } #toggle { position: fixed; left: var(--app-preview-left); top: var(--app-preview-top); right: calc(var(--app-preview-right) - 3px); bottom: calc(var(--app-preview-bottom) - 3px); width: var(--preview-width); height: var(--preview-height); background: none; border: 3px solid #00DC82; border-radius: 8px; cursor: pointer; opacity: 0.8; transition: opacity 0.2s, box-shadow 0.2s; z-index: calc(var(--z-base) + 1); display: flex; align-items: center; justify-content: center; } #toggle:hover, #toggle:focus { opacity: 1; box-shadow: 0 0 20px rgba(0, 220, 130, 0.6); } #toggle:focus-visible { outline: 3px solid #00DC82; outline-offset: 0; box-shadow: 0 0 24px rgba(0, 220, 130, 0.8); } #frame[inert] ~ #toggle { left: var(--error-pip-left); top: var(--error-pip-top); right: calc(var(--error-pip-right) - 3px); bottom: calc(var(--error-pip-bottom) - 3px); cursor: grab; } :host(.dragging) #frame[inert] ~ #toggle { cursor: grabbing; } #frame:not([inert]) ~ #toggle, #frame:not([inert]) + #preview { cursor: grab; } :host(.dragging-preview) #frame:not([inert]) ~ #toggle, :host(.dragging-preview) #frame:not([inert]) + #preview { cursor: grabbing; } #pip-close { position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; border-radius: 50%; border: none; background: rgba(0, 0, 0, 0.75); color: #fff; font-size: 16px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); pointer-events: auto; } #pip-close:focus-visible { outline: 2px solid #00DC82; outline-offset: 2px; } #pip-restore { position: fixed; right: 16px; bottom: 16px; padding: 8px 14px; border-radius: 999px; border: 2px solid #00DC82; background: #111; color: #fff; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; font-size: 14px; display: inline-flex; align-items: center; gap: 6px; z-index: calc(var(--z-base) + 2); cursor: grab; } #pip-restore:focus-visible { outline: 2px solid #00DC82; outline-offset: 2px; } :host(.dragging-restore) #pip-restore { cursor: grabbing; } #frame[hidden], #toggle[hidden], #preview[hidden], #pip-restore[hidden], #pip-close[hidden] { display: none !important; } @media (prefers-reduced-motion: reduce) { #toggle { transition: none; } } `; function webComponentScript(base64HTML, startMinimized) { return ` (function () { try { // ========================= // Host + Shadow // ========================= const host = document.querySelector('nuxt-error-overlay'); if (!host) return; const shadow = host.attachShadow({ mode: 'open' }); // ========================= // DOM helpers // ========================= const el = (tag) => document.createElement(tag); const on = (node, type, fn, opts) => node.addEventListener(type, fn, opts); const hide = (node, v) => node.toggleAttribute('hidden', !!v); const setVar = (name, value) => host.style.setProperty(name, value); const unsetVar = (name) => host.style.removeProperty(name); // ========================= // Create DOM // ========================= const style = el('style'); style.textContent = ${JSON.stringify(errorCSS)}; const iframe = el('iframe'); iframe.id = 'frame'; iframe.src = 'data:text/html;base64,${base64HTML}'; iframe.title = 'Detailed error stack trace'; iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); const preview = el('div'); preview.id = 'preview'; const toggle = el('div'); toggle.id = 'toggle'; toggle.setAttribute('aria-expanded', 'true'); toggle.setAttribute('role', 'button'); toggle.setAttribute('tabindex', '0'); toggle.innerHTML = 'Toggle detailed error view'; const liveRegion = el('div'); liveRegion.setAttribute('role', 'status'); liveRegion.setAttribute('aria-live', 'polite'); liveRegion.className = 'sr-only'; const pipCloseButton = el('button'); pipCloseButton.id = 'pip-close'; pipCloseButton.setAttribute('type', 'button'); pipCloseButton.setAttribute('aria-label', 'Hide error preview overlay'); pipCloseButton.innerHTML = '×'; pipCloseButton.hidden = true; toggle.appendChild(pipCloseButton); const pipRestoreButton = el('button'); pipRestoreButton.id = 'pip-restore'; pipRestoreButton.setAttribute('type', 'button'); pipRestoreButton.setAttribute('aria-label', 'Show error overlay'); pipRestoreButton.innerHTML = 'Show error overlay'; pipRestoreButton.hidden = true; // Order matters: #frame + #preview adjacency shadow.appendChild(style); shadow.appendChild(liveRegion); shadow.appendChild(iframe); shadow.appendChild(preview); shadow.appendChild(toggle); shadow.appendChild(pipRestoreButton); // ========================= // Constants / keys // ========================= const POS_KEYS = { position: 'nuxt-error-overlay:position', hiddenPretty: 'nuxt-error-overlay:error-pip:hidden', hiddenPreview: 'nuxt-error-overlay:app-preview:hidden' }; const CSS_VARS = { pip: { left: '--error-pip-left', top: '--error-pip-top', right: '--error-pip-right', bottom: '--error-pip-bottom' }, preview: { left: '--app-preview-left', top: '--app-preview-top', right: '--app-preview-right', bottom: '--app-preview-bottom' } }; const MIN_GAP = 5; const DRAG_THRESHOLD = 2; // ========================= // Local storage safe access + state // ========================= let storageReady = true; let isPrettyHidden = false; let isPreviewHidden = false; const safeGet = (k) => { try { return localStorage.getItem(k); } catch { return null; } }; const safeSet = (k, v) => { if (!storageReady) return; try { localStorage.setItem(k, v); } catch {} }; // ========================= // Sizing helpers // ========================= const vvSize = () => { const v = window.visualViewport; return v ? { w: v.width, h: v.height } : { w: window.innerWidth, h: window.innerHeight }; }; const previewSize = () => { const styles = getComputedStyle(host); const w = parseFloat(styles.getPropertyValue('--preview-width')) || 240; const h = parseFloat(styles.getPropertyValue('--preview-height')) || 180; return { w, h }; }; const sizeForTarget = (target) => { if (!target) return previewSize(); const rect = target.getBoundingClientRect(); if (rect.width && rect.height) return { w: rect.width, h: rect.height }; return previewSize(); }; // ========================= // Dock model + offset/alignment calculations // ========================= const dock = { edge: null, offset: null, align: null, gap: null }; const maxOffsetFor = (edge, size) => { const vv = vvSize(); if (edge === 'left' || edge === 'right') return Math.max(MIN_GAP, vv.h - size.h - MIN_GAP); return Math.max(MIN_GAP, vv.w - size.w - MIN_GAP); }; const clampOffset = (edge, value, size) => { const max = maxOffsetFor(edge, size); return Math.min(Math.max(value, MIN_GAP), max); }; const updateDockAlignment = (size) => { if (!dock.edge || dock.offset == null) return; const max = maxOffsetFor(dock.edge, size); if (dock.offset <= max / 2) { dock.align = 'start'; dock.gap = dock.offset; } else { dock.align = 'end'; dock.gap = Math.max(0, max - dock.offset); } }; const appliedOffsetFor = (size) => { if (!dock.edge || dock.offset == null) return null; const max = maxOffsetFor(dock.edge, size); if (dock.align === 'end' && typeof dock.gap === 'number') { return clampOffset(dock.edge, max - dock.gap, size); } if (dock.align === 'start' && typeof dock.gap === 'number') { return clampOffset(dock.edge, dock.gap, size); } return clampOffset(dock.edge, dock.offset, size); }; const nearestEdgeAt = (x, y) => { const { w, h } = vvSize(); const d = { left: x, right: w - x, top: y, bottom: h - y }; return Object.keys(d).reduce((a, b) => (d[a] < d[b] ? a : b)); }; const cornerDefaultDock = () => { const vv = vvSize(); const size = previewSize(); const offset = Math.max(MIN_GAP, vv.w - size.w - MIN_GAP); return { edge: 'bottom', offset }; }; const currentTransformOrigin = () => { if (!dock.edge) return null; if (dock.edge === 'left' || dock.edge === 'top') return 'top left'; if (dock.edge === 'right') return 'top right'; return 'bottom left'; }; // ========================= // Persist / load dock // ========================= const loadDock = () => { const raw = safeGet(POS_KEYS.position); if (!raw) return; try { const parsed = JSON.parse(raw); const { edge, offset, align, gap } = parsed || {}; if (!['left', 'right', 'top', 'bottom'].includes(edge)) return; if (typeof offset !== 'number') return; dock.edge = edge; dock.offset = clampOffset(edge, offset, previewSize()); dock.align = align === 'start' || align === 'end' ? align : null; dock.gap = typeof gap === 'number' ? gap : null; if (!dock.align || dock.gap == null) updateDockAlignment(previewSize()); } catch {} }; const persistDock = () => { if (!dock.edge || dock.offset == null) return; safeSet(POS_KEYS.position, JSON.stringify({ edge: dock.edge, offset: dock.offset, align: dock.align, gap: dock.gap })); }; // ========================= // Apply dock // ========================= const dockToVars = (vars) => ({ set: (side, v) => host.style.setProperty(vars[side], v), clear: (side) => host.style.removeProperty(vars[side]) }); const dockToEl = (node) => ({ set: (side, v) => { node.style[side] = v; }, clear: (side) => { node.style[side] = ''; } }); const applyDock = (target, size, opts) => { if (!dock.edge || dock.offset == null) { target.clear('left'); target.clear('top'); target.clear('right'); target.clear('bottom'); return; } target.set('left', 'auto'); target.set('top', 'auto'); target.set('right', 'auto'); target.set('bottom', 'auto'); const applied = appliedOffsetFor(size); if (dock.edge === 'left') { target.set('left', MIN_GAP + 'px'); target.set('top', applied + 'px'); } else if (dock.edge === 'right') { target.set('right', MIN_GAP + 'px'); target.set('top', applied + 'px'); } else if (dock.edge === 'top') { target.set('top', MIN_GAP + 'px'); target.set('left', applied + 'px'); } else { target.set('bottom', MIN_GAP + 'px'); target.set('left', applied + 'px'); } if (!opts || opts.persist !== false) persistDock(); }; const applyDockAll = (opts) => { applyDock(dockToVars(CSS_VARS.pip), previewSize(), opts); applyDock(dockToVars(CSS_VARS.preview), previewSize(), opts); applyDock(dockToEl(pipRestoreButton), sizeForTarget(pipRestoreButton), opts); }; const repaintToDock = () => { if (!dock.edge || dock.offset == null) return; const origin = currentTransformOrigin(); if (origin) setVar('--error-pip-origin', origin); else unsetVar('--error-pip-origin'); applyDockAll({ persist: false }); }; // ========================= // Hidden state + UI // ========================= const loadHidden = () => { const rawPretty = safeGet(POS_KEYS.hiddenPretty); if (rawPretty != null) isPrettyHidden = rawPretty === '1' || rawPretty === 'true'; const rawPreview = safeGet(POS_KEYS.hiddenPreview); if (rawPreview != null) isPreviewHidden = rawPreview === '1' || rawPreview === 'true'; }; const setPrettyHidden = (v) => { isPrettyHidden = !!v; safeSet(POS_KEYS.hiddenPretty, isPrettyHidden ? '1' : '0'); updateUI(); }; const setPreviewHidden = (v) => { isPreviewHidden = !!v; safeSet(POS_KEYS.hiddenPreview, isPreviewHidden ? '1' : '0'); updateUI(); }; const isMinimized = () => iframe.hasAttribute('inert'); const setMinimized = (v) => { if (v) { iframe.setAttribute('inert', ''); toggle.setAttribute('aria-expanded', 'false'); } else { iframe.removeAttribute('inert'); toggle.setAttribute('aria-expanded', 'true'); } }; const setRestoreLabel = (kind) => { if (kind === 'pretty') { pipRestoreButton.innerHTML = 'Show error overlay'; pipRestoreButton.setAttribute('aria-label', 'Show error overlay'); } else { pipRestoreButton.innerHTML = 'Show error page'; pipRestoreButton.setAttribute('aria-label', 'Show error page'); } }; const updateUI = () => { const minimized = isMinimized(); const showPiP = minimized && !isPrettyHidden; const showPreview = !minimized && !isPreviewHidden; const pipHiddenByUser = minimized && isPrettyHidden; const previewHiddenByUser = !minimized && isPreviewHidden; const showToggle = minimized ? showPiP : showPreview; const showRestore = pipHiddenByUser || previewHiddenByUser; hide(iframe, pipHiddenByUser); hide(preview, !showPreview); hide(toggle, !showToggle); hide(pipCloseButton, !showToggle); hide(pipRestoreButton, !showRestore); pipCloseButton.setAttribute('aria-label', minimized ? 'Hide error overlay' : 'Hide error page preview'); if (pipHiddenByUser) setRestoreLabel('pretty'); else if (previewHiddenByUser) setRestoreLabel('preview'); host.classList.toggle('pip-hidden', isPrettyHidden); host.classList.toggle('preview-hidden', isPreviewHidden); }; // ========================= // Preview snapshot // ========================= const updatePreview = () => { try { let previewIframe = preview.querySelector('iframe'); if (!previewIframe) { previewIframe = el('iframe'); previewIframe.style.cssText = 'width: 1200px; height: 900px; transform: scale(0.2); transform-origin: top left; border: none;'; previewIframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); preview.appendChild(previewIframe); } const doctype = document.doctype ? '' : ''; const cleanedHTML = document.documentElement.outerHTML .replace(/]*>.*?<\\/nuxt-error-overlay>/gs, '') .replace(/]*>.*?<\\/script>/gs, ''); const iframeDoc = previewIframe.contentDocument || previewIframe.contentWindow.document; iframeDoc.open(); iframeDoc.write(doctype + cleanedHTML); iframeDoc.close(); } catch (err) { console.error('Failed to update preview:', err); } }; // ========================= // View toggling // ========================= const toggleView = () => { if (isMinimized()) { updatePreview(); setMinimized(false); liveRegion.textContent = 'Showing detailed error view'; setTimeout(() => { try { iframe.contentWindow.focus(); } catch {} }, 100); } else { setMinimized(true); liveRegion.textContent = 'Showing error page'; repaintToDock(); void iframe.offsetWidth; } updateUI(); }; // ========================= // Dragging (unified, rAF throttled) // ========================= let drag = null; let rafId = null; let suppressToggleClick = false; let suppressRestoreClick = false; const beginDrag = (e) => { if (drag) return; if (!dock.edge || dock.offset == null) { const def = cornerDefaultDock(); dock.edge = def.edge; dock.offset = def.offset; updateDockAlignment(previewSize()); } const isRestoreTarget = e.currentTarget === pipRestoreButton; drag = { kind: isRestoreTarget ? 'restore' : (isMinimized() ? 'pip' : 'preview'), pointerId: e.pointerId, startX: e.clientX, startY: e.clientY, lastX: e.clientX, lastY: e.clientY, moved: false, target: e.currentTarget }; drag.target.setPointerCapture(e.pointerId); if (drag.kind === 'restore') host.classList.add('dragging-restore'); else host.classList.add(drag.kind === 'pip' ? 'dragging' : 'dragging-preview'); e.preventDefault(); }; const moveDrag = (e) => { if (!drag || drag.pointerId !== e.pointerId) return; drag.lastX = e.clientX; drag.lastY = e.clientY; const dx = drag.lastX - drag.startX; const dy = drag.lastY - drag.startY; if (!drag.moved && (Math.abs(dx) > DRAG_THRESHOLD || Math.abs(dy) > DRAG_THRESHOLD)) { drag.moved = true; } if (!drag.moved) return; if (rafId) return; rafId = requestAnimationFrame(() => { rafId = null; const edge = nearestEdgeAt(drag.lastX, drag.lastY); const size = sizeForTarget(drag.target); let offset; if (edge === 'left' || edge === 'right') { const top = drag.lastY - (size.h / 2); offset = clampOffset(edge, Math.round(top), size); } else { const left = drag.lastX - (size.w / 2); offset = clampOffset(edge, Math.round(left), size); } dock.edge = edge; dock.offset = offset; updateDockAlignment(size); const origin = currentTransformOrigin(); setVar('--error-pip-origin', origin || 'bottom right'); applyDockAll({ persist: false }); }); }; const endDrag = (e) => { if (!drag || drag.pointerId !== e.pointerId) return; const endedKind = drag.kind; drag.target.releasePointerCapture(e.pointerId); if (endedKind === 'restore') host.classList.remove('dragging-restore'); else host.classList.remove(endedKind === 'pip' ? 'dragging' : 'dragging-preview'); const didMove = drag.moved; drag = null; if (didMove) { persistDock(); if (endedKind === 'restore') suppressRestoreClick = true; else suppressToggleClick = true; e.preventDefault(); e.stopPropagation(); } }; const bindDragTarget = (node) => { on(node, 'pointerdown', beginDrag); on(node, 'pointermove', moveDrag); on(node, 'pointerup', endDrag); on(node, 'pointercancel', endDrag); }; bindDragTarget(toggle); bindDragTarget(pipRestoreButton); // ========================= // Events (toggle / close / restore) // ========================= on(toggle, 'click', (e) => { if (suppressToggleClick) { e.preventDefault(); suppressToggleClick = false; return; } toggleView(); }); on(toggle, 'keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleView(); } }); on(pipCloseButton, 'click', (e) => { e.preventDefault(); e.stopPropagation(); if (isMinimized()) setPrettyHidden(true); else setPreviewHidden(true); }); on(pipCloseButton, 'pointerdown', (e) => { e.stopPropagation(); }); on(pipRestoreButton, 'click', (e) => { if (suppressRestoreClick) { e.preventDefault(); suppressRestoreClick = false; return; } e.preventDefault(); e.stopPropagation(); if (isMinimized()) setPrettyHidden(false); else setPreviewHidden(false); }); // ========================= // Lifecycle: load / sync / repaint // ========================= const loadState = () => { loadDock(); loadHidden(); if (isPrettyHidden && !isMinimized()) setMinimized(true); updateUI(); repaintToDock(); }; loadState(); on(window, 'storage-ready', () => { storageReady = true; loadState(); }); const onViewportChange = () => repaintToDock(); on(window, 'resize', onViewportChange); if (window.visualViewport) { on(window.visualViewport, 'resize', onViewportChange); on(window.visualViewport, 'scroll', onViewportChange); } // initial preview setTimeout(updatePreview, 100); // initial minimized option if (${startMinimized}) { setMinimized(true); repaintToDock(); void iframe.offsetWidth; updateUI(); } } catch (err) { console.error('Failed to initialize Nuxt error overlay:', err); } })(); `; } function generateErrorOverlayHTML(html, options) { const nonce = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join(""); const errorPage = html.replace("", `