veryfront 0.1.1197 → 0.1.1199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/extensions/ext-llm-openai/src/openai-chat-stream.d.ts.map +1 -1
  3. package/esm/extensions/ext-llm-openai/src/openai-chat-stream.js +0 -13
  4. package/esm/src/cache/keys/builders/render.d.ts.map +1 -1
  5. package/esm/src/cache/keys/builders/render.js +6 -1
  6. package/esm/src/html/hydration-script-builder/hydration-runtime.generated.js +1 -1
  7. package/esm/src/internal-agents/run-stream.d.ts +6 -0
  8. package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
  9. package/esm/src/internal-agents/run-stream.js +44 -3
  10. package/esm/src/platform/adapters/fs/veryfront/proxy-manager.d.ts.map +1 -1
  11. package/esm/src/platform/adapters/fs/veryfront/proxy-manager.js +5 -3
  12. package/esm/src/platform/compat/http/pinned-fetch.d.ts +1 -1
  13. package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
  14. package/esm/src/server/handlers/preview/hmr.handler.js +4 -0
  15. package/esm/src/server/handlers/request/agent-run-cancel.handler.d.ts.map +1 -1
  16. package/esm/src/server/handlers/request/agent-run-cancel.handler.js +10 -1
  17. package/esm/src/server/handlers/request/agent-run-resume.handler.d.ts.map +1 -1
  18. package/esm/src/server/handlers/request/agent-run-resume.handler.js +10 -1
  19. package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
  20. package/esm/src/server/handlers/request/agent-stream.handler.js +17 -42
  21. package/esm/src/server/handlers/request/report-handler-failure.d.ts +18 -0
  22. package/esm/src/server/handlers/request/report-handler-failure.d.ts.map +1 -0
  23. package/esm/src/server/handlers/request/report-handler-failure.js +33 -0
  24. package/esm/src/utils/version-constant.d.ts +1 -1
  25. package/esm/src/utils/version-constant.js +1 -1
  26. package/package.json +8 -8
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.1197",
3
+ "version": "0.1.1199",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -1 +1 @@
1
- {"version":3,"file":"openai-chat-stream.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-chat-stream.ts"],"names":[],"mappings":"AA2BA,KAAK,4BAA4B,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAExE,KAAK,uBAAuB,GAAG;IAC7B,YAAY,CAAC,EAAE,4BAA4B,CAAC;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AASF,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AA4KlD,wBAAuB,2BAA2B,CAChD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,uBAA4B,GACpC,aAAa,CAAC,OAAO,CAAC,CAuVxB"}
1
+ {"version":3,"file":"openai-chat-stream.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-chat-stream.ts"],"names":[],"mappings":"AA2BA,KAAK,4BAA4B,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAExE,KAAK,uBAAuB,GAAG;IAC7B,YAAY,CAAC,EAAE,4BAA4B,CAAC;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AASF,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AA4KlD,wBAAuB,2BAA2B,CAChD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,uBAA4B,GACpC,aAAa,CAAC,OAAO,CAAC,CA0UxB"}
@@ -153,7 +153,6 @@ export async function* streamOpenAICompatibleParts(stream, context = {}) {
153
153
  let sawChoiceEnvelope = false;
154
154
  let sawFinishReason = false;
155
155
  let sawDone = false;
156
- let sawPostFinishUsage = false;
157
156
  const toolArgumentBudget = {
158
157
  bytes: 0,
159
158
  fragments: 0,
@@ -182,12 +181,6 @@ export async function* streamOpenAICompatibleParts(stream, context = {}) {
182
181
  if (!usageRecord) {
183
182
  throw invalidOpenAIStream(context, "event had neither choices nor usage");
184
183
  }
185
- if (sawFinishReason) {
186
- if (sawPostFinishUsage) {
187
- throw invalidOpenAIStream(context, "stream contained multiple post-finish usage events");
188
- }
189
- sawPostFinishUsage = true;
190
- }
191
184
  return;
192
185
  }
193
186
  if (!Array.isArray(record.choices)) {
@@ -197,12 +190,6 @@ export async function* streamOpenAICompatibleParts(stream, context = {}) {
197
190
  if (!usageRecord) {
198
191
  throw invalidOpenAIStream(context, "empty choices event had no usage");
199
192
  }
200
- if (sawFinishReason) {
201
- if (sawPostFinishUsage) {
202
- throw invalidOpenAIStream(context, "stream contained multiple post-finish usage events");
203
- }
204
- sawPostFinishUsage = true;
205
- }
206
193
  return;
207
194
  }
208
195
  if (sawFinishReason) {
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../../../src/src/cache/keys/builders/render.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAO7D,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,UAAU,EAAE,MAAM;AAClB;;;;;GAKG;AACH,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAGR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,CAaR;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,yBAAyB,CAAC,EAAE,MAAM,EAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAOR;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,GACtB,MAAM,CAER;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,OAAO,EACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE;IACV,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,GACA,MAAM,CA0BR;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,GAAG,EACT,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAMR"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../../../src/src/cache/keys/builders/render.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAO7D,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,UAAU,EAAE,MAAM;AAClB;;;;;GAKG;AACH,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAGR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,CAaR;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,yBAAyB,CAAC,EAAE,MAAM,EAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAOR;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,GACtB,MAAM,CAER;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,OAAO,EACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE;IACV,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,GACA,MAAM,CA+BR;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,GAAG,EACT,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAMR"}
@@ -89,7 +89,12 @@ export function buildProxyManagerCacheKey(projectSlug, productionMode, releaseId
89
89
  return `${CacheKeyPrefix.PROXY}:${projectSlug}:${mode}:${source.key}${authorityKey}`;
90
90
  }
91
91
  const source = encodeCacheSourceIdentity({ type: "branch", branch: branch ?? "main" });
92
- return `${CacheKeyPrefix.PROXY}:${projectSlug}:${mode}:${source.qualifier}${authorityKey}`;
92
+ // ProxyFSAdapterManager asserts environmentName matches on reuse, so it must
93
+ // be part of the key. Omitted when unnamed to keep existing keys stable.
94
+ const environmentQualifier = environmentName
95
+ ? `:env:${encodeCacheKeyLiteralSegment(environmentName)}`
96
+ : "";
97
+ return `${CacheKeyPrefix.PROXY}:${projectSlug}:${mode}:${source.qualifier}${environmentQualifier}${authorityKey}`;
93
98
  }
94
99
  /**
95
100
  * Build a query-aware key that preserves query semantics for multi-tenant
@@ -6,4 +6,4 @@
6
6
  * `deno task generate` to regenerate.
7
7
  * @module
8
8
  */
9
- export const HYDRATION_RUNTIME_BUNDLE = '// src/html/hydration-script-builder/runtime/main.ts\nimport * as React from "react";\nimport { createRoot } from "react-dom/client";\nimport { RouterProvider, useRouter as useRouterFromModule } from "veryfront/router";\nimport * as RouterRuntime from "veryfront/router";\nimport { PageContextProvider } from "veryfront/context";\n\n// src/routing/flatten-route-params.ts\nfunction flattenRouteParams(params) {\n if (!params) return {};\n const flat = {};\n for (const [key, value] of Object.entries(params)) {\n if (value === void 0) continue;\n flat[key] = Array.isArray(value) ? value.join("/") : value;\n }\n return flat;\n}\n\n// src/html/hydration-script-builder/runtime/shared.ts\nfunction moduleServerUrl(window) {\n return window.location.origin + "/_vf_modules";\n}\nfunction createLogging(window) {\n const DEBUG = Boolean(\n window.__VERYFRONT_DEBUG__ || new URLSearchParams(window.location.search).has("vf_debug")\n );\n const log = DEBUG ? console.log.bind(console, "[Veryfront]") : () => {\n };\n const logError = console.error.bind(console, "[Veryfront]");\n function logBackgroundFetchFailure(reason, path, error) {\n const message = error?.message ?? String(error);\n log(reason + " failed:", path, message);\n }\n const perfTimers = /* @__PURE__ */ new Map();\n const perfStart = DEBUG ? (label) => {\n perfTimers.set(label, performance.now());\n } : () => {\n };\n const perfEnd = DEBUG ? (label) => {\n const start = perfTimers.get(label);\n if (start === void 0) return 0;\n const duration = performance.now() - start;\n perfTimers.delete(label);\n console.log(\n "[Veryfront Perf] %c" + label + ": %c" + duration.toFixed(2) + "ms",\n "color: #888",\n duration > 100 ? "color: #f00; font-weight: bold" : "color: #0a0"\n );\n return duration;\n } : () => 0;\n return { DEBUG, log, logError, logBackgroundFetchFailure, perfStart, perfEnd };\n}\nfunction isAbortError(error) {\n return error?.name === "AbortError";\n}\nfunction resolveDocumentNavigationUrl(target, origin) {\n try {\n const url = new URL(target, origin);\n if (url.protocol === "http:" || url.protocol === "https:") return url.href;\n } catch (_) {\n }\n return null;\n}\nfunction getDocumentNonce(document2) {\n const element = document2.querySelector("script[nonce], style[nonce], link[nonce]");\n if (!element) return void 0;\n return element.nonce || element.getAttribute("nonce") || void 0;\n}\n\n// src/html/hydration-data-element.ts\nvar HYDRATION_DATA_ELEMENT_ID = "veryfront-hydration-data";\nfunction findServerHydrationDataElement(document2) {\n try {\n const matches = [...document2.querySelectorAll(`[id="${HYDRATION_DATA_ELEMENT_ID}"]`)];\n if (matches.length !== 1) return null;\n const body = document2.body;\n if (!body) return null;\n const element = matches[0];\n if (body.firstElementChild !== element && element.parentElement !== body) return null;\n if (element.tagName?.toLowerCase() !== "script") return null;\n if (element.getAttribute("type")?.trim().toLowerCase() !== "application/json") return null;\n return element;\n } catch {\n return null;\n }\n}\n\n// src/html/hydration-script-builder/runtime/hydration-data.ts\nfunction readInitialHydrationData(document2) {\n try {\n const element = findServerHydrationDataElement(document2);\n return JSON.parse(element && element.textContent ? element.textContent : "{}") || {};\n } catch (_) {\n return {};\n }\n}\nfunction readDocumentDependencyPinningCacheKey(initialHydrationData2) {\n return typeof initialHydrationData2.dependencyPinningCacheKey === "string" && initialHydrationData2.dependencyPinningCacheKey.startsWith("on:") ? initialHydrationData2.dependencyPinningCacheKey : null;\n}\n\n// src/html/hydration-script-builder/runtime/snapshot-modules.ts\nvar RECOVERY_STATE_KEY = "__VF_DEPENDENCY_SNAPSHOT_RECOVERY_STARTED__";\nasync function isDependencySnapshotConflictResponse(response) {\n if (!response || response.status !== 409) return false;\n try {\n const clone = response.clone?.() ?? response;\n const body = (await clone.text?.() ?? "").trim();\n return body === "Unknown dependency snapshot" || body === "export default null; // Unknown dependency snapshot";\n } catch (_) {\n return false;\n }\n}\nfunction createSnapshotModuleImporter(deps) {\n async function recoverFromSnapshotBoundModuleFailure(moduleUrl, allowDocumentReload = true) {\n try {\n const parsedUrl = new URL(moduleUrl, "http://veryfront.local");\n const snapshotKeys = parsedUrl.searchParams.getAll("pins");\n const pathMatch = parsedUrl.pathname.match(\n /^\\/_vf_modules\\/_pins\\/([^/]+)(?:\\/|$)/\n );\n if (pathMatch) {\n try {\n snapshotKeys.push(decodeURIComponent(pathMatch[1]));\n } catch (_) {\n return false;\n }\n }\n if (snapshotKeys.length !== 1 || !/^on:[A-Za-z0-9._-]+$/.test(snapshotKeys[0])) return false;\n const response = await deps.fetchModule(moduleUrl, { cache: "no-store" });\n if (!await isDependencySnapshotConflictResponse(response)) return false;\n if (!allowDocumentReload) return true;\n if (deps.recoveryState[RECOVERY_STATE_KEY] === true) return true;\n deps.recoveryState[RECOVERY_STATE_KEY] = true;\n try {\n deps.reloadDocument();\n } catch (_) {\n delete deps.recoveryState[RECOVERY_STATE_KEY];\n return false;\n }\n return true;\n } catch (_) {\n return false;\n }\n }\n async function importSnapshotBoundModule(moduleUrl, allowDocumentReload = true) {\n try {\n return await deps.importModule(moduleUrl);\n } catch (error) {\n const snapshotConflict = await recoverFromSnapshotBoundModuleFailure(\n moduleUrl,\n allowDocumentReload\n );\n if (snapshotConflict && !allowDocumentReload) {\n const conflictError = new Error(\n "Dependency snapshot is unavailable during speculative module prefetch"\n );\n conflictError.name = "DependencySnapshotConflictError";\n conflictError.dependencySnapshotConflict = true;\n conflictError.cause = error;\n throw conflictError;\n }\n throw error;\n }\n }\n return { importSnapshotBoundModule, recoverFromSnapshotBoundModuleFailure };\n}\nfunction isDependencySnapshotConflict(error) {\n return Boolean(error?.dependencySnapshotConflict);\n}\n\n// src/utils/version-constant.ts\nvar VERSION = "0.1.1197";\n\n// src/html/hydration-script-builder/runtime/module-urls.ts\nfunction appendQueryParam(url, key, value) {\n return url + (url.includes("?") ? "&" : "?") + key + "=" + value;\n}\nfunction appendDependencyPinningVersion(url, moduleData) {\n const pinKey = moduleData && moduleData.dependencyPinningCacheKey;\n if (typeof pinKey !== "string" || !pinKey.startsWith("on:")) return url;\n const hashIndex = url.indexOf("#");\n const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";\n const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;\n const queryIndex = withoutHash.indexOf("?");\n const base = queryIndex >= 0 ? withoutHash.slice(0, queryIndex) : withoutHash;\n const params = new URLSearchParams(queryIndex >= 0 ? withoutHash.slice(queryIndex + 1) : "");\n const modulePrefix = "/_vf_modules/";\n const prefixIndex = base.indexOf(modulePrefix);\n const origin = prefixIndex >= 0 ? base.slice(0, prefixIndex) : "";\n if (prefixIndex >= 0 && (origin === "" || /^https?:\\/\\/[^/]+$/i.test(origin))) {\n const pathStart = prefixIndex + modulePrefix.length;\n let modulePath = base.slice(pathStart);\n if (modulePath.startsWith("_pins/")) {\n const existingKeyEnd = modulePath.indexOf("/", "_pins/".length);\n const encodedExistingKey = existingKeyEnd < 0 ? modulePath.slice("_pins/".length) : modulePath.slice("_pins/".length, existingKeyEnd);\n let existingKey;\n try {\n existingKey = decodeURIComponent(encodedExistingKey);\n } catch {\n existingKey = void 0;\n }\n if (existingKey && /^on:[A-Za-z0-9._-]+$/.test(existingKey)) {\n if (existingKeyEnd < 0) return url;\n modulePath = modulePath.slice(existingKeyEnd + 1);\n }\n }\n params.delete("pins");\n const query = params.toString();\n return base.slice(0, pathStart) + "_pins/" + encodeURIComponent(pinKey) + "/" + modulePath + (query ? "?" + query : "") + hash;\n }\n params.set("pins", pinKey);\n return base + "?" + params.toString() + hash;\n}\nfunction componentCacheKey(path, moduleData) {\n const pinKey = moduleData && moduleData.dependencyPinningCacheKey;\n return typeof pinKey === "string" && pinKey.startsWith("on:") ? path + "|vf_pins|" + pinKey : path;\n}\nfunction normalizeReleaseAssetModulePath(path) {\n return String(path || "").replace(/^\\/?_vf_modules\\//, "").replace(/^\\/+/, "").replace(/[?#].*$/, "");\n}\nfunction buildPinnedRscModuleUrl(path, moduleData) {\n let moduleUrl = "/_veryfront/rsc/module?rel=" + encodeURIComponent(path);\n const pinKey = moduleData && moduleData.dependencyPinningCacheKey;\n if (typeof pinKey === "string" && pinKey.startsWith("on:")) {\n moduleUrl += "&pins=" + encodeURIComponent(pinKey);\n }\n return moduleUrl;\n}\nfunction buildPageDataEndpoint(path, origin) {\n const targetUrl = new URL(path, origin);\n const normalizedPath = targetUrl.pathname === "/" ? "" : targetUrl.pathname.replace(/^\\//, "");\n const endpointUrl = new URL(\n "/_veryfront/page-data/" + normalizedPath + ".json",\n origin\n );\n endpointUrl.search = targetUrl.search;\n return endpointUrl.pathname + endpointUrl.search;\n}\nfunction pageDataCacheIdentity(path, documentDependencyPinningCacheKey2) {\n return documentDependencyPinningCacheKey2 ? documentDependencyPinningCacheKey2 + "|path:" + path : path;\n}\nfunction assertPageDataMatchesDocumentSnapshot(path, data, documentDependencyPinningCacheKey2) {\n if (!documentDependencyPinningCacheKey2) return data;\n if (data && data.dependencyPinningCacheKey === documentDependencyPinningCacheKey2) {\n return data;\n }\n const error = new Error("Page data dependency snapshot does not match the document");\n error.status = 409;\n error.dependencySnapshotMismatch = true;\n error.path = path;\n throw error;\n}\n\n// src/html/hydration-script-builder/runtime/component-loader.ts\nvar VERYFRONT_RUNTIME_VERSION = VERSION;\nfunction createComponentLoader(deps) {\n const { window, moduleServerUrl: moduleServerUrl2 } = deps;\n const { DEBUG, log, logError } = deps.logging;\n const componentCache = /* @__PURE__ */ new Map();\n const loadingPromises = /* @__PURE__ */ new Map();\n let releaseId = null;\n let releaseAssetModules = null;\n let studioEmbed = false;\n let hmrRefreshTimestamp = null;\n function clearComponentCache(path) {\n if (!path) {\n componentCache.clear();\n loadingPromises.clear();\n log("Cleared all component caches");\n return;\n }\n for (const key of componentCache.keys()) {\n if (key === path || key.startsWith(path + "|vf_pins|")) {\n componentCache.delete(key);\n }\n }\n for (const key of loadingPromises.keys()) {\n if (key === path || key.startsWith(path + "|vf_pins|")) {\n loadingPromises.delete(key);\n }\n }\n log("Cleared component cache for:", path);\n }\n function setReleaseId(value) {\n releaseId = typeof value === "string" && value ? value : null;\n window.__veryfrontReleaseId = releaseId;\n }\n function appendReleaseModuleVersion(url) {\n if (!releaseId || url.includes("vf_release=")) return url;\n let versionedUrl = appendQueryParam(url, "vf_release", encodeURIComponent(releaseId));\n versionedUrl = appendQueryParam(\n versionedUrl,\n "vf_runtime",\n encodeURIComponent(VERYFRONT_RUNTIME_VERSION)\n );\n return versionedUrl;\n }\n function setReleaseAssetModules(value) {\n releaseAssetModules = value && typeof value === "object" && !Array.isArray(value) ? value : null;\n window.__veryfrontReleaseAssetModules = releaseAssetModules;\n }\n function resolveReleaseAssetModuleUrl(path) {\n if (!releaseAssetModules || studioEmbed || hmrRefreshTimestamp) return null;\n const key = normalizeReleaseAssetModulePath(path);\n if (releaseAssetModules[key]) return releaseAssetModules[key];\n const withoutExt = key.replace(/\\.(tsx|ts|jsx|mdx|js|mjs)$/, "");\n const extensions = [".tsx", ".ts", ".jsx", ".mdx", ".js"];\n for (const ext of extensions) {\n const candidate = withoutExt + ext;\n if (releaseAssetModules[candidate]) return releaseAssetModules[candidate];\n }\n return null;\n }\n function pathToModuleUrl(path, embedInStudio, moduleData) {\n const releaseAssetUrl = resolveReleaseAssetModuleUrl(path);\n if (releaseAssetUrl) return releaseAssetUrl;\n const pattern = /(pages|components|app|lib|layouts|shared|features)\\/(.+)\\.(tsx|ts|jsx|mdx)$/;\n const match = path.match(new RegExp("/" + pattern.source)) || path.match(new RegExp("^" + pattern.source));\n let url;\n if (match) {\n url = moduleServerUrl2 + "/" + match[1] + "/" + match[2] + ".js";\n } else {\n const hasKnownExt = /\\.(tsx|ts|jsx|mdx|js|mjs)$/.test(path);\n url = moduleServerUrl2 + "/" + (hasKnownExt ? path.replace(/\\.(tsx|ts|jsx|mdx)$/, ".js") : path + ".js");\n }\n if (embedInStudio) url = appendQueryParam(url, "studio_embed", "true");\n if (hmrRefreshTimestamp) url = appendQueryParam(url, "t", hmrRefreshTimestamp);\n if (!embedInStudio && !hmrRefreshTimestamp) url = appendReleaseModuleVersion(url);\n url = appendDependencyPinningVersion(url, moduleData);\n return url;\n }\n function setStudioEmbed(value) {\n studioEmbed = value;\n window.__veryfrontStudioEmbed = value;\n }\n function setHMRRefreshTimestamp(timestamp) {\n hmrRefreshTimestamp = timestamp;\n window.__veryfrontHMRRefreshTimestamp = timestamp;\n }\n async function loadComponent(path, moduleData, options = {}) {\n if (!path) return null;\n const cacheKey = componentCacheKey(path, moduleData);\n if (componentCache.has(cacheKey)) {\n log("Component cached:", path);\n return componentCache.get(cacheKey);\n }\n const existingPromise = loadingPromises.get(cacheKey);\n if (existingPromise) return existingPromise;\n const loadPromise = (async () => {\n try {\n const moduleUrl = pathToModuleUrl(path, studioEmbed, moduleData);\n const start = DEBUG ? performance.now() : 0;\n log("Loading component:", moduleUrl);\n const module = await deps.snapshotModules.importSnapshotBoundModule(\n moduleUrl,\n options.allowDocumentReload !== false\n );\n const component = module.MDXLayout || module.MainLayout || module.default || module;\n if (DEBUG) {\n const duration = performance.now() - start;\n console.log(\n "[Veryfront Perf] %cimport:" + path.split("/").pop() + ": %c" + duration.toFixed(2) + "ms",\n "color: #888",\n duration > 50 ? "color: #f00; font-weight: bold" : "color: #0a0"\n );\n }\n componentCache.set(cacheKey, component);\n return component;\n } catch (error) {\n if (isDependencySnapshotConflict(error)) throw error;\n logError("Failed to load component:", path, error);\n return null;\n } finally {\n loadingPromises.delete(cacheKey);\n }\n })();\n loadingPromises.set(cacheKey, loadPromise);\n return loadPromise;\n }\n return {\n loadComponent,\n pathToModuleUrl,\n clearComponentCache,\n setStudioEmbed,\n setReleaseId,\n setReleaseAssetModules,\n setHMRRefreshTimestamp\n };\n}\n\n// src/html/hydration-script-builder/runtime/route-timing.ts\nvar MAX_ROUTE_TIMINGS = 100;\nvar MAX_SERVER_TIMING_LENGTH = 1024;\nfunction routeTimingNow() {\n return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();\n}\nfunction sanitizeServerTimingMetricName(name) {\n return String(name || "").trim().replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 128);\n}\nfunction sanitizeServerTimingHeader(value) {\n if (!value) return null;\n const metrics = [];\n const printable = String(value).replace(/[^\\x20-\\x7E]/g, " ").trim();\n if (!printable) return null;\n for (const item of printable.split(",")) {\n const segments = item.split(";").map((segment) => segment.trim()).filter(Boolean);\n const name = sanitizeServerTimingMetricName(segments[0]);\n if (!name) continue;\n for (const segment of segments.slice(1)) {\n const [key, rawValue = ""] = segment.split("=");\n if ((key ?? "").trim().toLowerCase() !== "dur") continue;\n const duration = Number(rawValue.trim().replace(/^"|"$/g, ""));\n if (!Number.isFinite(duration) || duration < 0) continue;\n metrics.push(name + ";dur=" + (Math.round(duration * 100) / 100).toFixed(2));\n break;\n }\n }\n const sanitized = metrics.join(", ");\n return sanitized ? sanitized.slice(0, MAX_SERVER_TIMING_LENGTH) : null;\n}\nfunction parseServerTimingMetrics(value) {\n const header = sanitizeServerTimingHeader(value);\n if (!header) return null;\n const metrics = {};\n for (const item of header.split(",")) {\n const segments = item.split(";").map((segment) => segment.trim()).filter(Boolean);\n const name = sanitizeServerTimingMetricName(segments[0]);\n if (!name) continue;\n for (const segment of segments.slice(1)) {\n const [key, rawValue = ""] = segment.split("=");\n if ((key ?? "").trim().toLowerCase() !== "dur") continue;\n const duration = Number(rawValue.trim().replace(/^"|"$/g, ""));\n if (Number.isFinite(duration) && duration >= 0) {\n metrics[name] = Math.round(duration * 100) / 100;\n }\n }\n }\n return Object.keys(metrics).length ? metrics : null;\n}\nfunction readResponseServerTiming(response) {\n try {\n return sanitizeServerTimingHeader(response.headers?.get("server-timing"));\n } catch (_) {\n return null;\n }\n}\nfunction roundRouteTimingValue(value) {\n return Math.round(value * 100) / 100;\n}\nfunction extractResourceTiming(entry) {\n const fields = [\n "startTime",\n "requestStart",\n "responseStart",\n "responseEnd",\n "duration",\n "transferSize",\n "encodedBodySize",\n "decodedBodySize"\n ];\n const timing = {};\n for (const field of fields) {\n const value = entry?.[field];\n if (typeof value === "number" && Number.isFinite(value) && value >= 0) {\n timing[field] = roundRouteTimingValue(value);\n }\n }\n return Object.keys(timing).length ? timing : null;\n}\nfunction createRouteTimingRecorder(window, logging2) {\n const { log } = logging2;\n function emitRouteTiming(phase, path, startedAt, detail = {}) {\n const entry = {\n phase,\n path,\n duration: Math.max(0, routeTimingNow() - startedAt),\n timestamp: Date.now(),\n ...detail\n };\n const timings = Array.isArray(window.__veryfrontRouteTimings) ? window.__veryfrontRouteTimings : [];\n timings.push(entry);\n if (timings.length > MAX_ROUTE_TIMINGS) {\n timings.splice(0, timings.length - MAX_ROUTE_TIMINGS);\n }\n window.__veryfrontRouteTimings = timings;\n try {\n window.dispatchEvent(new CustomEvent("veryfront:route-timing", { detail: entry }));\n } catch (_) {\n }\n log("Route timing:", entry);\n return entry;\n }\n function getPageDataResourceTiming(endpoint, fetchStartedAt) {\n try {\n if (typeof performance === "undefined" || typeof performance.getEntriesByName !== "function") {\n return null;\n }\n const href = new URL(endpoint, window.location.href).href;\n const entries = performance.getEntriesByName(href, "resource");\n if (!entries.length) return null;\n for (let index = entries.length - 1; index >= 0; index--) {\n const entry = entries[index];\n const responseEnd = entry?.responseEnd;\n if (typeof responseEnd === "number" && Number.isFinite(responseEnd) && responseEnd + 1 >= fetchStartedAt) {\n return extractResourceTiming(entry);\n }\n }\n return null;\n } catch (_) {\n return null;\n }\n }\n function buildPageDataTimingDetail(response, endpoint, fetchStartedAt, source) {\n const detail = { source, status: response.status };\n const serverTiming = readResponseServerTiming(response);\n if (serverTiming) {\n detail.serverTiming = serverTiming;\n const serverTimingMetrics = parseServerTimingMetrics(serverTiming);\n if (serverTimingMetrics) detail.serverTimingMetrics = serverTimingMetrics;\n }\n const resourceTiming = getPageDataResourceTiming(response.url || endpoint, fetchStartedAt);\n if (resourceTiming) detail.resourceTiming = resourceTiming;\n return detail;\n }\n return { emitRouteTiming, buildPageDataTimingDetail };\n}\n\n// src/html/managed-head-protocol.ts\nvar HEAD_PROVENANCE_ATTRIBUTE = "data-vf-head";\nvar HEAD_LEGACY_MANAGED_ATTRIBUTE = "data-veryfront-managed";\nvar HEAD_CONTENT_HASH_ATTRIBUTE = "data-vf-hash";\nvar HEAD_REACT_MANAGED_ATTRIBUTE = "data-vf-react-head";\nvar HEAD_REACT_OWNER_ATTRIBUTE = "data-vf-react-head-owner";\nvar HEAD_ROUTE_MANAGED_ATTRIBUTE = "data-vf-route-head";\nvar HEAD_SERVER_COMMIT_ATTRIBUTE = "data-vf-server-head-commit";\nvar HEAD_SHELL_PROVENANCE_ATTRIBUTE = "data-vf-shell-head";\nvar HEAD_SSR_PAYLOAD_ATTRIBUTE = "data-vf-ssr-head";\nvar MAX_MANAGED_HEAD_BYTES = 2 * 1024 * 1024;\nvar MAX_MANAGED_HEAD_PAYLOAD_BYTES = MAX_MANAGED_HEAD_BYTES * 2;\nvar SINGLETON_META_KEYS = /* @__PURE__ */ new Set([\n "description",\n "robots",\n "viewport",\n "referrer",\n "color-scheme",\n "application-name",\n "generator",\n "og:title",\n "og:description",\n "og:url",\n "og:type",\n "og:site_name",\n "og:locale",\n "twitter:card",\n "twitter:site",\n "twitter:creator",\n "twitter:title",\n "twitter:description",\n "twitter:image",\n "twitter:image:alt"\n]);\nvar SINGLETON_LINK_RELS = /* @__PURE__ */ new Set([\n "canonical",\n "manifest",\n "amphtml"\n]);\nvar MAX_HEAD_ATTRIBUTE_VALUE_BYTES = 64 * 1024;\nvar MAX_HEAD_ATTRIBUTE_BYTES = 1024 * 1024;\nvar MAX_HEAD_CONTENT_BYTES = 1024 * 1024;\nvar headTextEncoder = new TextEncoder();\nvar BOOLEAN_HEAD_ATTRIBUTES = /* @__PURE__ */ new Set([\n "async",\n "defer",\n "disabled",\n "itemscope",\n "nomodule"\n]);\nfunction isHeadFrameworkAttribute(name) {\n switch (name.toLowerCase()) {\n case HEAD_PROVENANCE_ATTRIBUTE:\n case HEAD_LEGACY_MANAGED_ATTRIBUTE:\n case HEAD_CONTENT_HASH_ATTRIBUTE:\n case HEAD_REACT_MANAGED_ATTRIBUTE:\n case HEAD_REACT_OWNER_ATTRIBUTE:\n case HEAD_ROUTE_MANAGED_ATTRIBUTE:\n case HEAD_SERVER_COMMIT_ATTRIBUTE:\n case HEAD_SHELL_PROVENANCE_ATTRIBUTE:\n case HEAD_SSR_PAYLOAD_ATTRIBUTE:\n return true;\n default:\n return false;\n }\n}\nfunction normalizeHeadIdentityValue(value) {\n const normalized = value?.trim().toLowerCase();\n return normalized || void 0;\n}\nfunction readOwnString(record, key) {\n try {\n const descriptor = Reflect.getOwnPropertyDescriptor(record, key);\n return descriptor && !descriptor.get && !descriptor.set && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;\n } catch {\n return void 0;\n }\n}\nfunction headMetaSingletonKeyFromRecord(meta) {\n if (readOwnString(meta, "charset") !== void 0) return "meta:charset";\n const key = normalizeHeadIdentityValue(\n readOwnString(meta, "property") ?? readOwnString(meta, "name")\n );\n if (!key) return void 0;\n if (key === "theme-color") {\n return `meta:theme-color:${readOwnString(meta, "media")?.trim() ?? ""}`;\n }\n return SINGLETON_META_KEYS.has(key) ? `meta:${key}` : void 0;\n}\nfunction headLinkSingletonKeyFromRecord(link) {\n const rel = normalizeHeadIdentityValue(readOwnString(link, "rel"));\n return rel && SINGLETON_LINK_RELS.has(rel) ? `link:${rel}` : void 0;\n}\n\n// src/html/client-head-manager.ts\nvar HEAD_MANAGER_STATE_SYMBOL = /* @__PURE__ */ Symbol.for(\n "veryfront.client-head-manager.v2"\n);\nvar CROSS_PAGE_PRESERVED_SINGLETON_KEYS = /* @__PURE__ */ new Set([\n "meta:viewport",\n "link:manifest"\n]);\nfunction getClientHeadManagerState() {\n const globalState = globalThis;\n return globalState[HEAD_MANAGER_STATE_SYMBOL] ?? (globalState[HEAD_MANAGER_STATE_SYMBOL] = {\n documents: /* @__PURE__ */ new WeakMap()\n });\n}\nfunction readElementAttributes(element) {\n const attributes = [];\n for (const attribute of element.attributes) {\n const name = attribute.name.toLowerCase();\n if (isHeadFrameworkAttribute(name)) continue;\n const nonce = name === "nonce" && "nonce" in element ? element.nonce : "";\n const value = BOOLEAN_HEAD_ATTRIBUTES.has(name) ? "" : nonce || attribute.value;\n attributes.push([name, value]);\n }\n return attributes.sort(([left], [right]) => left.localeCompare(right));\n}\nfunction elementSingletonKey(element) {\n const tagName = element.tagName.toLowerCase();\n if (tagName === "title") return "title";\n const attributes = Object.fromEntries(readElementAttributes(element));\n if (tagName === "meta") return headMetaSingletonKeyFromRecord(attributes);\n if (tagName === "link") return headLinkSingletonKeyFromRecord(attributes);\n return void 0;\n}\nfunction promoteToShellHeadBaseline(element) {\n for (const attribute of [...element.attributes]) {\n if (isHeadFrameworkAttribute(attribute.name)) {\n element.removeAttribute(attribute.name);\n }\n }\n element.setAttribute(HEAD_SHELL_PROVENANCE_ATTRIBUTE, "true");\n}\nfunction isCrossPagePreservedSingleton(element, singletonKey = elementSingletonKey(element)) {\n return element.parentElement !== null && singletonKey !== void 0 && CROSS_PAGE_PRESERVED_SINGLETON_KEYS.has(singletonKey);\n}\nfunction isFrameworkOwnedHeadElement(element) {\n return element.getAttribute(HEAD_PROVENANCE_ATTRIBUTE) === "true" || element.getAttribute(HEAD_REACT_MANAGED_ATTRIBUTE) === "true" || element.getAttribute(HEAD_LEGACY_MANAGED_ATTRIBUTE) === "1" || element.getAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE) === "true" || element.getAttribute(HEAD_SHELL_PROVENANCE_ATTRIBUTE) === "true";\n}\nfunction retireFrameworkHeadElement(element) {\n if (isCrossPagePreservedSingleton(element)) {\n promoteToShellHeadBaseline(element);\n return;\n }\n element.remove();\n}\nfunction retireClientHeadOwnership(targetDocument) {\n const manager = getClientHeadManagerState().documents.get(targetDocument);\n if (manager) {\n manager.retire();\n return;\n }\n for (const element of [...targetDocument.head?.children ?? []]) {\n if (isFrameworkOwnedHeadElement(element)) retireFrameworkHeadElement(element);\n }\n}\n\n// src/html/client-route-head.ts\nfunction updateRouteTitle(title, targetDocument = document) {\n if (typeof title !== "string" || !title) return;\n const titles = [...targetDocument.head.querySelectorAll("title")];\n if (titles.some((element) => element.getAttribute(HEAD_LEGACY_MANAGED_ATTRIBUTE) === "1")) {\n return;\n }\n let titleElement = titles.find(\n (element) => element.getAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE) === "true"\n );\n for (const element of titles) {\n if (element !== titleElement) element.remove();\n }\n if (!titleElement) {\n titleElement = targetDocument.createElement("title");\n titleElement.setAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE, "true");\n targetDocument.head.appendChild(titleElement);\n }\n titleElement.textContent = title;\n}\nfunction updateRouteMetaTag(targetDocument, selector, attributeName, attributeValue, content) {\n const matches = [...targetDocument.head.querySelectorAll(selector)];\n if (matches.some((element) => element.getAttribute(HEAD_LEGACY_MANAGED_ATTRIBUTE) === "1")) {\n return;\n }\n let metaTag = matches.find(\n (element) => element.getAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE) === "true"\n );\n if (!metaTag) {\n metaTag = targetDocument.createElement("meta");\n metaTag.setAttribute(attributeName, attributeValue);\n metaTag.setAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE, "true");\n targetDocument.head.appendChild(metaTag);\n }\n metaTag.setAttribute("content", content);\n}\nfunction updateRouteMetaTags(metadata, targetDocument = document) {\n if (typeof metadata.description === "string" && metadata.description) {\n updateRouteMetaTag(\n targetDocument,\n \'meta[name="description"]\',\n "name",\n "description",\n metadata.description\n );\n }\n if (typeof metadata.ogTitle === "string" && metadata.ogTitle) {\n updateRouteMetaTag(\n targetDocument,\n \'meta[property="og:title"]\',\n "property",\n "og:title",\n metadata.ogTitle\n );\n }\n}\nfunction handoffClientRouteMetadata(metadata, targetDocument = document) {\n const retainedTitle = targetDocument.title;\n retireClientHeadOwnership(targetDocument);\n updateRouteTitle(\n typeof metadata.title === "string" && metadata.title ? metadata.title : retainedTitle,\n targetDocument\n );\n updateRouteMetaTags(metadata, targetDocument);\n}\n\n// src/html/hydration-script-builder/runtime/router.ts\nvar FETCH_TIMEOUT_MS = 1e4;\nvar MAX_RETRIES = 2;\nvar MAX_CACHE_SIZE = 50;\nvar CACHE_TTL_MS = 5 * 60 * 1e3;\nvar BACKGROUND_REFRESH_INTERVAL_MS = 30 * 1e3;\nvar PREFETCH_DELAY_MS = 100;\nvar MAX_PREFETCH_PATHS = 100;\nvar IDLE_PREFETCH_DELAY_MS = 1200;\nvar IDLE_PREFETCH_MAX_LINKS = 4;\nvar VIEWPORT_PREFETCH_MAX_LINKS = 8;\nvar PAGE_DATA_PREFETCH_CONCURRENCY = 2;\nvar VIEWPORT_PREFETCH_ROOT_MARGIN = "200px";\nvar MAX_SCROLL_POSITIONS = 100;\nfunction createRouterRuntime(deps) {\n const { env: env2, logging: logging2, routeTiming: routeTiming2, componentLoader: componentLoader2, snapshotModules: snapshotModules2 } = deps;\n const { window, document: document2, React: React2, RouterProvider: RouterProvider2, PageContextProvider: PageContextProvider2 } = env2;\n const { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = env2;\n const { log, logError, logBackgroundFetchFailure, perfStart, perfEnd } = logging2;\n const { emitRouteTiming, buildPageDataTimingDetail } = routeTiming2;\n const { loadComponent } = componentLoader2;\n const documentPinKey = deps.documentDependencyPinningCacheKey;\n let hydrationResolve;\n let hydrationReject;\n const hydrationPromise = new Promise((resolve, reject) => {\n hydrationResolve = resolve;\n hydrationReject = reject;\n });\n let hydrationCompleted = false;\n let hydrationFailed = false;\n function signalHydrationComplete() {\n hydrationCompleted = true;\n hydrationResolve();\n log("Hydration complete signal received");\n }\n function signalHydrationFailed(error) {\n hydrationFailed = true;\n hydrationReject(error);\n logError("Hydration failed signal received:", error);\n }\n window.__veryfrontHydrationComplete = signalHydrationComplete;\n window.__veryfrontHydrationFailed = signalHydrationFailed;\n function pageDataCacheIdentity2(path) {\n return pageDataCacheIdentity(path, documentPinKey);\n }\n function navigateDocument(target) {\n const safeUrl = resolveDocumentNavigationUrl(target, window.location.origin);\n if (safeUrl) {\n window.location.href = safeUrl;\n return;\n }\n logError("Refusing an unsafe document navigation:", target);\n window.location.reload();\n }\n let clientBuildVersion = null;\n function checkVersionMismatch(newVersion) {\n if (!clientBuildVersion) {\n clientBuildVersion = newVersion;\n log("Build version initialized:", newVersion);\n return false;\n }\n if (newVersion.serverStart !== clientBuildVersion.serverStart) {\n log("Server restarted, reloading...", {\n old: clientBuildVersion.serverStart,\n new: newVersion.serverStart\n });\n return true;\n }\n if (newVersion.framework !== clientBuildVersion.framework) {\n log("Framework version changed, reloading...", {\n old: clientBuildVersion.framework,\n new: newVersion.framework\n });\n return true;\n }\n if (newVersion.projectUpdated && clientBuildVersion.projectUpdated && newVersion.projectUpdated !== clientBuildVersion.projectUpdated) {\n log("Project content updated, reloading...", {\n old: clientBuildVersion.projectUpdated,\n new: newVersion.projectUpdated\n });\n return true;\n }\n return false;\n }\n const pageDataCache = /* @__PURE__ */ new Map();\n const pendingPageDataFetches = /* @__PURE__ */ new Map();\n const backgroundRefreshTimestamps = /* @__PURE__ */ new Map();\n function getCachedPageData(path) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n const entry = pageDataCache.get(cacheIdentity);\n if (!entry) return null;\n if (Date.now() - entry.timestamp < CACHE_TTL_MS) return entry.data;\n pageDataCache.delete(cacheIdentity);\n backgroundRefreshTimestamps.delete(cacheIdentity);\n return null;\n }\n function setCachedPageData(path, data) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n if (pageDataCache.size >= MAX_CACHE_SIZE) {\n const oldest = pageDataCache.keys().next().value;\n if (oldest) {\n pageDataCache.delete(oldest);\n backgroundRefreshTimestamps.delete(oldest);\n }\n }\n pageDataCache.set(cacheIdentity, { data, timestamp: Date.now() });\n }\n const scrollPositions = /* @__PURE__ */ new Map();\n function saveScrollPosition(path) {\n if (scrollPositions.size >= MAX_SCROLL_POSITIONS) {\n const oldest = scrollPositions.keys().next().value;\n if (oldest) scrollPositions.delete(oldest);\n }\n scrollPositions.set(path, window.scrollY);\n }\n function restoreScrollPosition(path) {\n const savedY = scrollPositions.get(path);\n if (savedY === void 0) return false;\n requestAnimationFrame(() => window.scrollTo(0, savedY));\n return true;\n }\n let progressBar = null;\n let progressTimeout = null;\n function showNavigationProgress() {\n if (!progressBar) {\n progressBar = document2.createElement("div");\n progressBar.id = "vf-nav-progress";\n progressBar.style.cssText = "position:fixed;top:0;left:0;height:3px;width:0;background:linear-gradient(90deg,#0066ff,#00aaff);z-index:99999;transition:width 0.3s ease-out,opacity 0.2s;opacity:1;";\n document2.body.prepend(progressBar);\n }\n progressBar.style.opacity = "1";\n progressBar.style.width = "30%";\n progressTimeout = setTimeout2(() => {\n if (progressBar?.style) progressBar.style.width = "70%";\n }, 300);\n document2.body.setAttribute("aria-busy", "true");\n }\n function hideNavigationProgress() {\n if (progressTimeout) {\n clearTimeout2(progressTimeout);\n progressTimeout = null;\n }\n if (progressBar) {\n progressBar.style.width = "100%";\n setTimeout2(() => {\n if (!progressBar) return;\n progressBar.style.opacity = "0";\n setTimeout2(() => {\n if (progressBar) progressBar.style.width = "0";\n }, 200);\n }, 150);\n }\n document2.body.removeAttribute("aria-busy");\n }\n let currentAbortController = null;\n function sleep(ms) {\n return new Promise((resolve) => setTimeout2(resolve, ms));\n }\n async function fetchWithRetry(url, options, maxRetries = MAX_RETRIES) {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const controller = new AbortController();\n const callerSignal = options.signal;\n const abortFromCaller = () => controller.abort();\n if (callerSignal?.aborted) controller.abort();\n callerSignal?.addEventListener("abort", abortFromCaller, { once: true });\n const timeout = setTimeout2(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await env2.fetch(url, { ...options, signal: controller.signal });\n clearTimeout2(timeout);\n callerSignal?.removeEventListener("abort", abortFromCaller);\n if (response.ok) return response;\n if (response.status >= 500 && attempt < maxRetries) {\n log("Server error, retrying...", response.status);\n await sleep(Math.pow(2, attempt) * 500);\n continue;\n }\n return response;\n } catch (error) {\n clearTimeout2(timeout);\n callerSignal?.removeEventListener("abort", abortFromCaller);\n if (error.name === "AbortError" && callerSignal?.aborted) throw error;\n if (attempt === maxRetries) throw error;\n log("Fetch failed, retrying...", error.message);\n await sleep(Math.pow(2, attempt) * 500);\n }\n }\n throw new Error("Failed to fetch page data");\n }\n async function fetchPageDataFresh(path, signal, options = {}) {\n const {\n triggerReloadOnVersionMismatch = false,\n recordRouteTiming = false,\n timingSource = "network"\n } = options;\n const endpoint = buildPageDataEndpoint(path, window.location.origin);\n const startedAt = recordRouteTiming ? routeTimingNow() : 0;\n log("Fetching page data:", path);\n perfStart("fetch:" + path);\n const headers = options.prefetch ? { "X-Veryfront-Prefetch": "1" } : { "X-Veryfront-Navigation": "spa" };\n if (documentPinKey) {\n headers["X-Veryfront-Dependency-Pins"] = documentPinKey;\n }\n const response = await fetchWithRetry(endpoint, {\n headers,\n signal\n }, options.prefetch ? 0 : MAX_RETRIES);\n if (!response.ok) {\n perfEnd("fetch:" + path);\n if (recordRouteTiming) {\n emitRouteTiming(\n "page-data",\n path,\n startedAt,\n buildPageDataTimingDetail(response, endpoint, startedAt, timingSource)\n );\n }\n const error = new Error("Failed to fetch page data: " + response.status);\n error.status = response.status;\n throw error;\n }\n perfStart("parse:" + path);\n const data = assertPageDataMatchesDocumentSnapshot(\n path,\n await response.json(),\n documentPinKey\n );\n perfEnd("parse:" + path);\n perfEnd("fetch:" + path);\n if (recordRouteTiming) {\n emitRouteTiming(\n "page-data",\n path,\n startedAt,\n buildPageDataTimingDetail(response, endpoint, startedAt, timingSource)\n );\n }\n if (triggerReloadOnVersionMismatch) {\n const checkedData = handlePageDataVersionMismatch(path, data);\n if (checkedData !== data) return checkedData;\n }\n setCachedPageData(path, data);\n return data;\n }\n function handlePageDataVersionMismatch(path, data) {\n if (data.buildVersion && checkVersionMismatch(data.buildVersion)) {\n log("Version mismatch detected, performing full page reload to:", path);\n navigateDocument(path);\n return new Promise(() => {\n });\n }\n return data;\n }\n function startPageDataFetch(path, signal, options = {}) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n const request = fetchPageDataFresh(path, signal, options).finally(() => {\n if (options.trackPending !== false && pendingPageDataFetches.get(cacheIdentity) === request) {\n pendingPageDataFetches.delete(cacheIdentity);\n }\n });\n if (options.trackPending !== false) {\n pendingPageDataFetches.set(cacheIdentity, request);\n }\n return request;\n }\n function fetchPageDataDeduped(path) {\n const pending = pendingPageDataFetches.get(pageDataCacheIdentity2(path));\n if (pending) return pending;\n return startPageDataFetch(path, null);\n }\n function refreshPageDataInBackground(path) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n const lastRefreshAt = backgroundRefreshTimestamps.get(cacheIdentity) || 0;\n const now = Date.now();\n if (now - lastRefreshAt < BACKGROUND_REFRESH_INTERVAL_MS) return;\n backgroundRefreshTimestamps.set(cacheIdentity, now);\n fetchPageDataDeduped(path).catch((error) => {\n logBackgroundFetchFailure("Stale page data refresh", path, error);\n });\n }\n async function fetchPageDataForNavigation(path, signal) {\n const startedAt = routeTimingNow();\n const cached = getCachedPageData(path);\n if (cached) {\n log("Using cached page data:", path);\n refreshPageDataInBackground(path);\n emitRouteTiming("page-data", path, startedAt, { source: "cache" });\n return cached;\n }\n const pending = pendingPageDataFetches.get(pageDataCacheIdentity2(path));\n if (pending) {\n log("Reusing pending page data fetch for navigation:", path);\n const data = await pending;\n emitRouteTiming("page-data", path, startedAt, { source: "deduped" });\n return handlePageDataVersionMismatch(path, data);\n }\n return startPageDataFetch(path, signal, {\n triggerReloadOnVersionMismatch: true,\n recordRouteTiming: true,\n timingSource: "network"\n });\n }\n function fetchPageDataForPrefetch(path, signal) {\n if (getCachedPageData(path)) return Promise.resolve();\n return startPageDataFetch(path, signal, { prefetch: true, trackPending: false }).then((data) => preloadModulesForPageData(data, path)).catch((error) => {\n if (!isAbortError(error)) {\n logBackgroundFetchFailure("Page data prefetch", path, error);\n }\n throw error;\n });\n }\n let currentPath = window.location.pathname;\n let isNavigating = false;\n async function navigateSPA(href, historyMode = "push", restoreScroll = false) {\n currentAbortController?.abort();\n if (isNavigating) return;\n isNavigating = true;\n const [navigationPath] = href.split("#");\n removeQueuedPrefetch(navigationPath || href);\n abortActiveSpeculativePrefetches();\n currentAbortController = new AbortController();\n const signal = currentAbortController.signal;\n const navigationStartedAt = routeTimingNow();\n showNavigationProgress();\n perfStart("nav:total:" + href);\n try {\n log("SPA navigating to:", href);\n saveScrollPosition(currentPath);\n const [path, hash] = href.split("#");\n const targetPath = path || currentPath;\n perfStart("nav:fetchData:" + href);\n const pageData = await fetchPageDataForNavigation(targetPath, signal);\n perfEnd("nav:fetchData:" + href);\n if (signal.aborted) return;\n if (pageData && pageData.redirect && typeof pageData.redirect.destination === "string") {\n const redirectUrl = resolveDocumentNavigationUrl(\n pageData.redirect.destination,\n window.location.origin\n );\n if (redirectUrl) {\n log("SPA navigation redirect -> " + redirectUrl);\n window.location.href = redirectUrl;\n return;\n }\n }\n if (historyMode === "push") {\n window.history.pushState({ pageData, scrollY: 0 }, "", href);\n } else if (historyMode === "replace") {\n window.history.replaceState({ pageData, scrollY: 0 }, "", href);\n }\n currentPath = targetPath;\n router.pathname = targetPath;\n router.query = Object.fromEntries(new URLSearchParams(window.location.search));\n router.params = flattenRouteParams(pageData.params);\n perfStart("nav:render:" + href);\n await renderPageFromData(pageData, targetPath);\n perfEnd("nav:render:" + href);\n if (restoreScroll) {\n restoreScrollPosition(targetPath);\n } else if (hash) {\n requestAnimationFrame(() => {\n const target = document2.getElementById(hash);\n if (target) {\n target.scrollIntoView({ behavior: "smooth" });\n return;\n }\n window.scrollTo(0, 0);\n });\n } else {\n window.scrollTo(0, 0);\n }\n hideNavigationProgress();\n perfEnd("nav:total:" + href);\n emitRouteTiming("total", targetPath, navigationStartedAt, {\n href,\n historyMode,\n restoreScroll\n });\n log("SPA navigation complete");\n } catch (error) {\n hideNavigationProgress();\n if (error.name === "AbortError") {\n log("Navigation aborted");\n return;\n }\n logError("SPA navigation failed:", error.message);\n if (error.status === 404) {\n logError("Page not found:", href);\n }\n navigateDocument(href);\n } finally {\n isNavigating = false;\n currentAbortController = null;\n processPageDataPrefetchQueue();\n }\n }\n async function loadPageDataComponent(pageData, path, options = {}) {\n if (!pageData.isolatedClientPage) return loadComponent(path, pageData, options);\n const moduleUrl = buildPinnedRscModuleUrl(path, pageData);\n const module = await snapshotModules2.importSnapshotBoundModule(\n moduleUrl,\n options.allowDocumentReload !== false\n );\n return module.MDXLayout || module.MainLayout || module.default || module;\n }\n async function renderPageFromData(pageData, targetPath) {\n if (pageData.requiresFullDocumentNavigation) {\n throw new Error("Server layout requires full document navigation");\n }\n if (window.__veryfrontSetReleaseId) {\n window.__veryfrontSetReleaseId(pageData.releaseId || null);\n }\n if (window.__veryfrontSetReleaseAssetModules) {\n window.__veryfrontSetReleaseAssetModules(pageData.releaseAssetModules || null);\n }\n perfStart("render:loadAll");\n const allPaths = getPageDataModulePaths(pageData);\n const modulesStartedAt = routeTimingNow();\n const components = await Promise.all(\n allPaths.map((path) => loadPageDataComponent(pageData, path))\n );\n emitRouteTiming("modules", targetPath, modulesStartedAt, { count: allPaths.length });\n perfEnd("render:loadAll");\n const [PageComponent, ...rest] = components;\n const ErrorComponent = pageData.errorPath ? rest.pop() : null;\n const AppComponent = pageData.appPath ? rest.pop() : null;\n const LayoutComponents = rest;\n if (!PageComponent) {\n throw new Error("Failed to load page component: " + pageData.pagePath);\n }\n handoffClientRouteMetadata(\n pageData.frontmatter ?? {},\n document2\n );\n if (pageData.css) {\n const existingStyle = document2.getElementById("veryfront-spa-css");\n if (existingStyle) {\n existingStyle.textContent = pageData.css;\n } else {\n const styleEl = document2.createElement("style");\n const nonce = getDocumentNonce(document2);\n if (nonce) styleEl.setAttribute("nonce", nonce);\n styleEl.id = "veryfront-spa-css";\n styleEl.textContent = pageData.css;\n document2.head.appendChild(styleEl);\n }\n log("Injected CSS for SPA navigation", { cssLength: pageData.css.length });\n } else if (pageData.cssAction === "clear") {\n const existingStyle = document2.getElementById("veryfront-spa-css");\n if (existingStyle) {\n existingStyle.remove();\n log("Cleared SPA CSS for release stylesheet navigation");\n }\n }\n const normalizedParams = flattenRouteParams(pageData.params);\n let tree = React2.createElement(PageComponent, {\n ...pageData.props,\n params: normalizedParams\n });\n if (pageData.layouts?.length) {\n for (let i = pageData.layouts.length - 1; i >= 0; i--) {\n const layout = pageData.layouts[i];\n const LayoutComponent = LayoutComponents[i];\n if (!LayoutComponent || !layout) continue;\n const layoutProps = pageData.layoutProps?.[layout.path] || {};\n tree = React2.createElement(LayoutComponent, { ...layoutProps, children: tree });\n }\n }\n if (AppComponent) {\n tree = React2.createElement(AppComponent, { children: tree });\n log("Wrapped with App component for SPA navigation");\n }\n if (ErrorComponent) {\n class AppRouterErrorBoundary extends React2.Component {\n constructor(props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n static getDerivedStateFromError(error) {\n return { hasError: true, error };\n }\n render() {\n if (this.state.hasError) {\n return React2.createElement(ErrorComponent, {\n error: this.state.error,\n reset: () => this.setState({ hasError: false, error: null })\n });\n }\n return this.props.children;\n }\n }\n tree = React2.createElement(AppRouterErrorBoundary, null, tree);\n }\n const headingsArray = pageData.headings || [];\n const pageContext = {\n slug: pageData.slug || "",\n path: pageData.pagePath || targetPath,\n params: normalizedParams,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n frontmatter: pageData.frontmatter || {},\n data: pageData.props || {},\n headings: headingsArray,\n mdxHeadings: headingsArray\n };\n tree = React2.createElement(PageContextProvider2, { pageContext, children: tree });\n tree = React2.createElement(RouterProvider2, { router, children: tree });\n const container = pageData.isolatedClientPage ? document2.getElementById("veryfront-page-island") : document2.getElementById("root");\n if (!hydrationCompleted && !hydrationFailed) {\n log("Waiting for hydration to complete before SPA render...");\n try {\n await Promise.race([\n hydrationPromise,\n new Promise(\n (_, reject) => setTimeout2(() => reject(new Error("Hydration timeout")), 1e4)\n )\n ]);\n } catch (waitError) {\n log("Hydration wait failed:", waitError.message);\n }\n }\n if (container?.__reactRoot) {\n perfStart("render:reactRender");\n container.__reactRoot.render(tree);\n perfEnd("render:reactRender");\n log("Page re-rendered via SPA");\n scheduleRoutePrefetchRefresh();\n return;\n }\n if (hydrationFailed) {\n throw new Error(\n "React root not found - hydration failed, falling back to full page navigation"\n );\n }\n throw new Error("React root not found");\n }\n let prefetchTimeout = null;\n let currentHoverLink = null;\n let routePrefetchRefreshPending = false;\n let viewportPrefetchObserver = null;\n const observedPrefetchLinks = /* @__PURE__ */ new WeakSet();\n const prefetchedPaths = /* @__PURE__ */ new Set();\n const inFlightPrefetches = /* @__PURE__ */ new Set();\n const queuedPrefetchPaths = /* @__PURE__ */ new Set();\n const pageDataPrefetchQueue = [];\n const activePageDataPrefetchControllers = /* @__PURE__ */ new Map();\n function cancelScheduledPrefetch() {\n if (prefetchTimeout) {\n clearTimeout2(prefetchTimeout);\n prefetchTimeout = null;\n }\n currentHoverLink = null;\n }\n function getPageDataModulePaths(pageData) {\n const layoutPaths = (pageData.layouts || []).map((l) => l.path).filter(Boolean);\n const allPaths = [pageData.pagePath, ...layoutPaths].filter(Boolean);\n if (pageData.appPath) allPaths.push(pageData.appPath);\n if (pageData.errorPath) allPaths.push(pageData.errorPath);\n return allPaths;\n }\n function getCurrentRouteHref() {\n return window.location.pathname + window.location.search;\n }\n function getInternalRouteHrefFromLink(link) {\n if (!link || link.target === "_blank" || link.hasAttribute("download") || link.getAttribute("data-prefetch") === "false") {\n return null;\n }\n const href = link.getAttribute("href");\n if (!href || href.startsWith("#") || href.startsWith("//") || !href.startsWith("/")) {\n return null;\n }\n try {\n const url = new URL(href, window.location.origin);\n if (url.origin !== window.location.origin) return null;\n const routeHref = url.pathname + url.search;\n return routeHref === getCurrentRouteHref() ? null : routeHref;\n } catch (_) {\n return null;\n }\n }\n function getEligiblePrefetchLinks(limit) {\n const links = [];\n const seenHrefs = /* @__PURE__ */ new Set();\n for (const link of document2.querySelectorAll("a[href]")) {\n const href = getInternalRouteHrefFromLink(link);\n if (!href || seenHrefs.has(href)) continue;\n seenHrefs.add(href);\n links.push({ link, href });\n if (links.length >= limit) break;\n }\n return links;\n }\n async function preloadModulesForPageData(pageData, path) {\n if (!pageData || pageData.requiresFullDocumentNavigation) return;\n if (pageData.releaseId && window.__veryfrontSetReleaseId) {\n window.__veryfrontSetReleaseId(pageData.releaseId);\n }\n if (pageData.releaseAssetModules && window.__veryfrontSetReleaseAssetModules) {\n window.__veryfrontSetReleaseAssetModules(pageData.releaseAssetModules);\n }\n const modulePaths = getPageDataModulePaths(pageData);\n if (modulePaths.length === 0) return;\n try {\n await Promise.all(\n modulePaths.map(\n (modulePath) => loadPageDataComponent(pageData, modulePath, { allowDocumentReload: false })\n )\n );\n } catch (error) {\n if (isDependencySnapshotConflict(error)) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n pageDataCache.delete(cacheIdentity);\n backgroundRefreshTimestamps.delete(cacheIdentity);\n prefetchedPaths.delete(path);\n throw error;\n }\n logBackgroundFetchFailure("Module prefetch", path, error);\n }\n }\n function removeQueuedPrefetch(path) {\n queuedPrefetchPaths.delete(path);\n for (let i = pageDataPrefetchQueue.length - 1; i >= 0; i--) {\n if (pageDataPrefetchQueue[i] === path) pageDataPrefetchQueue.splice(i, 1);\n }\n }\n function abortActiveSpeculativePrefetches() {\n for (const controller of activePageDataPrefetchControllers.values()) {\n controller.abort();\n }\n }\n function processPageDataPrefetchQueue() {\n if (isNavigating) return;\n while (activePageDataPrefetchControllers.size < PAGE_DATA_PREFETCH_CONCURRENCY && pageDataPrefetchQueue.length > 0) {\n const href = pageDataPrefetchQueue.shift();\n queuedPrefetchPaths.delete(href);\n if (prefetchedPaths.has(href) || inFlightPrefetches.has(href) || getCachedPageData(href)) {\n continue;\n }\n if (prefetchedPaths.size >= MAX_PREFETCH_PATHS) {\n const oldest = prefetchedPaths.values().next().value;\n if (oldest) prefetchedPaths.delete(oldest);\n }\n const controller = new AbortController();\n prefetchedPaths.add(href);\n inFlightPrefetches.add(href);\n activePageDataPrefetchControllers.set(href, controller);\n fetchPageDataForPrefetch(href, controller.signal).catch((error) => {\n prefetchedPaths.delete(href);\n if (isDependencySnapshotConflict(error)) {\n logBackgroundFetchFailure("Module prefetch", href, error);\n }\n }).finally(() => {\n inFlightPrefetches.delete(href);\n activePageDataPrefetchControllers.delete(href);\n processPageDataPrefetchQueue();\n });\n }\n }\n function prefetchPage(href) {\n if (isNavigating) return;\n if (prefetchedPaths.has(href) || inFlightPrefetches.has(href) || queuedPrefetchPaths.has(href)) return;\n const cachedPageData = getCachedPageData(href);\n if (cachedPageData) {\n preloadModulesForPageData(cachedPageData, href).catch((error) => {\n logBackgroundFetchFailure("Module prefetch", href, error);\n });\n return;\n }\n queuedPrefetchPaths.add(href);\n pageDataPrefetchQueue.push(href);\n processPageDataPrefetchQueue();\n }\n function prefetchEligibleRouteLinks(limit) {\n for (const { href } of getEligiblePrefetchLinks(limit)) {\n prefetchPage(href);\n }\n }\n function ensureViewportPrefetchObserver() {\n if (viewportPrefetchObserver || typeof IntersectionObserver !== "function") {\n return viewportPrefetchObserver;\n }\n viewportPrefetchObserver = new IntersectionObserver((entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n viewportPrefetchObserver?.unobserve(entry.target);\n const href = getInternalRouteHrefFromLink(\n entry.target\n );\n if (href) prefetchPage(href);\n }\n }, { rootMargin: VIEWPORT_PREFETCH_ROOT_MARGIN });\n return viewportPrefetchObserver;\n }\n function observeViewportPrefetchLinks() {\n const observer = ensureViewportPrefetchObserver();\n if (!observer) return;\n for (const { link } of getEligiblePrefetchLinks(VIEWPORT_PREFETCH_MAX_LINKS)) {\n if (observedPrefetchLinks.has(link)) continue;\n observedPrefetchLinks.add(link);\n observer.observe(link);\n }\n }\n function runRoutePrefetchRefresh() {\n routePrefetchRefreshPending = false;\n prefetchEligibleRouteLinks(IDLE_PREFETCH_MAX_LINKS);\n observeViewportPrefetchLinks();\n }\n function scheduleRoutePrefetchRefresh() {\n if (routePrefetchRefreshPending) return;\n routePrefetchRefreshPending = true;\n setTimeout2(() => {\n if (typeof requestIdleCallback === "function") {\n requestIdleCallback(runRoutePrefetchRefresh, { timeout: IDLE_PREFETCH_DELAY_MS });\n return;\n }\n runRoutePrefetchRefresh();\n }, IDLE_PREFETCH_DELAY_MS);\n }\n const router = {\n domain: window.location.origin,\n path: window.location.pathname,\n push: (path) => {\n void navigateSPA(path, "push");\n },\n replace: (path) => {\n void navigateSPA(path, "replace");\n },\n back: () => {\n window.history.back();\n },\n forward: () => {\n window.history.forward();\n },\n prefetch: (path) => {\n prefetchPage(path);\n },\n pathname: window.location.pathname,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n // Seed route params from the hydration data (issue #2741). Catch-all\n // segments arrive as arrays and are joined so no path info is lost.\n params: flattenRouteParams(deps.initialHydrationData.params || {}),\n isPreview: false,\n isMounted: true,\n navigate: (path) => navigateSPA(path, "push"),\n reload: () => window.location.reload()\n };\n window.__veryfrontRouter = router;\n if (deps.navigationStoreUsesRegistryFallback) {\n log("Router runtime does not export getNavigationStore; using shared v1 registry fallback");\n }\n if (typeof deps.getNavigationStore === "function") {\n deps.getNavigationStore().setNavigator((href, options) => {\n const mode = options && options.history;\n const historyMode = mode === "replace" ? "replace" : mode === "none" ? "none" : "push";\n return navigateSPA(href, historyMode);\n });\n }\n window.addEventListener("popstate", async (e) => {\n const path = window.location.pathname;\n log("Popstate:", path);\n saveScrollPosition(currentPath);\n if (!e.state?.pageData) {\n await navigateSPA(path, "none", true);\n return;\n }\n showNavigationProgress();\n try {\n currentPath = path;\n router.pathname = path;\n router.query = Object.fromEntries(new URLSearchParams(window.location.search));\n router.params = flattenRouteParams(e.state.pageData.params);\n await renderPageFromData(e.state.pageData, path);\n restoreScrollPosition(path);\n hideNavigationProgress();\n } catch (error) {\n hideNavigationProgress();\n logError("Popstate render failed:", error.message);\n window.location.reload();\n }\n });\n document2.addEventListener("click", (e) => {\n const link = e.target?.closest("a[href]");\n if (!link) return;\n const href = link.getAttribute("href");\n if (!href) return;\n if (href.startsWith("#")) {\n const target = document2.getElementById(href.slice(1));\n if (!target) return;\n e.preventDefault();\n target.scrollIntoView({ behavior: "smooth" });\n window.history.pushState(null, "", href);\n return;\n }\n if (link.target === "_blank" || link.hasAttribute("download") || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || !href.startsWith("/") || href.startsWith("//")) {\n return;\n }\n e.preventDefault();\n cancelScheduledPrefetch();\n void navigateSPA(href, "push");\n });\n document2.addEventListener(\n "mouseenter",\n (e) => {\n if (!e.target || typeof e.target.closest !== "function") return;\n const link = e.target.closest("a[href]");\n if (!link) return;\n const href = getInternalRouteHrefFromLink(link);\n if (!href) return;\n if (currentHoverLink === link) return;\n if (prefetchTimeout) {\n clearTimeout2(prefetchTimeout);\n prefetchTimeout = null;\n }\n currentHoverLink = link;\n prefetchTimeout = setTimeout2(() => {\n prefetchPage(href);\n prefetchTimeout = null;\n }, PREFETCH_DELAY_MS);\n },\n true\n );\n document2.addEventListener(\n "mouseleave",\n (e) => {\n if (!e.target || typeof e.target.closest !== "function") return;\n const relatedTarget = e.relatedTarget;\n if (currentHoverLink && relatedTarget && currentHoverLink.contains(relatedTarget)) return;\n cancelScheduledPrefetch();\n },\n true\n );\n if (document2.readyState === "loading") {\n document2.addEventListener("DOMContentLoaded", scheduleRoutePrefetchRefresh, { once: true });\n } else {\n scheduleRoutePrefetchRefresh();\n }\n window.useRouter = () => {\n try {\n return env2.useRouterFromModule();\n } catch (_) {\n return window.__veryfrontRouter;\n }\n };\n return {\n router,\n navigateSPA,\n renderPageFromData,\n prefetchPage,\n signalHydrationComplete,\n signalHydrationFailed\n };\n}\n\n// src/html/hydration-script-builder/runtime/renderer.ts\nfunction isModuleNotFoundError(error) {\n if (!error) return false;\n if (error instanceof SyntaxError) return false;\n const message = String(error.message || error);\n return /(?:dynamically imported module|Importing a module script failed|Failed to load module script)/i.test(message);\n}\nfunction preferReachedModuleError(earlier, later) {\n if (!earlier) return later;\n if (!later) return earlier;\n if (isModuleNotFoundError(earlier) && !isModuleNotFoundError(later)) return later;\n return earlier;\n}\nasync function loadPageModuleWithIndexFallback(basePath, pageSlug, pageModuleError, importModule) {\n try {\n return await importModule(basePath + ".js");\n } catch (error) {\n const routeError = preferReachedModuleError(pageModuleError, error);\n if (pageSlug === "index" || pageSlug.endsWith("/index")) throw routeError;\n try {\n return await importModule(basePath + "/index.js");\n } catch (indexError) {\n throw preferReachedModuleError(routeError, indexError);\n }\n }\n}\nfunction isAppRouterPath(path, appRouterRoot) {\n const normalizedPath = typeof path === "string" ? path.replace(/^\\/+/, "") : "";\n return normalizedPath === appRouterRoot || normalizedPath.startsWith(appRouterRoot + "/");\n}\nfunction isRootAppLayoutPath(path, appRouterRoot) {\n const normalizedPath = typeof path === "string" ? path.replace(/^\\/+/, "") : "";\n const pathWithoutExtension = normalizedPath.replace(/\\.(?:tsx|jsx|ts|js)$/, "");\n return pathWithoutExtension === appRouterRoot + "/layout";\n}\nfunction unwrapAppRouterDocumentLayout(LayoutComponent, React2) {\n return function AppRouterDocumentLayout(props) {\n const element = LayoutComponent(props);\n const asElement = element;\n if (!React2.isValidElement(element) || asElement.type !== "html") {\n return element;\n }\n const body = React2.Children.toArray(asElement.props?.children).find(\n (child) => React2.isValidElement(child) && child.type === "body"\n );\n return body?.props?.children ?? props.children;\n };\n}\nfunction createHydrationRenderer(deps) {\n const { env: env2, logging: logging2, componentLoader: componentLoader2, snapshotModules: snapshotModules2, moduleServerUrl: moduleServerUrl2 } = deps;\n const { window, document: document2, React: React2, RouterProvider: RouterProvider2, PageContextProvider: PageContextProvider2 } = env2;\n const { DEBUG, log, logError } = logging2;\n const { loadComponent, pathToModuleUrl } = componentLoader2;\n const { importSnapshotBoundModule } = snapshotModules2;\n async function renderPage(pathname) {\n const resolvedPathname = (() => {\n const input = typeof pathname === "string" ? pathname : window.location.pathname;\n try {\n return new URL(input, window.location.origin).pathname || "/";\n } catch (_) {\n const [pathOnly] = String(input || "/").split(/[?#]/);\n return pathOnly || "/";\n }\n })();\n const dataScript = findServerHydrationDataElement(document2);\n if (!dataScript) {\n logError("Hydration data not found");\n return;\n }\n let data = {};\n try {\n data = JSON.parse(dataScript.textContent || "{}");\n } catch (parseError) {\n logError("Failed to parse hydration data:", parseError);\n return;\n }\n log("Hydration data:", data);\n if (data.studioEmbed && window.__veryfrontSetStudioEmbed) {\n window.__veryfrontSetStudioEmbed(true);\n }\n if (window.__veryfrontSetReleaseId) {\n window.__veryfrontSetReleaseId(data.releaseId || null);\n }\n if (data.releaseAssetModules && window.__veryfrontSetReleaseAssetModules) {\n window.__veryfrontSetReleaseAssetModules(data.releaseAssetModules);\n }\n try {\n let pageModule;\n const pagePath = typeof data.pagePath === "string" ? data.pagePath : "";\n const normalizedPagePath = pagePath.replace(/^\\/+/, "");\n const normalizedAppRouterRoot = typeof data.appRouterRoot === "string" && data.appRouterRoot.replace(/^\\/+|\\/+$/g, "") ? data.appRouterRoot.replace(/^\\/+|\\/+$/g, "") : "app";\n const hasReleaseAssetModules = data.releaseAssetModules && Object.keys(data.releaseAssetModules).length > 0;\n const shouldRenderRscClientPage = data.clientModuleStrategy === "rsc-module" && !hasReleaseAssetModules && isAppRouterPath(normalizedPagePath, normalizedAppRouterRoot);\n const isolatedClientPage = data.isolatedClientPage === true;\n const loadHydrationComponent = async (path, preferRscModule) => {\n const normalizedPath = typeof path === "string" ? path.replace(/^\\/+/, "") : "";\n if (preferRscModule && isAppRouterPath(normalizedPath, normalizedAppRouterRoot)) {\n const moduleUrl = buildPinnedRscModuleUrl(path, data);\n log("Loading App Router component from RSC module:", moduleUrl);\n const module = await importSnapshotBoundModule(moduleUrl);\n return module.default || module;\n }\n return loadComponent(path, data);\n };\n let pageModuleError = null;\n if (data.pagePath) {\n const moduleUrl = shouldRenderRscClientPage ? buildPinnedRscModuleUrl(data.pagePath, data) : pathToModuleUrl(data.pagePath, data.studioEmbed, data);\n log("Loading page from hydration data:", moduleUrl);\n try {\n pageModule = await importSnapshotBoundModule(moduleUrl);\n } catch (error) {\n pageModuleError = error;\n logError("Failed to load page from hydration data:", error);\n }\n }\n if (!pageModule) {\n const pageSlug = resolvedPathname === "/" ? "index" : resolvedPathname.slice(1);\n log("Falling back to Pages Router pattern:", pageSlug);\n const prefix = pageSlug.startsWith("@/") ? "" : "/pages";\n const basePath = moduleServerUrl2 + prefix + "/" + pageSlug;\n pageModule = await loadPageModuleWithIndexFallback(\n basePath,\n pageSlug,\n pageModuleError,\n (moduleUrl) => importSnapshotBoundModule(appendDependencyPinningVersion(moduleUrl, data))\n );\n }\n if (!pageModule) {\n logError("Page module failed to load");\n return;\n }\n const PageComponent = pageModule.default || pageModule;\n if (!PageComponent) {\n logError("Page component not found");\n return;\n }\n const normalizedParams = flattenRouteParams(data.params);\n const pageProps = { ...data.props || {}, params: normalizedParams };\n let tree = React2.createElement(PageComponent, pageProps);\n const layouts = data.layouts;\n if (layouts?.length) {\n for (let i = layouts.length - 1; i >= 0; i--) {\n const layout = layouts[i];\n if (!layout) continue;\n const LayoutComponent = await loadHydrationComponent(\n layout.path,\n shouldRenderRscClientPage\n );\n if (LayoutComponent) {\n const WrappedLayoutComponent = shouldRenderRscClientPage && isRootAppLayoutPath(layout.path, normalizedAppRouterRoot) ? unwrapAppRouterDocumentLayout(LayoutComponent, React2) : LayoutComponent;\n const layoutProps = data.layoutProps?.[layout.path] || {};\n tree = React2.createElement(\n WrappedLayoutComponent,\n { ...layoutProps, children: tree }\n );\n }\n }\n }\n if (data.appPath && !isolatedClientPage) {\n const AppComponent = await loadHydrationComponent(data.appPath, shouldRenderRscClientPage);\n if (AppComponent) {\n tree = React2.createElement(AppComponent, { children: tree });\n }\n }\n if (data.errorPath) {\n const ErrorComponent = await loadHydrationComponent(\n data.errorPath,\n shouldRenderRscClientPage\n );\n if (ErrorComponent) {\n class AppRouterErrorBoundary extends React2.Component {\n constructor(props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n static getDerivedStateFromError(error) {\n return { hasError: true, error };\n }\n render() {\n if (this.state.hasError) {\n return React2.createElement(ErrorComponent, {\n error: this.state.error,\n reset: () => this.setState({ hasError: false, error: null })\n });\n }\n return this.props.children;\n }\n }\n tree = React2.createElement(AppRouterErrorBoundary, null, tree);\n }\n }\n const headings = data.headings || [];\n const pageContext = {\n slug: data.slug || "",\n path: data.pagePath || resolvedPathname,\n params: normalizedParams,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n frontmatter: data.frontmatter || {},\n data: data.props || {},\n headings,\n mdxHeadings: headings\n // Alias for backwards compatibility\n };\n tree = React2.createElement(PageContextProvider2, { pageContext, children: tree });\n tree = React2.createElement(RouterProvider2, { router: deps.router, children: tree });\n const container = isolatedClientPage ? document2.getElementById("veryfront-page-island") : document2.getElementById("root");\n if (!container) {\n if (isolatedClientPage) {\n throw new Error("Isolated client page root not found");\n }\n return;\n }\n if (container.__reactRoot) {\n container.__reactRoot.render(tree);\n log("Page re-rendered");\n return;\n }\n if (shouldRenderRscClientPage) {\n container.__reactRoot = env2.createRoot(container);\n container.__reactRoot.render(tree);\n log("Client-side React app rendered successfully");\n } else {\n const { hydrateRoot } = await import("react-dom/client");\n const options = {\n identifierPrefix: "vf",\n onRecoverableError: (error) => {\n if (data.dev && DEBUG) {\n log("Hydration mismatch (suppressed):", error.message);\n }\n }\n };\n container.__reactRoot = hydrateRoot(container, tree, options);\n log("Client-side React app hydrated successfully");\n }\n if (window.__veryfrontHydrationComplete) {\n window.__veryfrontHydrationComplete();\n }\n } catch (error) {\n logError("Client initialization error:", error);\n if (window.__veryfrontHydrationFailed) {\n window.__veryfrontHydrationFailed(error);\n }\n }\n }\n function start() {\n window.__veryfrontRenderPage = renderPage;\n void renderPage(window.location.pathname);\n const initialDataScript = findServerHydrationDataElement(document2);\n if (initialDataScript) {\n try {\n const pageData = JSON.parse(initialDataScript.textContent || "{}");\n if (pageData.pagePath) {\n window.history.replaceState({ pageData, scrollY: 0 }, "", window.location.href);\n log("Stored initial page data in history state");\n }\n } catch (_) {\n }\n }\n }\n return { renderPage, start };\n}\n\n// src/html/hydration-script-builder/runtime/navigation-store.ts\nvar NAVIGATION_STORE_REGISTRY_KEY = "veryfront.navigation.store.v1";\nfunction resolveNavigationStore(RouterRuntime2) {\n const usesRegistryFallback2 = typeof RouterRuntime2.getNavigationStore !== "function";\n if (!usesRegistryFallback2) {\n return {\n usesRegistryFallback: usesRegistryFallback2,\n getNavigationStore: RouterRuntime2.getNavigationStore\n };\n }\n return {\n usesRegistryFallback: usesRegistryFallback2,\n getNavigationStore: () => {\n const storeKey = Symbol.for(NAVIGATION_STORE_REGISTRY_KEY);\n const registry = globalThis;\n const existing = registry[storeKey];\n if (existing) return existing;\n const listeners = /* @__PURE__ */ new Set();\n let navigator = null;\n const store = {\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getHref() {\n const loc = globalThis.location;\n return loc ? loc.pathname + loc.search + loc.hash : "/";\n },\n notify() {\n for (const listener of [...listeners]) {\n try {\n listener();\n } catch {\n }\n }\n },\n navigate(href, options) {\n if (navigator) return navigator(href, options);\n globalThis.location?.assign(href);\n return Promise.resolve();\n },\n setNavigator(next) {\n navigator = next;\n }\n };\n registry[storeKey] = store;\n return store;\n }\n };\n}\n\n// src/html/hydration-script-builder/runtime/main.ts\nvar runtimeWindow = globalThis;\nvar runtimeDocument = globalThis.document;\nvar env = {\n window: runtimeWindow,\n document: runtimeDocument,\n fetch: (url, init) => fetch(url, init),\n React,\n RouterProvider,\n PageContextProvider,\n createRoot: (container) => createRoot(container),\n importModule: (moduleUrl) => import(moduleUrl),\n useRouterFromModule,\n setTimeout: (handler, timeout) => setTimeout(handler, timeout),\n clearTimeout: (id) => clearTimeout(id)\n};\nvar logging = createLogging(runtimeWindow);\nvar initialHydrationData = readInitialHydrationData(runtimeDocument);\nvar documentDependencyPinningCacheKey = readDocumentDependencyPinningCacheKey(\n initialHydrationData\n);\nvar routeTiming = createRouteTimingRecorder(runtimeWindow, logging);\nvar snapshotModules = createSnapshotModuleImporter({\n importModule: env.importModule,\n fetchModule: env.fetch,\n reloadDocument: () => runtimeWindow.location.reload(),\n recoveryState: runtimeWindow\n});\nvar componentLoader = createComponentLoader({\n window: runtimeWindow,\n logging,\n moduleServerUrl: moduleServerUrl(runtimeWindow),\n snapshotModules\n});\nruntimeWindow.__veryfrontClearComponentCache = componentLoader.clearComponentCache;\nruntimeWindow.__veryfrontSetStudioEmbed = componentLoader.setStudioEmbed;\nruntimeWindow.__veryfrontSetReleaseId = componentLoader.setReleaseId;\nruntimeWindow.__veryfrontSetReleaseAssetModules = componentLoader.setReleaseAssetModules;\nruntimeWindow.__veryfrontSetHMRRefreshTimestamp = componentLoader.setHMRRefreshTimestamp;\nvar { usesRegistryFallback, getNavigationStore } = resolveNavigationStore(RouterRuntime);\nvar routerRuntime = createRouterRuntime({\n env,\n logging,\n routeTiming,\n componentLoader,\n snapshotModules,\n initialHydrationData,\n documentDependencyPinningCacheKey,\n getNavigationStore,\n navigationStoreUsesRegistryFallback: usesRegistryFallback\n});\ncreateHydrationRenderer({\n env,\n logging,\n componentLoader,\n snapshotModules,\n moduleServerUrl: moduleServerUrl(runtimeWindow),\n router: routerRuntime.router\n}).start();\n';
9
+ export const HYDRATION_RUNTIME_BUNDLE = '// src/html/hydration-script-builder/runtime/main.ts\nimport * as React from "react";\nimport { createRoot } from "react-dom/client";\nimport { RouterProvider, useRouter as useRouterFromModule } from "veryfront/router";\nimport * as RouterRuntime from "veryfront/router";\nimport { PageContextProvider } from "veryfront/context";\n\n// src/routing/flatten-route-params.ts\nfunction flattenRouteParams(params) {\n if (!params) return {};\n const flat = {};\n for (const [key, value] of Object.entries(params)) {\n if (value === void 0) continue;\n flat[key] = Array.isArray(value) ? value.join("/") : value;\n }\n return flat;\n}\n\n// src/html/hydration-script-builder/runtime/shared.ts\nfunction moduleServerUrl(window) {\n return window.location.origin + "/_vf_modules";\n}\nfunction createLogging(window) {\n const DEBUG = Boolean(\n window.__VERYFRONT_DEBUG__ || new URLSearchParams(window.location.search).has("vf_debug")\n );\n const log = DEBUG ? console.log.bind(console, "[Veryfront]") : () => {\n };\n const logError = console.error.bind(console, "[Veryfront]");\n function logBackgroundFetchFailure(reason, path, error) {\n const message = error?.message ?? String(error);\n log(reason + " failed:", path, message);\n }\n const perfTimers = /* @__PURE__ */ new Map();\n const perfStart = DEBUG ? (label) => {\n perfTimers.set(label, performance.now());\n } : () => {\n };\n const perfEnd = DEBUG ? (label) => {\n const start = perfTimers.get(label);\n if (start === void 0) return 0;\n const duration = performance.now() - start;\n perfTimers.delete(label);\n console.log(\n "[Veryfront Perf] %c" + label + ": %c" + duration.toFixed(2) + "ms",\n "color: #888",\n duration > 100 ? "color: #f00; font-weight: bold" : "color: #0a0"\n );\n return duration;\n } : () => 0;\n return { DEBUG, log, logError, logBackgroundFetchFailure, perfStart, perfEnd };\n}\nfunction isAbortError(error) {\n return error?.name === "AbortError";\n}\nfunction resolveDocumentNavigationUrl(target, origin) {\n try {\n const url = new URL(target, origin);\n if (url.protocol === "http:" || url.protocol === "https:") return url.href;\n } catch (_) {\n }\n return null;\n}\nfunction getDocumentNonce(document2) {\n const element = document2.querySelector("script[nonce], style[nonce], link[nonce]");\n if (!element) return void 0;\n return element.nonce || element.getAttribute("nonce") || void 0;\n}\n\n// src/html/hydration-data-element.ts\nvar HYDRATION_DATA_ELEMENT_ID = "veryfront-hydration-data";\nfunction findServerHydrationDataElement(document2) {\n try {\n const matches = [...document2.querySelectorAll(`[id="${HYDRATION_DATA_ELEMENT_ID}"]`)];\n if (matches.length !== 1) return null;\n const body = document2.body;\n if (!body) return null;\n const element = matches[0];\n if (body.firstElementChild !== element && element.parentElement !== body) return null;\n if (element.tagName?.toLowerCase() !== "script") return null;\n if (element.getAttribute("type")?.trim().toLowerCase() !== "application/json") return null;\n return element;\n } catch {\n return null;\n }\n}\n\n// src/html/hydration-script-builder/runtime/hydration-data.ts\nfunction readInitialHydrationData(document2) {\n try {\n const element = findServerHydrationDataElement(document2);\n return JSON.parse(element && element.textContent ? element.textContent : "{}") || {};\n } catch (_) {\n return {};\n }\n}\nfunction readDocumentDependencyPinningCacheKey(initialHydrationData2) {\n return typeof initialHydrationData2.dependencyPinningCacheKey === "string" && initialHydrationData2.dependencyPinningCacheKey.startsWith("on:") ? initialHydrationData2.dependencyPinningCacheKey : null;\n}\n\n// src/html/hydration-script-builder/runtime/snapshot-modules.ts\nvar RECOVERY_STATE_KEY = "__VF_DEPENDENCY_SNAPSHOT_RECOVERY_STARTED__";\nasync function isDependencySnapshotConflictResponse(response) {\n if (!response || response.status !== 409) return false;\n try {\n const clone = response.clone?.() ?? response;\n const body = (await clone.text?.() ?? "").trim();\n return body === "Unknown dependency snapshot" || body === "export default null; // Unknown dependency snapshot";\n } catch (_) {\n return false;\n }\n}\nfunction createSnapshotModuleImporter(deps) {\n async function recoverFromSnapshotBoundModuleFailure(moduleUrl, allowDocumentReload = true) {\n try {\n const parsedUrl = new URL(moduleUrl, "http://veryfront.local");\n const snapshotKeys = parsedUrl.searchParams.getAll("pins");\n const pathMatch = parsedUrl.pathname.match(\n /^\\/_vf_modules\\/_pins\\/([^/]+)(?:\\/|$)/\n );\n if (pathMatch) {\n try {\n snapshotKeys.push(decodeURIComponent(pathMatch[1]));\n } catch (_) {\n return false;\n }\n }\n if (snapshotKeys.length !== 1 || !/^on:[A-Za-z0-9._-]+$/.test(snapshotKeys[0])) return false;\n const response = await deps.fetchModule(moduleUrl, { cache: "no-store" });\n if (!await isDependencySnapshotConflictResponse(response)) return false;\n if (!allowDocumentReload) return true;\n if (deps.recoveryState[RECOVERY_STATE_KEY] === true) return true;\n deps.recoveryState[RECOVERY_STATE_KEY] = true;\n try {\n deps.reloadDocument();\n } catch (_) {\n delete deps.recoveryState[RECOVERY_STATE_KEY];\n return false;\n }\n return true;\n } catch (_) {\n return false;\n }\n }\n async function importSnapshotBoundModule(moduleUrl, allowDocumentReload = true) {\n try {\n return await deps.importModule(moduleUrl);\n } catch (error) {\n const snapshotConflict = await recoverFromSnapshotBoundModuleFailure(\n moduleUrl,\n allowDocumentReload\n );\n if (snapshotConflict && !allowDocumentReload) {\n const conflictError = new Error(\n "Dependency snapshot is unavailable during speculative module prefetch"\n );\n conflictError.name = "DependencySnapshotConflictError";\n conflictError.dependencySnapshotConflict = true;\n conflictError.cause = error;\n throw conflictError;\n }\n throw error;\n }\n }\n return { importSnapshotBoundModule, recoverFromSnapshotBoundModuleFailure };\n}\nfunction isDependencySnapshotConflict(error) {\n return Boolean(error?.dependencySnapshotConflict);\n}\n\n// src/utils/version-constant.ts\nvar VERSION = "0.1.1199";\n\n// src/html/hydration-script-builder/runtime/module-urls.ts\nfunction appendQueryParam(url, key, value) {\n return url + (url.includes("?") ? "&" : "?") + key + "=" + value;\n}\nfunction appendDependencyPinningVersion(url, moduleData) {\n const pinKey = moduleData && moduleData.dependencyPinningCacheKey;\n if (typeof pinKey !== "string" || !pinKey.startsWith("on:")) return url;\n const hashIndex = url.indexOf("#");\n const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";\n const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;\n const queryIndex = withoutHash.indexOf("?");\n const base = queryIndex >= 0 ? withoutHash.slice(0, queryIndex) : withoutHash;\n const params = new URLSearchParams(queryIndex >= 0 ? withoutHash.slice(queryIndex + 1) : "");\n const modulePrefix = "/_vf_modules/";\n const prefixIndex = base.indexOf(modulePrefix);\n const origin = prefixIndex >= 0 ? base.slice(0, prefixIndex) : "";\n if (prefixIndex >= 0 && (origin === "" || /^https?:\\/\\/[^/]+$/i.test(origin))) {\n const pathStart = prefixIndex + modulePrefix.length;\n let modulePath = base.slice(pathStart);\n if (modulePath.startsWith("_pins/")) {\n const existingKeyEnd = modulePath.indexOf("/", "_pins/".length);\n const encodedExistingKey = existingKeyEnd < 0 ? modulePath.slice("_pins/".length) : modulePath.slice("_pins/".length, existingKeyEnd);\n let existingKey;\n try {\n existingKey = decodeURIComponent(encodedExistingKey);\n } catch {\n existingKey = void 0;\n }\n if (existingKey && /^on:[A-Za-z0-9._-]+$/.test(existingKey)) {\n if (existingKeyEnd < 0) return url;\n modulePath = modulePath.slice(existingKeyEnd + 1);\n }\n }\n params.delete("pins");\n const query = params.toString();\n return base.slice(0, pathStart) + "_pins/" + encodeURIComponent(pinKey) + "/" + modulePath + (query ? "?" + query : "") + hash;\n }\n params.set("pins", pinKey);\n return base + "?" + params.toString() + hash;\n}\nfunction componentCacheKey(path, moduleData) {\n const pinKey = moduleData && moduleData.dependencyPinningCacheKey;\n return typeof pinKey === "string" && pinKey.startsWith("on:") ? path + "|vf_pins|" + pinKey : path;\n}\nfunction normalizeReleaseAssetModulePath(path) {\n return String(path || "").replace(/^\\/?_vf_modules\\//, "").replace(/^\\/+/, "").replace(/[?#].*$/, "");\n}\nfunction buildPinnedRscModuleUrl(path, moduleData) {\n let moduleUrl = "/_veryfront/rsc/module?rel=" + encodeURIComponent(path);\n const pinKey = moduleData && moduleData.dependencyPinningCacheKey;\n if (typeof pinKey === "string" && pinKey.startsWith("on:")) {\n moduleUrl += "&pins=" + encodeURIComponent(pinKey);\n }\n return moduleUrl;\n}\nfunction buildPageDataEndpoint(path, origin) {\n const targetUrl = new URL(path, origin);\n const normalizedPath = targetUrl.pathname === "/" ? "" : targetUrl.pathname.replace(/^\\//, "");\n const endpointUrl = new URL(\n "/_veryfront/page-data/" + normalizedPath + ".json",\n origin\n );\n endpointUrl.search = targetUrl.search;\n return endpointUrl.pathname + endpointUrl.search;\n}\nfunction pageDataCacheIdentity(path, documentDependencyPinningCacheKey2) {\n return documentDependencyPinningCacheKey2 ? documentDependencyPinningCacheKey2 + "|path:" + path : path;\n}\nfunction assertPageDataMatchesDocumentSnapshot(path, data, documentDependencyPinningCacheKey2) {\n if (!documentDependencyPinningCacheKey2) return data;\n if (data && data.dependencyPinningCacheKey === documentDependencyPinningCacheKey2) {\n return data;\n }\n const error = new Error("Page data dependency snapshot does not match the document");\n error.status = 409;\n error.dependencySnapshotMismatch = true;\n error.path = path;\n throw error;\n}\n\n// src/html/hydration-script-builder/runtime/component-loader.ts\nvar VERYFRONT_RUNTIME_VERSION = VERSION;\nfunction createComponentLoader(deps) {\n const { window, moduleServerUrl: moduleServerUrl2 } = deps;\n const { DEBUG, log, logError } = deps.logging;\n const componentCache = /* @__PURE__ */ new Map();\n const loadingPromises = /* @__PURE__ */ new Map();\n let releaseId = null;\n let releaseAssetModules = null;\n let studioEmbed = false;\n let hmrRefreshTimestamp = null;\n function clearComponentCache(path) {\n if (!path) {\n componentCache.clear();\n loadingPromises.clear();\n log("Cleared all component caches");\n return;\n }\n for (const key of componentCache.keys()) {\n if (key === path || key.startsWith(path + "|vf_pins|")) {\n componentCache.delete(key);\n }\n }\n for (const key of loadingPromises.keys()) {\n if (key === path || key.startsWith(path + "|vf_pins|")) {\n loadingPromises.delete(key);\n }\n }\n log("Cleared component cache for:", path);\n }\n function setReleaseId(value) {\n releaseId = typeof value === "string" && value ? value : null;\n window.__veryfrontReleaseId = releaseId;\n }\n function appendReleaseModuleVersion(url) {\n if (!releaseId || url.includes("vf_release=")) return url;\n let versionedUrl = appendQueryParam(url, "vf_release", encodeURIComponent(releaseId));\n versionedUrl = appendQueryParam(\n versionedUrl,\n "vf_runtime",\n encodeURIComponent(VERYFRONT_RUNTIME_VERSION)\n );\n return versionedUrl;\n }\n function setReleaseAssetModules(value) {\n releaseAssetModules = value && typeof value === "object" && !Array.isArray(value) ? value : null;\n window.__veryfrontReleaseAssetModules = releaseAssetModules;\n }\n function resolveReleaseAssetModuleUrl(path) {\n if (!releaseAssetModules || studioEmbed || hmrRefreshTimestamp) return null;\n const key = normalizeReleaseAssetModulePath(path);\n if (releaseAssetModules[key]) return releaseAssetModules[key];\n const withoutExt = key.replace(/\\.(tsx|ts|jsx|mdx|js|mjs)$/, "");\n const extensions = [".tsx", ".ts", ".jsx", ".mdx", ".js"];\n for (const ext of extensions) {\n const candidate = withoutExt + ext;\n if (releaseAssetModules[candidate]) return releaseAssetModules[candidate];\n }\n return null;\n }\n function pathToModuleUrl(path, embedInStudio, moduleData) {\n const releaseAssetUrl = resolveReleaseAssetModuleUrl(path);\n if (releaseAssetUrl) return releaseAssetUrl;\n const pattern = /(pages|components|app|lib|layouts|shared|features)\\/(.+)\\.(tsx|ts|jsx|mdx)$/;\n const match = path.match(new RegExp("/" + pattern.source)) || path.match(new RegExp("^" + pattern.source));\n let url;\n if (match) {\n url = moduleServerUrl2 + "/" + match[1] + "/" + match[2] + ".js";\n } else {\n const hasKnownExt = /\\.(tsx|ts|jsx|mdx|js|mjs)$/.test(path);\n url = moduleServerUrl2 + "/" + (hasKnownExt ? path.replace(/\\.(tsx|ts|jsx|mdx)$/, ".js") : path + ".js");\n }\n if (embedInStudio) url = appendQueryParam(url, "studio_embed", "true");\n if (hmrRefreshTimestamp) url = appendQueryParam(url, "t", hmrRefreshTimestamp);\n if (!embedInStudio && !hmrRefreshTimestamp) url = appendReleaseModuleVersion(url);\n url = appendDependencyPinningVersion(url, moduleData);\n return url;\n }\n function setStudioEmbed(value) {\n studioEmbed = value;\n window.__veryfrontStudioEmbed = value;\n }\n function setHMRRefreshTimestamp(timestamp) {\n hmrRefreshTimestamp = timestamp;\n window.__veryfrontHMRRefreshTimestamp = timestamp;\n }\n async function loadComponent(path, moduleData, options = {}) {\n if (!path) return null;\n const cacheKey = componentCacheKey(path, moduleData);\n if (componentCache.has(cacheKey)) {\n log("Component cached:", path);\n return componentCache.get(cacheKey);\n }\n const existingPromise = loadingPromises.get(cacheKey);\n if (existingPromise) return existingPromise;\n const loadPromise = (async () => {\n try {\n const moduleUrl = pathToModuleUrl(path, studioEmbed, moduleData);\n const start = DEBUG ? performance.now() : 0;\n log("Loading component:", moduleUrl);\n const module = await deps.snapshotModules.importSnapshotBoundModule(\n moduleUrl,\n options.allowDocumentReload !== false\n );\n const component = module.MDXLayout || module.MainLayout || module.default || module;\n if (DEBUG) {\n const duration = performance.now() - start;\n console.log(\n "[Veryfront Perf] %cimport:" + path.split("/").pop() + ": %c" + duration.toFixed(2) + "ms",\n "color: #888",\n duration > 50 ? "color: #f00; font-weight: bold" : "color: #0a0"\n );\n }\n componentCache.set(cacheKey, component);\n return component;\n } catch (error) {\n if (isDependencySnapshotConflict(error)) throw error;\n logError("Failed to load component:", path, error);\n return null;\n } finally {\n loadingPromises.delete(cacheKey);\n }\n })();\n loadingPromises.set(cacheKey, loadPromise);\n return loadPromise;\n }\n return {\n loadComponent,\n pathToModuleUrl,\n clearComponentCache,\n setStudioEmbed,\n setReleaseId,\n setReleaseAssetModules,\n setHMRRefreshTimestamp\n };\n}\n\n// src/html/hydration-script-builder/runtime/route-timing.ts\nvar MAX_ROUTE_TIMINGS = 100;\nvar MAX_SERVER_TIMING_LENGTH = 1024;\nfunction routeTimingNow() {\n return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();\n}\nfunction sanitizeServerTimingMetricName(name) {\n return String(name || "").trim().replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 128);\n}\nfunction sanitizeServerTimingHeader(value) {\n if (!value) return null;\n const metrics = [];\n const printable = String(value).replace(/[^\\x20-\\x7E]/g, " ").trim();\n if (!printable) return null;\n for (const item of printable.split(",")) {\n const segments = item.split(";").map((segment) => segment.trim()).filter(Boolean);\n const name = sanitizeServerTimingMetricName(segments[0]);\n if (!name) continue;\n for (const segment of segments.slice(1)) {\n const [key, rawValue = ""] = segment.split("=");\n if ((key ?? "").trim().toLowerCase() !== "dur") continue;\n const duration = Number(rawValue.trim().replace(/^"|"$/g, ""));\n if (!Number.isFinite(duration) || duration < 0) continue;\n metrics.push(name + ";dur=" + (Math.round(duration * 100) / 100).toFixed(2));\n break;\n }\n }\n const sanitized = metrics.join(", ");\n return sanitized ? sanitized.slice(0, MAX_SERVER_TIMING_LENGTH) : null;\n}\nfunction parseServerTimingMetrics(value) {\n const header = sanitizeServerTimingHeader(value);\n if (!header) return null;\n const metrics = {};\n for (const item of header.split(",")) {\n const segments = item.split(";").map((segment) => segment.trim()).filter(Boolean);\n const name = sanitizeServerTimingMetricName(segments[0]);\n if (!name) continue;\n for (const segment of segments.slice(1)) {\n const [key, rawValue = ""] = segment.split("=");\n if ((key ?? "").trim().toLowerCase() !== "dur") continue;\n const duration = Number(rawValue.trim().replace(/^"|"$/g, ""));\n if (Number.isFinite(duration) && duration >= 0) {\n metrics[name] = Math.round(duration * 100) / 100;\n }\n }\n }\n return Object.keys(metrics).length ? metrics : null;\n}\nfunction readResponseServerTiming(response) {\n try {\n return sanitizeServerTimingHeader(response.headers?.get("server-timing"));\n } catch (_) {\n return null;\n }\n}\nfunction roundRouteTimingValue(value) {\n return Math.round(value * 100) / 100;\n}\nfunction extractResourceTiming(entry) {\n const fields = [\n "startTime",\n "requestStart",\n "responseStart",\n "responseEnd",\n "duration",\n "transferSize",\n "encodedBodySize",\n "decodedBodySize"\n ];\n const timing = {};\n for (const field of fields) {\n const value = entry?.[field];\n if (typeof value === "number" && Number.isFinite(value) && value >= 0) {\n timing[field] = roundRouteTimingValue(value);\n }\n }\n return Object.keys(timing).length ? timing : null;\n}\nfunction createRouteTimingRecorder(window, logging2) {\n const { log } = logging2;\n function emitRouteTiming(phase, path, startedAt, detail = {}) {\n const entry = {\n phase,\n path,\n duration: Math.max(0, routeTimingNow() - startedAt),\n timestamp: Date.now(),\n ...detail\n };\n const timings = Array.isArray(window.__veryfrontRouteTimings) ? window.__veryfrontRouteTimings : [];\n timings.push(entry);\n if (timings.length > MAX_ROUTE_TIMINGS) {\n timings.splice(0, timings.length - MAX_ROUTE_TIMINGS);\n }\n window.__veryfrontRouteTimings = timings;\n try {\n window.dispatchEvent(new CustomEvent("veryfront:route-timing", { detail: entry }));\n } catch (_) {\n }\n log("Route timing:", entry);\n return entry;\n }\n function getPageDataResourceTiming(endpoint, fetchStartedAt) {\n try {\n if (typeof performance === "undefined" || typeof performance.getEntriesByName !== "function") {\n return null;\n }\n const href = new URL(endpoint, window.location.href).href;\n const entries = performance.getEntriesByName(href, "resource");\n if (!entries.length) return null;\n for (let index = entries.length - 1; index >= 0; index--) {\n const entry = entries[index];\n const responseEnd = entry?.responseEnd;\n if (typeof responseEnd === "number" && Number.isFinite(responseEnd) && responseEnd + 1 >= fetchStartedAt) {\n return extractResourceTiming(entry);\n }\n }\n return null;\n } catch (_) {\n return null;\n }\n }\n function buildPageDataTimingDetail(response, endpoint, fetchStartedAt, source) {\n const detail = { source, status: response.status };\n const serverTiming = readResponseServerTiming(response);\n if (serverTiming) {\n detail.serverTiming = serverTiming;\n const serverTimingMetrics = parseServerTimingMetrics(serverTiming);\n if (serverTimingMetrics) detail.serverTimingMetrics = serverTimingMetrics;\n }\n const resourceTiming = getPageDataResourceTiming(response.url || endpoint, fetchStartedAt);\n if (resourceTiming) detail.resourceTiming = resourceTiming;\n return detail;\n }\n return { emitRouteTiming, buildPageDataTimingDetail };\n}\n\n// src/html/managed-head-protocol.ts\nvar HEAD_PROVENANCE_ATTRIBUTE = "data-vf-head";\nvar HEAD_LEGACY_MANAGED_ATTRIBUTE = "data-veryfront-managed";\nvar HEAD_CONTENT_HASH_ATTRIBUTE = "data-vf-hash";\nvar HEAD_REACT_MANAGED_ATTRIBUTE = "data-vf-react-head";\nvar HEAD_REACT_OWNER_ATTRIBUTE = "data-vf-react-head-owner";\nvar HEAD_ROUTE_MANAGED_ATTRIBUTE = "data-vf-route-head";\nvar HEAD_SERVER_COMMIT_ATTRIBUTE = "data-vf-server-head-commit";\nvar HEAD_SHELL_PROVENANCE_ATTRIBUTE = "data-vf-shell-head";\nvar HEAD_SSR_PAYLOAD_ATTRIBUTE = "data-vf-ssr-head";\nvar MAX_MANAGED_HEAD_BYTES = 2 * 1024 * 1024;\nvar MAX_MANAGED_HEAD_PAYLOAD_BYTES = MAX_MANAGED_HEAD_BYTES * 2;\nvar SINGLETON_META_KEYS = /* @__PURE__ */ new Set([\n "description",\n "robots",\n "viewport",\n "referrer",\n "color-scheme",\n "application-name",\n "generator",\n "og:title",\n "og:description",\n "og:url",\n "og:type",\n "og:site_name",\n "og:locale",\n "twitter:card",\n "twitter:site",\n "twitter:creator",\n "twitter:title",\n "twitter:description",\n "twitter:image",\n "twitter:image:alt"\n]);\nvar SINGLETON_LINK_RELS = /* @__PURE__ */ new Set([\n "canonical",\n "manifest",\n "amphtml"\n]);\nvar MAX_HEAD_ATTRIBUTE_VALUE_BYTES = 64 * 1024;\nvar MAX_HEAD_ATTRIBUTE_BYTES = 1024 * 1024;\nvar MAX_HEAD_CONTENT_BYTES = 1024 * 1024;\nvar headTextEncoder = new TextEncoder();\nvar BOOLEAN_HEAD_ATTRIBUTES = /* @__PURE__ */ new Set([\n "async",\n "defer",\n "disabled",\n "itemscope",\n "nomodule"\n]);\nfunction isHeadFrameworkAttribute(name) {\n switch (name.toLowerCase()) {\n case HEAD_PROVENANCE_ATTRIBUTE:\n case HEAD_LEGACY_MANAGED_ATTRIBUTE:\n case HEAD_CONTENT_HASH_ATTRIBUTE:\n case HEAD_REACT_MANAGED_ATTRIBUTE:\n case HEAD_REACT_OWNER_ATTRIBUTE:\n case HEAD_ROUTE_MANAGED_ATTRIBUTE:\n case HEAD_SERVER_COMMIT_ATTRIBUTE:\n case HEAD_SHELL_PROVENANCE_ATTRIBUTE:\n case HEAD_SSR_PAYLOAD_ATTRIBUTE:\n return true;\n default:\n return false;\n }\n}\nfunction normalizeHeadIdentityValue(value) {\n const normalized = value?.trim().toLowerCase();\n return normalized || void 0;\n}\nfunction readOwnString(record, key) {\n try {\n const descriptor = Reflect.getOwnPropertyDescriptor(record, key);\n return descriptor && !descriptor.get && !descriptor.set && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;\n } catch {\n return void 0;\n }\n}\nfunction headMetaSingletonKeyFromRecord(meta) {\n if (readOwnString(meta, "charset") !== void 0) return "meta:charset";\n const key = normalizeHeadIdentityValue(\n readOwnString(meta, "property") ?? readOwnString(meta, "name")\n );\n if (!key) return void 0;\n if (key === "theme-color") {\n return `meta:theme-color:${readOwnString(meta, "media")?.trim() ?? ""}`;\n }\n return SINGLETON_META_KEYS.has(key) ? `meta:${key}` : void 0;\n}\nfunction headLinkSingletonKeyFromRecord(link) {\n const rel = normalizeHeadIdentityValue(readOwnString(link, "rel"));\n return rel && SINGLETON_LINK_RELS.has(rel) ? `link:${rel}` : void 0;\n}\n\n// src/html/client-head-manager.ts\nvar HEAD_MANAGER_STATE_SYMBOL = /* @__PURE__ */ Symbol.for(\n "veryfront.client-head-manager.v2"\n);\nvar CROSS_PAGE_PRESERVED_SINGLETON_KEYS = /* @__PURE__ */ new Set([\n "meta:viewport",\n "link:manifest"\n]);\nfunction getClientHeadManagerState() {\n const globalState = globalThis;\n return globalState[HEAD_MANAGER_STATE_SYMBOL] ?? (globalState[HEAD_MANAGER_STATE_SYMBOL] = {\n documents: /* @__PURE__ */ new WeakMap()\n });\n}\nfunction readElementAttributes(element) {\n const attributes = [];\n for (const attribute of element.attributes) {\n const name = attribute.name.toLowerCase();\n if (isHeadFrameworkAttribute(name)) continue;\n const nonce = name === "nonce" && "nonce" in element ? element.nonce : "";\n const value = BOOLEAN_HEAD_ATTRIBUTES.has(name) ? "" : nonce || attribute.value;\n attributes.push([name, value]);\n }\n return attributes.sort(([left], [right]) => left.localeCompare(right));\n}\nfunction elementSingletonKey(element) {\n const tagName = element.tagName.toLowerCase();\n if (tagName === "title") return "title";\n const attributes = Object.fromEntries(readElementAttributes(element));\n if (tagName === "meta") return headMetaSingletonKeyFromRecord(attributes);\n if (tagName === "link") return headLinkSingletonKeyFromRecord(attributes);\n return void 0;\n}\nfunction promoteToShellHeadBaseline(element) {\n for (const attribute of [...element.attributes]) {\n if (isHeadFrameworkAttribute(attribute.name)) {\n element.removeAttribute(attribute.name);\n }\n }\n element.setAttribute(HEAD_SHELL_PROVENANCE_ATTRIBUTE, "true");\n}\nfunction isCrossPagePreservedSingleton(element, singletonKey = elementSingletonKey(element)) {\n return element.parentElement !== null && singletonKey !== void 0 && CROSS_PAGE_PRESERVED_SINGLETON_KEYS.has(singletonKey);\n}\nfunction isFrameworkOwnedHeadElement(element) {\n return element.getAttribute(HEAD_PROVENANCE_ATTRIBUTE) === "true" || element.getAttribute(HEAD_REACT_MANAGED_ATTRIBUTE) === "true" || element.getAttribute(HEAD_LEGACY_MANAGED_ATTRIBUTE) === "1" || element.getAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE) === "true" || element.getAttribute(HEAD_SHELL_PROVENANCE_ATTRIBUTE) === "true";\n}\nfunction retireFrameworkHeadElement(element) {\n if (isCrossPagePreservedSingleton(element)) {\n promoteToShellHeadBaseline(element);\n return;\n }\n element.remove();\n}\nfunction retireClientHeadOwnership(targetDocument) {\n const manager = getClientHeadManagerState().documents.get(targetDocument);\n if (manager) {\n manager.retire();\n return;\n }\n for (const element of [...targetDocument.head?.children ?? []]) {\n if (isFrameworkOwnedHeadElement(element)) retireFrameworkHeadElement(element);\n }\n}\n\n// src/html/client-route-head.ts\nfunction updateRouteTitle(title, targetDocument = document) {\n if (typeof title !== "string" || !title) return;\n const titles = [...targetDocument.head.querySelectorAll("title")];\n if (titles.some((element) => element.getAttribute(HEAD_LEGACY_MANAGED_ATTRIBUTE) === "1")) {\n return;\n }\n let titleElement = titles.find(\n (element) => element.getAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE) === "true"\n );\n for (const element of titles) {\n if (element !== titleElement) element.remove();\n }\n if (!titleElement) {\n titleElement = targetDocument.createElement("title");\n titleElement.setAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE, "true");\n targetDocument.head.appendChild(titleElement);\n }\n titleElement.textContent = title;\n}\nfunction updateRouteMetaTag(targetDocument, selector, attributeName, attributeValue, content) {\n const matches = [...targetDocument.head.querySelectorAll(selector)];\n if (matches.some((element) => element.getAttribute(HEAD_LEGACY_MANAGED_ATTRIBUTE) === "1")) {\n return;\n }\n let metaTag = matches.find(\n (element) => element.getAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE) === "true"\n );\n if (!metaTag) {\n metaTag = targetDocument.createElement("meta");\n metaTag.setAttribute(attributeName, attributeValue);\n metaTag.setAttribute(HEAD_ROUTE_MANAGED_ATTRIBUTE, "true");\n targetDocument.head.appendChild(metaTag);\n }\n metaTag.setAttribute("content", content);\n}\nfunction updateRouteMetaTags(metadata, targetDocument = document) {\n if (typeof metadata.description === "string" && metadata.description) {\n updateRouteMetaTag(\n targetDocument,\n \'meta[name="description"]\',\n "name",\n "description",\n metadata.description\n );\n }\n if (typeof metadata.ogTitle === "string" && metadata.ogTitle) {\n updateRouteMetaTag(\n targetDocument,\n \'meta[property="og:title"]\',\n "property",\n "og:title",\n metadata.ogTitle\n );\n }\n}\nfunction handoffClientRouteMetadata(metadata, targetDocument = document) {\n const retainedTitle = targetDocument.title;\n retireClientHeadOwnership(targetDocument);\n updateRouteTitle(\n typeof metadata.title === "string" && metadata.title ? metadata.title : retainedTitle,\n targetDocument\n );\n updateRouteMetaTags(metadata, targetDocument);\n}\n\n// src/html/hydration-script-builder/runtime/router.ts\nvar FETCH_TIMEOUT_MS = 1e4;\nvar MAX_RETRIES = 2;\nvar MAX_CACHE_SIZE = 50;\nvar CACHE_TTL_MS = 5 * 60 * 1e3;\nvar BACKGROUND_REFRESH_INTERVAL_MS = 30 * 1e3;\nvar PREFETCH_DELAY_MS = 100;\nvar MAX_PREFETCH_PATHS = 100;\nvar IDLE_PREFETCH_DELAY_MS = 1200;\nvar IDLE_PREFETCH_MAX_LINKS = 4;\nvar VIEWPORT_PREFETCH_MAX_LINKS = 8;\nvar PAGE_DATA_PREFETCH_CONCURRENCY = 2;\nvar VIEWPORT_PREFETCH_ROOT_MARGIN = "200px";\nvar MAX_SCROLL_POSITIONS = 100;\nfunction createRouterRuntime(deps) {\n const { env: env2, logging: logging2, routeTiming: routeTiming2, componentLoader: componentLoader2, snapshotModules: snapshotModules2 } = deps;\n const { window, document: document2, React: React2, RouterProvider: RouterProvider2, PageContextProvider: PageContextProvider2 } = env2;\n const { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = env2;\n const { log, logError, logBackgroundFetchFailure, perfStart, perfEnd } = logging2;\n const { emitRouteTiming, buildPageDataTimingDetail } = routeTiming2;\n const { loadComponent } = componentLoader2;\n const documentPinKey = deps.documentDependencyPinningCacheKey;\n let hydrationResolve;\n let hydrationReject;\n const hydrationPromise = new Promise((resolve, reject) => {\n hydrationResolve = resolve;\n hydrationReject = reject;\n });\n let hydrationCompleted = false;\n let hydrationFailed = false;\n function signalHydrationComplete() {\n hydrationCompleted = true;\n hydrationResolve();\n log("Hydration complete signal received");\n }\n function signalHydrationFailed(error) {\n hydrationFailed = true;\n hydrationReject(error);\n logError("Hydration failed signal received:", error);\n }\n window.__veryfrontHydrationComplete = signalHydrationComplete;\n window.__veryfrontHydrationFailed = signalHydrationFailed;\n function pageDataCacheIdentity2(path) {\n return pageDataCacheIdentity(path, documentPinKey);\n }\n function navigateDocument(target) {\n const safeUrl = resolveDocumentNavigationUrl(target, window.location.origin);\n if (safeUrl) {\n window.location.href = safeUrl;\n return;\n }\n logError("Refusing an unsafe document navigation:", target);\n window.location.reload();\n }\n let clientBuildVersion = null;\n function checkVersionMismatch(newVersion) {\n if (!clientBuildVersion) {\n clientBuildVersion = newVersion;\n log("Build version initialized:", newVersion);\n return false;\n }\n if (newVersion.serverStart !== clientBuildVersion.serverStart) {\n log("Server restarted, reloading...", {\n old: clientBuildVersion.serverStart,\n new: newVersion.serverStart\n });\n return true;\n }\n if (newVersion.framework !== clientBuildVersion.framework) {\n log("Framework version changed, reloading...", {\n old: clientBuildVersion.framework,\n new: newVersion.framework\n });\n return true;\n }\n if (newVersion.projectUpdated && clientBuildVersion.projectUpdated && newVersion.projectUpdated !== clientBuildVersion.projectUpdated) {\n log("Project content updated, reloading...", {\n old: clientBuildVersion.projectUpdated,\n new: newVersion.projectUpdated\n });\n return true;\n }\n return false;\n }\n const pageDataCache = /* @__PURE__ */ new Map();\n const pendingPageDataFetches = /* @__PURE__ */ new Map();\n const backgroundRefreshTimestamps = /* @__PURE__ */ new Map();\n function getCachedPageData(path) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n const entry = pageDataCache.get(cacheIdentity);\n if (!entry) return null;\n if (Date.now() - entry.timestamp < CACHE_TTL_MS) return entry.data;\n pageDataCache.delete(cacheIdentity);\n backgroundRefreshTimestamps.delete(cacheIdentity);\n return null;\n }\n function setCachedPageData(path, data) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n if (pageDataCache.size >= MAX_CACHE_SIZE) {\n const oldest = pageDataCache.keys().next().value;\n if (oldest) {\n pageDataCache.delete(oldest);\n backgroundRefreshTimestamps.delete(oldest);\n }\n }\n pageDataCache.set(cacheIdentity, { data, timestamp: Date.now() });\n }\n const scrollPositions = /* @__PURE__ */ new Map();\n function saveScrollPosition(path) {\n if (scrollPositions.size >= MAX_SCROLL_POSITIONS) {\n const oldest = scrollPositions.keys().next().value;\n if (oldest) scrollPositions.delete(oldest);\n }\n scrollPositions.set(path, window.scrollY);\n }\n function restoreScrollPosition(path) {\n const savedY = scrollPositions.get(path);\n if (savedY === void 0) return false;\n requestAnimationFrame(() => window.scrollTo(0, savedY));\n return true;\n }\n let progressBar = null;\n let progressTimeout = null;\n function showNavigationProgress() {\n if (!progressBar) {\n progressBar = document2.createElement("div");\n progressBar.id = "vf-nav-progress";\n progressBar.style.cssText = "position:fixed;top:0;left:0;height:3px;width:0;background:linear-gradient(90deg,#0066ff,#00aaff);z-index:99999;transition:width 0.3s ease-out,opacity 0.2s;opacity:1;";\n document2.body.prepend(progressBar);\n }\n progressBar.style.opacity = "1";\n progressBar.style.width = "30%";\n progressTimeout = setTimeout2(() => {\n if (progressBar?.style) progressBar.style.width = "70%";\n }, 300);\n document2.body.setAttribute("aria-busy", "true");\n }\n function hideNavigationProgress() {\n if (progressTimeout) {\n clearTimeout2(progressTimeout);\n progressTimeout = null;\n }\n if (progressBar) {\n progressBar.style.width = "100%";\n setTimeout2(() => {\n if (!progressBar) return;\n progressBar.style.opacity = "0";\n setTimeout2(() => {\n if (progressBar) progressBar.style.width = "0";\n }, 200);\n }, 150);\n }\n document2.body.removeAttribute("aria-busy");\n }\n let currentAbortController = null;\n function sleep(ms) {\n return new Promise((resolve) => setTimeout2(resolve, ms));\n }\n async function fetchWithRetry(url, options, maxRetries = MAX_RETRIES) {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const controller = new AbortController();\n const callerSignal = options.signal;\n const abortFromCaller = () => controller.abort();\n if (callerSignal?.aborted) controller.abort();\n callerSignal?.addEventListener("abort", abortFromCaller, { once: true });\n const timeout = setTimeout2(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await env2.fetch(url, { ...options, signal: controller.signal });\n clearTimeout2(timeout);\n callerSignal?.removeEventListener("abort", abortFromCaller);\n if (response.ok) return response;\n if (response.status >= 500 && attempt < maxRetries) {\n log("Server error, retrying...", response.status);\n await sleep(Math.pow(2, attempt) * 500);\n continue;\n }\n return response;\n } catch (error) {\n clearTimeout2(timeout);\n callerSignal?.removeEventListener("abort", abortFromCaller);\n if (error.name === "AbortError" && callerSignal?.aborted) throw error;\n if (attempt === maxRetries) throw error;\n log("Fetch failed, retrying...", error.message);\n await sleep(Math.pow(2, attempt) * 500);\n }\n }\n throw new Error("Failed to fetch page data");\n }\n async function fetchPageDataFresh(path, signal, options = {}) {\n const {\n triggerReloadOnVersionMismatch = false,\n recordRouteTiming = false,\n timingSource = "network"\n } = options;\n const endpoint = buildPageDataEndpoint(path, window.location.origin);\n const startedAt = recordRouteTiming ? routeTimingNow() : 0;\n log("Fetching page data:", path);\n perfStart("fetch:" + path);\n const headers = options.prefetch ? { "X-Veryfront-Prefetch": "1" } : { "X-Veryfront-Navigation": "spa" };\n if (documentPinKey) {\n headers["X-Veryfront-Dependency-Pins"] = documentPinKey;\n }\n const response = await fetchWithRetry(endpoint, {\n headers,\n signal\n }, options.prefetch ? 0 : MAX_RETRIES);\n if (!response.ok) {\n perfEnd("fetch:" + path);\n if (recordRouteTiming) {\n emitRouteTiming(\n "page-data",\n path,\n startedAt,\n buildPageDataTimingDetail(response, endpoint, startedAt, timingSource)\n );\n }\n const error = new Error("Failed to fetch page data: " + response.status);\n error.status = response.status;\n throw error;\n }\n perfStart("parse:" + path);\n const data = assertPageDataMatchesDocumentSnapshot(\n path,\n await response.json(),\n documentPinKey\n );\n perfEnd("parse:" + path);\n perfEnd("fetch:" + path);\n if (recordRouteTiming) {\n emitRouteTiming(\n "page-data",\n path,\n startedAt,\n buildPageDataTimingDetail(response, endpoint, startedAt, timingSource)\n );\n }\n if (triggerReloadOnVersionMismatch) {\n const checkedData = handlePageDataVersionMismatch(path, data);\n if (checkedData !== data) return checkedData;\n }\n setCachedPageData(path, data);\n return data;\n }\n function handlePageDataVersionMismatch(path, data) {\n if (data.buildVersion && checkVersionMismatch(data.buildVersion)) {\n log("Version mismatch detected, performing full page reload to:", path);\n navigateDocument(path);\n return new Promise(() => {\n });\n }\n return data;\n }\n function startPageDataFetch(path, signal, options = {}) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n const request = fetchPageDataFresh(path, signal, options).finally(() => {\n if (options.trackPending !== false && pendingPageDataFetches.get(cacheIdentity) === request) {\n pendingPageDataFetches.delete(cacheIdentity);\n }\n });\n if (options.trackPending !== false) {\n pendingPageDataFetches.set(cacheIdentity, request);\n }\n return request;\n }\n function fetchPageDataDeduped(path) {\n const pending = pendingPageDataFetches.get(pageDataCacheIdentity2(path));\n if (pending) return pending;\n return startPageDataFetch(path, null);\n }\n function refreshPageDataInBackground(path) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n const lastRefreshAt = backgroundRefreshTimestamps.get(cacheIdentity) || 0;\n const now = Date.now();\n if (now - lastRefreshAt < BACKGROUND_REFRESH_INTERVAL_MS) return;\n backgroundRefreshTimestamps.set(cacheIdentity, now);\n fetchPageDataDeduped(path).catch((error) => {\n logBackgroundFetchFailure("Stale page data refresh", path, error);\n });\n }\n async function fetchPageDataForNavigation(path, signal) {\n const startedAt = routeTimingNow();\n const cached = getCachedPageData(path);\n if (cached) {\n log("Using cached page data:", path);\n refreshPageDataInBackground(path);\n emitRouteTiming("page-data", path, startedAt, { source: "cache" });\n return cached;\n }\n const pending = pendingPageDataFetches.get(pageDataCacheIdentity2(path));\n if (pending) {\n log("Reusing pending page data fetch for navigation:", path);\n const data = await pending;\n emitRouteTiming("page-data", path, startedAt, { source: "deduped" });\n return handlePageDataVersionMismatch(path, data);\n }\n return startPageDataFetch(path, signal, {\n triggerReloadOnVersionMismatch: true,\n recordRouteTiming: true,\n timingSource: "network"\n });\n }\n function fetchPageDataForPrefetch(path, signal) {\n if (getCachedPageData(path)) return Promise.resolve();\n return startPageDataFetch(path, signal, { prefetch: true, trackPending: false }).then((data) => preloadModulesForPageData(data, path)).catch((error) => {\n if (!isAbortError(error)) {\n logBackgroundFetchFailure("Page data prefetch", path, error);\n }\n throw error;\n });\n }\n let currentPath = window.location.pathname;\n let isNavigating = false;\n async function navigateSPA(href, historyMode = "push", restoreScroll = false) {\n currentAbortController?.abort();\n if (isNavigating) return;\n isNavigating = true;\n const [navigationPath] = href.split("#");\n removeQueuedPrefetch(navigationPath || href);\n abortActiveSpeculativePrefetches();\n currentAbortController = new AbortController();\n const signal = currentAbortController.signal;\n const navigationStartedAt = routeTimingNow();\n showNavigationProgress();\n perfStart("nav:total:" + href);\n try {\n log("SPA navigating to:", href);\n saveScrollPosition(currentPath);\n const [path, hash] = href.split("#");\n const targetPath = path || currentPath;\n perfStart("nav:fetchData:" + href);\n const pageData = await fetchPageDataForNavigation(targetPath, signal);\n perfEnd("nav:fetchData:" + href);\n if (signal.aborted) return;\n if (pageData && pageData.redirect && typeof pageData.redirect.destination === "string") {\n const redirectUrl = resolveDocumentNavigationUrl(\n pageData.redirect.destination,\n window.location.origin\n );\n if (redirectUrl) {\n log("SPA navigation redirect -> " + redirectUrl);\n window.location.href = redirectUrl;\n return;\n }\n }\n if (historyMode === "push") {\n window.history.pushState({ pageData, scrollY: 0 }, "", href);\n } else if (historyMode === "replace") {\n window.history.replaceState({ pageData, scrollY: 0 }, "", href);\n }\n currentPath = targetPath;\n router.pathname = targetPath;\n router.query = Object.fromEntries(new URLSearchParams(window.location.search));\n router.params = flattenRouteParams(pageData.params);\n perfStart("nav:render:" + href);\n await renderPageFromData(pageData, targetPath);\n perfEnd("nav:render:" + href);\n if (restoreScroll) {\n restoreScrollPosition(targetPath);\n } else if (hash) {\n requestAnimationFrame(() => {\n const target = document2.getElementById(hash);\n if (target) {\n target.scrollIntoView({ behavior: "smooth" });\n return;\n }\n window.scrollTo(0, 0);\n });\n } else {\n window.scrollTo(0, 0);\n }\n hideNavigationProgress();\n perfEnd("nav:total:" + href);\n emitRouteTiming("total", targetPath, navigationStartedAt, {\n href,\n historyMode,\n restoreScroll\n });\n log("SPA navigation complete");\n } catch (error) {\n hideNavigationProgress();\n if (error.name === "AbortError") {\n log("Navigation aborted");\n return;\n }\n logError("SPA navigation failed:", error.message);\n if (error.status === 404) {\n logError("Page not found:", href);\n }\n navigateDocument(href);\n } finally {\n isNavigating = false;\n currentAbortController = null;\n processPageDataPrefetchQueue();\n }\n }\n async function loadPageDataComponent(pageData, path, options = {}) {\n if (!pageData.isolatedClientPage) return loadComponent(path, pageData, options);\n const moduleUrl = buildPinnedRscModuleUrl(path, pageData);\n const module = await snapshotModules2.importSnapshotBoundModule(\n moduleUrl,\n options.allowDocumentReload !== false\n );\n return module.MDXLayout || module.MainLayout || module.default || module;\n }\n async function renderPageFromData(pageData, targetPath) {\n if (pageData.requiresFullDocumentNavigation) {\n throw new Error("Server layout requires full document navigation");\n }\n if (window.__veryfrontSetReleaseId) {\n window.__veryfrontSetReleaseId(pageData.releaseId || null);\n }\n if (window.__veryfrontSetReleaseAssetModules) {\n window.__veryfrontSetReleaseAssetModules(pageData.releaseAssetModules || null);\n }\n perfStart("render:loadAll");\n const allPaths = getPageDataModulePaths(pageData);\n const modulesStartedAt = routeTimingNow();\n const components = await Promise.all(\n allPaths.map((path) => loadPageDataComponent(pageData, path))\n );\n emitRouteTiming("modules", targetPath, modulesStartedAt, { count: allPaths.length });\n perfEnd("render:loadAll");\n const [PageComponent, ...rest] = components;\n const ErrorComponent = pageData.errorPath ? rest.pop() : null;\n const AppComponent = pageData.appPath ? rest.pop() : null;\n const LayoutComponents = rest;\n if (!PageComponent) {\n throw new Error("Failed to load page component: " + pageData.pagePath);\n }\n handoffClientRouteMetadata(\n pageData.frontmatter ?? {},\n document2\n );\n if (pageData.css) {\n const existingStyle = document2.getElementById("veryfront-spa-css");\n if (existingStyle) {\n existingStyle.textContent = pageData.css;\n } else {\n const styleEl = document2.createElement("style");\n const nonce = getDocumentNonce(document2);\n if (nonce) styleEl.setAttribute("nonce", nonce);\n styleEl.id = "veryfront-spa-css";\n styleEl.textContent = pageData.css;\n document2.head.appendChild(styleEl);\n }\n log("Injected CSS for SPA navigation", { cssLength: pageData.css.length });\n } else if (pageData.cssAction === "clear") {\n const existingStyle = document2.getElementById("veryfront-spa-css");\n if (existingStyle) {\n existingStyle.remove();\n log("Cleared SPA CSS for release stylesheet navigation");\n }\n }\n const normalizedParams = flattenRouteParams(pageData.params);\n let tree = React2.createElement(PageComponent, {\n ...pageData.props,\n params: normalizedParams\n });\n if (pageData.layouts?.length) {\n for (let i = pageData.layouts.length - 1; i >= 0; i--) {\n const layout = pageData.layouts[i];\n const LayoutComponent = LayoutComponents[i];\n if (!LayoutComponent || !layout) continue;\n const layoutProps = pageData.layoutProps?.[layout.path] || {};\n tree = React2.createElement(LayoutComponent, { ...layoutProps, children: tree });\n }\n }\n if (AppComponent) {\n tree = React2.createElement(AppComponent, { children: tree });\n log("Wrapped with App component for SPA navigation");\n }\n if (ErrorComponent) {\n class AppRouterErrorBoundary extends React2.Component {\n constructor(props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n static getDerivedStateFromError(error) {\n return { hasError: true, error };\n }\n render() {\n if (this.state.hasError) {\n return React2.createElement(ErrorComponent, {\n error: this.state.error,\n reset: () => this.setState({ hasError: false, error: null })\n });\n }\n return this.props.children;\n }\n }\n tree = React2.createElement(AppRouterErrorBoundary, null, tree);\n }\n const headingsArray = pageData.headings || [];\n const pageContext = {\n slug: pageData.slug || "",\n path: pageData.pagePath || targetPath,\n params: normalizedParams,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n frontmatter: pageData.frontmatter || {},\n data: pageData.props || {},\n headings: headingsArray,\n mdxHeadings: headingsArray\n };\n tree = React2.createElement(PageContextProvider2, { pageContext, children: tree });\n tree = React2.createElement(RouterProvider2, { router, children: tree });\n const container = pageData.isolatedClientPage ? document2.getElementById("veryfront-page-island") : document2.getElementById("root");\n if (!hydrationCompleted && !hydrationFailed) {\n log("Waiting for hydration to complete before SPA render...");\n try {\n await Promise.race([\n hydrationPromise,\n new Promise(\n (_, reject) => setTimeout2(() => reject(new Error("Hydration timeout")), 1e4)\n )\n ]);\n } catch (waitError) {\n log("Hydration wait failed:", waitError.message);\n }\n }\n if (container?.__reactRoot) {\n perfStart("render:reactRender");\n container.__reactRoot.render(tree);\n perfEnd("render:reactRender");\n log("Page re-rendered via SPA");\n scheduleRoutePrefetchRefresh();\n return;\n }\n if (hydrationFailed) {\n throw new Error(\n "React root not found - hydration failed, falling back to full page navigation"\n );\n }\n throw new Error("React root not found");\n }\n let prefetchTimeout = null;\n let currentHoverLink = null;\n let routePrefetchRefreshPending = false;\n let viewportPrefetchObserver = null;\n const observedPrefetchLinks = /* @__PURE__ */ new WeakSet();\n const prefetchedPaths = /* @__PURE__ */ new Set();\n const inFlightPrefetches = /* @__PURE__ */ new Set();\n const queuedPrefetchPaths = /* @__PURE__ */ new Set();\n const pageDataPrefetchQueue = [];\n const activePageDataPrefetchControllers = /* @__PURE__ */ new Map();\n function cancelScheduledPrefetch() {\n if (prefetchTimeout) {\n clearTimeout2(prefetchTimeout);\n prefetchTimeout = null;\n }\n currentHoverLink = null;\n }\n function getPageDataModulePaths(pageData) {\n const layoutPaths = (pageData.layouts || []).map((l) => l.path).filter(Boolean);\n const allPaths = [pageData.pagePath, ...layoutPaths].filter(Boolean);\n if (pageData.appPath) allPaths.push(pageData.appPath);\n if (pageData.errorPath) allPaths.push(pageData.errorPath);\n return allPaths;\n }\n function getCurrentRouteHref() {\n return window.location.pathname + window.location.search;\n }\n function getInternalRouteHrefFromLink(link) {\n if (!link || link.target === "_blank" || link.hasAttribute("download") || link.getAttribute("data-prefetch") === "false") {\n return null;\n }\n const href = link.getAttribute("href");\n if (!href || href.startsWith("#") || href.startsWith("//") || !href.startsWith("/")) {\n return null;\n }\n try {\n const url = new URL(href, window.location.origin);\n if (url.origin !== window.location.origin) return null;\n const routeHref = url.pathname + url.search;\n return routeHref === getCurrentRouteHref() ? null : routeHref;\n } catch (_) {\n return null;\n }\n }\n function getEligiblePrefetchLinks(limit) {\n const links = [];\n const seenHrefs = /* @__PURE__ */ new Set();\n for (const link of document2.querySelectorAll("a[href]")) {\n const href = getInternalRouteHrefFromLink(link);\n if (!href || seenHrefs.has(href)) continue;\n seenHrefs.add(href);\n links.push({ link, href });\n if (links.length >= limit) break;\n }\n return links;\n }\n async function preloadModulesForPageData(pageData, path) {\n if (!pageData || pageData.requiresFullDocumentNavigation) return;\n if (pageData.releaseId && window.__veryfrontSetReleaseId) {\n window.__veryfrontSetReleaseId(pageData.releaseId);\n }\n if (pageData.releaseAssetModules && window.__veryfrontSetReleaseAssetModules) {\n window.__veryfrontSetReleaseAssetModules(pageData.releaseAssetModules);\n }\n const modulePaths = getPageDataModulePaths(pageData);\n if (modulePaths.length === 0) return;\n try {\n await Promise.all(\n modulePaths.map(\n (modulePath) => loadPageDataComponent(pageData, modulePath, { allowDocumentReload: false })\n )\n );\n } catch (error) {\n if (isDependencySnapshotConflict(error)) {\n const cacheIdentity = pageDataCacheIdentity2(path);\n pageDataCache.delete(cacheIdentity);\n backgroundRefreshTimestamps.delete(cacheIdentity);\n prefetchedPaths.delete(path);\n throw error;\n }\n logBackgroundFetchFailure("Module prefetch", path, error);\n }\n }\n function removeQueuedPrefetch(path) {\n queuedPrefetchPaths.delete(path);\n for (let i = pageDataPrefetchQueue.length - 1; i >= 0; i--) {\n if (pageDataPrefetchQueue[i] === path) pageDataPrefetchQueue.splice(i, 1);\n }\n }\n function abortActiveSpeculativePrefetches() {\n for (const controller of activePageDataPrefetchControllers.values()) {\n controller.abort();\n }\n }\n function processPageDataPrefetchQueue() {\n if (isNavigating) return;\n while (activePageDataPrefetchControllers.size < PAGE_DATA_PREFETCH_CONCURRENCY && pageDataPrefetchQueue.length > 0) {\n const href = pageDataPrefetchQueue.shift();\n queuedPrefetchPaths.delete(href);\n if (prefetchedPaths.has(href) || inFlightPrefetches.has(href) || getCachedPageData(href)) {\n continue;\n }\n if (prefetchedPaths.size >= MAX_PREFETCH_PATHS) {\n const oldest = prefetchedPaths.values().next().value;\n if (oldest) prefetchedPaths.delete(oldest);\n }\n const controller = new AbortController();\n prefetchedPaths.add(href);\n inFlightPrefetches.add(href);\n activePageDataPrefetchControllers.set(href, controller);\n fetchPageDataForPrefetch(href, controller.signal).catch((error) => {\n prefetchedPaths.delete(href);\n if (isDependencySnapshotConflict(error)) {\n logBackgroundFetchFailure("Module prefetch", href, error);\n }\n }).finally(() => {\n inFlightPrefetches.delete(href);\n activePageDataPrefetchControllers.delete(href);\n processPageDataPrefetchQueue();\n });\n }\n }\n function prefetchPage(href) {\n if (isNavigating) return;\n if (prefetchedPaths.has(href) || inFlightPrefetches.has(href) || queuedPrefetchPaths.has(href)) return;\n const cachedPageData = getCachedPageData(href);\n if (cachedPageData) {\n preloadModulesForPageData(cachedPageData, href).catch((error) => {\n logBackgroundFetchFailure("Module prefetch", href, error);\n });\n return;\n }\n queuedPrefetchPaths.add(href);\n pageDataPrefetchQueue.push(href);\n processPageDataPrefetchQueue();\n }\n function prefetchEligibleRouteLinks(limit) {\n for (const { href } of getEligiblePrefetchLinks(limit)) {\n prefetchPage(href);\n }\n }\n function ensureViewportPrefetchObserver() {\n if (viewportPrefetchObserver || typeof IntersectionObserver !== "function") {\n return viewportPrefetchObserver;\n }\n viewportPrefetchObserver = new IntersectionObserver((entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n viewportPrefetchObserver?.unobserve(entry.target);\n const href = getInternalRouteHrefFromLink(\n entry.target\n );\n if (href) prefetchPage(href);\n }\n }, { rootMargin: VIEWPORT_PREFETCH_ROOT_MARGIN });\n return viewportPrefetchObserver;\n }\n function observeViewportPrefetchLinks() {\n const observer = ensureViewportPrefetchObserver();\n if (!observer) return;\n for (const { link } of getEligiblePrefetchLinks(VIEWPORT_PREFETCH_MAX_LINKS)) {\n if (observedPrefetchLinks.has(link)) continue;\n observedPrefetchLinks.add(link);\n observer.observe(link);\n }\n }\n function runRoutePrefetchRefresh() {\n routePrefetchRefreshPending = false;\n prefetchEligibleRouteLinks(IDLE_PREFETCH_MAX_LINKS);\n observeViewportPrefetchLinks();\n }\n function scheduleRoutePrefetchRefresh() {\n if (routePrefetchRefreshPending) return;\n routePrefetchRefreshPending = true;\n setTimeout2(() => {\n if (typeof requestIdleCallback === "function") {\n requestIdleCallback(runRoutePrefetchRefresh, { timeout: IDLE_PREFETCH_DELAY_MS });\n return;\n }\n runRoutePrefetchRefresh();\n }, IDLE_PREFETCH_DELAY_MS);\n }\n const router = {\n domain: window.location.origin,\n path: window.location.pathname,\n push: (path) => {\n void navigateSPA(path, "push");\n },\n replace: (path) => {\n void navigateSPA(path, "replace");\n },\n back: () => {\n window.history.back();\n },\n forward: () => {\n window.history.forward();\n },\n prefetch: (path) => {\n prefetchPage(path);\n },\n pathname: window.location.pathname,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n // Seed route params from the hydration data (issue #2741). Catch-all\n // segments arrive as arrays and are joined so no path info is lost.\n params: flattenRouteParams(deps.initialHydrationData.params || {}),\n isPreview: false,\n isMounted: true,\n navigate: (path) => navigateSPA(path, "push"),\n reload: () => window.location.reload()\n };\n window.__veryfrontRouter = router;\n if (deps.navigationStoreUsesRegistryFallback) {\n log("Router runtime does not export getNavigationStore; using shared v1 registry fallback");\n }\n if (typeof deps.getNavigationStore === "function") {\n deps.getNavigationStore().setNavigator((href, options) => {\n const mode = options && options.history;\n const historyMode = mode === "replace" ? "replace" : mode === "none" ? "none" : "push";\n return navigateSPA(href, historyMode);\n });\n }\n window.addEventListener("popstate", async (e) => {\n const path = window.location.pathname;\n log("Popstate:", path);\n saveScrollPosition(currentPath);\n if (!e.state?.pageData) {\n await navigateSPA(path, "none", true);\n return;\n }\n showNavigationProgress();\n try {\n currentPath = path;\n router.pathname = path;\n router.query = Object.fromEntries(new URLSearchParams(window.location.search));\n router.params = flattenRouteParams(e.state.pageData.params);\n await renderPageFromData(e.state.pageData, path);\n restoreScrollPosition(path);\n hideNavigationProgress();\n } catch (error) {\n hideNavigationProgress();\n logError("Popstate render failed:", error.message);\n window.location.reload();\n }\n });\n document2.addEventListener("click", (e) => {\n const link = e.target?.closest("a[href]");\n if (!link) return;\n const href = link.getAttribute("href");\n if (!href) return;\n if (href.startsWith("#")) {\n const target = document2.getElementById(href.slice(1));\n if (!target) return;\n e.preventDefault();\n target.scrollIntoView({ behavior: "smooth" });\n window.history.pushState(null, "", href);\n return;\n }\n if (link.target === "_blank" || link.hasAttribute("download") || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || !href.startsWith("/") || href.startsWith("//")) {\n return;\n }\n e.preventDefault();\n cancelScheduledPrefetch();\n void navigateSPA(href, "push");\n });\n document2.addEventListener(\n "mouseenter",\n (e) => {\n if (!e.target || typeof e.target.closest !== "function") return;\n const link = e.target.closest("a[href]");\n if (!link) return;\n const href = getInternalRouteHrefFromLink(link);\n if (!href) return;\n if (currentHoverLink === link) return;\n if (prefetchTimeout) {\n clearTimeout2(prefetchTimeout);\n prefetchTimeout = null;\n }\n currentHoverLink = link;\n prefetchTimeout = setTimeout2(() => {\n prefetchPage(href);\n prefetchTimeout = null;\n }, PREFETCH_DELAY_MS);\n },\n true\n );\n document2.addEventListener(\n "mouseleave",\n (e) => {\n if (!e.target || typeof e.target.closest !== "function") return;\n const relatedTarget = e.relatedTarget;\n if (currentHoverLink && relatedTarget && currentHoverLink.contains(relatedTarget)) return;\n cancelScheduledPrefetch();\n },\n true\n );\n if (document2.readyState === "loading") {\n document2.addEventListener("DOMContentLoaded", scheduleRoutePrefetchRefresh, { once: true });\n } else {\n scheduleRoutePrefetchRefresh();\n }\n window.useRouter = () => {\n try {\n return env2.useRouterFromModule();\n } catch (_) {\n return window.__veryfrontRouter;\n }\n };\n return {\n router,\n navigateSPA,\n renderPageFromData,\n prefetchPage,\n signalHydrationComplete,\n signalHydrationFailed\n };\n}\n\n// src/html/hydration-script-builder/runtime/renderer.ts\nfunction isModuleNotFoundError(error) {\n if (!error) return false;\n if (error instanceof SyntaxError) return false;\n const message = String(error.message || error);\n return /(?:dynamically imported module|Importing a module script failed|Failed to load module script)/i.test(message);\n}\nfunction preferReachedModuleError(earlier, later) {\n if (!earlier) return later;\n if (!later) return earlier;\n if (isModuleNotFoundError(earlier) && !isModuleNotFoundError(later)) return later;\n return earlier;\n}\nasync function loadPageModuleWithIndexFallback(basePath, pageSlug, pageModuleError, importModule) {\n try {\n return await importModule(basePath + ".js");\n } catch (error) {\n const routeError = preferReachedModuleError(pageModuleError, error);\n if (pageSlug === "index" || pageSlug.endsWith("/index")) throw routeError;\n try {\n return await importModule(basePath + "/index.js");\n } catch (indexError) {\n throw preferReachedModuleError(routeError, indexError);\n }\n }\n}\nfunction isAppRouterPath(path, appRouterRoot) {\n const normalizedPath = typeof path === "string" ? path.replace(/^\\/+/, "") : "";\n return normalizedPath === appRouterRoot || normalizedPath.startsWith(appRouterRoot + "/");\n}\nfunction isRootAppLayoutPath(path, appRouterRoot) {\n const normalizedPath = typeof path === "string" ? path.replace(/^\\/+/, "") : "";\n const pathWithoutExtension = normalizedPath.replace(/\\.(?:tsx|jsx|ts|js)$/, "");\n return pathWithoutExtension === appRouterRoot + "/layout";\n}\nfunction unwrapAppRouterDocumentLayout(LayoutComponent, React2) {\n return function AppRouterDocumentLayout(props) {\n const element = LayoutComponent(props);\n const asElement = element;\n if (!React2.isValidElement(element) || asElement.type !== "html") {\n return element;\n }\n const body = React2.Children.toArray(asElement.props?.children).find(\n (child) => React2.isValidElement(child) && child.type === "body"\n );\n return body?.props?.children ?? props.children;\n };\n}\nfunction createHydrationRenderer(deps) {\n const { env: env2, logging: logging2, componentLoader: componentLoader2, snapshotModules: snapshotModules2, moduleServerUrl: moduleServerUrl2 } = deps;\n const { window, document: document2, React: React2, RouterProvider: RouterProvider2, PageContextProvider: PageContextProvider2 } = env2;\n const { DEBUG, log, logError } = logging2;\n const { loadComponent, pathToModuleUrl } = componentLoader2;\n const { importSnapshotBoundModule } = snapshotModules2;\n async function renderPage(pathname) {\n const resolvedPathname = (() => {\n const input = typeof pathname === "string" ? pathname : window.location.pathname;\n try {\n return new URL(input, window.location.origin).pathname || "/";\n } catch (_) {\n const [pathOnly] = String(input || "/").split(/[?#]/);\n return pathOnly || "/";\n }\n })();\n const dataScript = findServerHydrationDataElement(document2);\n if (!dataScript) {\n logError("Hydration data not found");\n return;\n }\n let data = {};\n try {\n data = JSON.parse(dataScript.textContent || "{}");\n } catch (parseError) {\n logError("Failed to parse hydration data:", parseError);\n return;\n }\n log("Hydration data:", data);\n if (data.studioEmbed && window.__veryfrontSetStudioEmbed) {\n window.__veryfrontSetStudioEmbed(true);\n }\n if (window.__veryfrontSetReleaseId) {\n window.__veryfrontSetReleaseId(data.releaseId || null);\n }\n if (data.releaseAssetModules && window.__veryfrontSetReleaseAssetModules) {\n window.__veryfrontSetReleaseAssetModules(data.releaseAssetModules);\n }\n try {\n let pageModule;\n const pagePath = typeof data.pagePath === "string" ? data.pagePath : "";\n const normalizedPagePath = pagePath.replace(/^\\/+/, "");\n const normalizedAppRouterRoot = typeof data.appRouterRoot === "string" && data.appRouterRoot.replace(/^\\/+|\\/+$/g, "") ? data.appRouterRoot.replace(/^\\/+|\\/+$/g, "") : "app";\n const hasReleaseAssetModules = data.releaseAssetModules && Object.keys(data.releaseAssetModules).length > 0;\n const shouldRenderRscClientPage = data.clientModuleStrategy === "rsc-module" && !hasReleaseAssetModules && isAppRouterPath(normalizedPagePath, normalizedAppRouterRoot);\n const isolatedClientPage = data.isolatedClientPage === true;\n const loadHydrationComponent = async (path, preferRscModule) => {\n const normalizedPath = typeof path === "string" ? path.replace(/^\\/+/, "") : "";\n if (preferRscModule && isAppRouterPath(normalizedPath, normalizedAppRouterRoot)) {\n const moduleUrl = buildPinnedRscModuleUrl(path, data);\n log("Loading App Router component from RSC module:", moduleUrl);\n const module = await importSnapshotBoundModule(moduleUrl);\n return module.default || module;\n }\n return loadComponent(path, data);\n };\n let pageModuleError = null;\n if (data.pagePath) {\n const moduleUrl = shouldRenderRscClientPage ? buildPinnedRscModuleUrl(data.pagePath, data) : pathToModuleUrl(data.pagePath, data.studioEmbed, data);\n log("Loading page from hydration data:", moduleUrl);\n try {\n pageModule = await importSnapshotBoundModule(moduleUrl);\n } catch (error) {\n pageModuleError = error;\n logError("Failed to load page from hydration data:", error);\n }\n }\n if (!pageModule) {\n const pageSlug = resolvedPathname === "/" ? "index" : resolvedPathname.slice(1);\n log("Falling back to Pages Router pattern:", pageSlug);\n const prefix = pageSlug.startsWith("@/") ? "" : "/pages";\n const basePath = moduleServerUrl2 + prefix + "/" + pageSlug;\n pageModule = await loadPageModuleWithIndexFallback(\n basePath,\n pageSlug,\n pageModuleError,\n (moduleUrl) => importSnapshotBoundModule(appendDependencyPinningVersion(moduleUrl, data))\n );\n }\n if (!pageModule) {\n logError("Page module failed to load");\n return;\n }\n const PageComponent = pageModule.default || pageModule;\n if (!PageComponent) {\n logError("Page component not found");\n return;\n }\n const normalizedParams = flattenRouteParams(data.params);\n const pageProps = { ...data.props || {}, params: normalizedParams };\n let tree = React2.createElement(PageComponent, pageProps);\n const layouts = data.layouts;\n if (layouts?.length) {\n for (let i = layouts.length - 1; i >= 0; i--) {\n const layout = layouts[i];\n if (!layout) continue;\n const LayoutComponent = await loadHydrationComponent(\n layout.path,\n shouldRenderRscClientPage\n );\n if (LayoutComponent) {\n const WrappedLayoutComponent = shouldRenderRscClientPage && isRootAppLayoutPath(layout.path, normalizedAppRouterRoot) ? unwrapAppRouterDocumentLayout(LayoutComponent, React2) : LayoutComponent;\n const layoutProps = data.layoutProps?.[layout.path] || {};\n tree = React2.createElement(\n WrappedLayoutComponent,\n { ...layoutProps, children: tree }\n );\n }\n }\n }\n if (data.appPath && !isolatedClientPage) {\n const AppComponent = await loadHydrationComponent(data.appPath, shouldRenderRscClientPage);\n if (AppComponent) {\n tree = React2.createElement(AppComponent, { children: tree });\n }\n }\n if (data.errorPath) {\n const ErrorComponent = await loadHydrationComponent(\n data.errorPath,\n shouldRenderRscClientPage\n );\n if (ErrorComponent) {\n class AppRouterErrorBoundary extends React2.Component {\n constructor(props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n static getDerivedStateFromError(error) {\n return { hasError: true, error };\n }\n render() {\n if (this.state.hasError) {\n return React2.createElement(ErrorComponent, {\n error: this.state.error,\n reset: () => this.setState({ hasError: false, error: null })\n });\n }\n return this.props.children;\n }\n }\n tree = React2.createElement(AppRouterErrorBoundary, null, tree);\n }\n }\n const headings = data.headings || [];\n const pageContext = {\n slug: data.slug || "",\n path: data.pagePath || resolvedPathname,\n params: normalizedParams,\n query: Object.fromEntries(new URLSearchParams(window.location.search)),\n frontmatter: data.frontmatter || {},\n data: data.props || {},\n headings,\n mdxHeadings: headings\n // Alias for backwards compatibility\n };\n tree = React2.createElement(PageContextProvider2, { pageContext, children: tree });\n tree = React2.createElement(RouterProvider2, { router: deps.router, children: tree });\n const container = isolatedClientPage ? document2.getElementById("veryfront-page-island") : document2.getElementById("root");\n if (!container) {\n if (isolatedClientPage) {\n throw new Error("Isolated client page root not found");\n }\n return;\n }\n if (container.__reactRoot) {\n container.__reactRoot.render(tree);\n log("Page re-rendered");\n return;\n }\n if (shouldRenderRscClientPage) {\n container.__reactRoot = env2.createRoot(container);\n container.__reactRoot.render(tree);\n log("Client-side React app rendered successfully");\n } else {\n const { hydrateRoot } = await import("react-dom/client");\n const options = {\n identifierPrefix: "vf",\n onRecoverableError: (error) => {\n if (data.dev && DEBUG) {\n log("Hydration mismatch (suppressed):", error.message);\n }\n }\n };\n container.__reactRoot = hydrateRoot(container, tree, options);\n log("Client-side React app hydrated successfully");\n }\n if (window.__veryfrontHydrationComplete) {\n window.__veryfrontHydrationComplete();\n }\n } catch (error) {\n logError("Client initialization error:", error);\n if (window.__veryfrontHydrationFailed) {\n window.__veryfrontHydrationFailed(error);\n }\n }\n }\n function start() {\n window.__veryfrontRenderPage = renderPage;\n void renderPage(window.location.pathname);\n const initialDataScript = findServerHydrationDataElement(document2);\n if (initialDataScript) {\n try {\n const pageData = JSON.parse(initialDataScript.textContent || "{}");\n if (pageData.pagePath) {\n window.history.replaceState({ pageData, scrollY: 0 }, "", window.location.href);\n log("Stored initial page data in history state");\n }\n } catch (_) {\n }\n }\n }\n return { renderPage, start };\n}\n\n// src/html/hydration-script-builder/runtime/navigation-store.ts\nvar NAVIGATION_STORE_REGISTRY_KEY = "veryfront.navigation.store.v1";\nfunction resolveNavigationStore(RouterRuntime2) {\n const usesRegistryFallback2 = typeof RouterRuntime2.getNavigationStore !== "function";\n if (!usesRegistryFallback2) {\n return {\n usesRegistryFallback: usesRegistryFallback2,\n getNavigationStore: RouterRuntime2.getNavigationStore\n };\n }\n return {\n usesRegistryFallback: usesRegistryFallback2,\n getNavigationStore: () => {\n const storeKey = Symbol.for(NAVIGATION_STORE_REGISTRY_KEY);\n const registry = globalThis;\n const existing = registry[storeKey];\n if (existing) return existing;\n const listeners = /* @__PURE__ */ new Set();\n let navigator = null;\n const store = {\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getHref() {\n const loc = globalThis.location;\n return loc ? loc.pathname + loc.search + loc.hash : "/";\n },\n notify() {\n for (const listener of [...listeners]) {\n try {\n listener();\n } catch {\n }\n }\n },\n navigate(href, options) {\n if (navigator) return navigator(href, options);\n globalThis.location?.assign(href);\n return Promise.resolve();\n },\n setNavigator(next) {\n navigator = next;\n }\n };\n registry[storeKey] = store;\n return store;\n }\n };\n}\n\n// src/html/hydration-script-builder/runtime/main.ts\nvar runtimeWindow = globalThis;\nvar runtimeDocument = globalThis.document;\nvar env = {\n window: runtimeWindow,\n document: runtimeDocument,\n fetch: (url, init) => fetch(url, init),\n React,\n RouterProvider,\n PageContextProvider,\n createRoot: (container) => createRoot(container),\n importModule: (moduleUrl) => import(moduleUrl),\n useRouterFromModule,\n setTimeout: (handler, timeout) => setTimeout(handler, timeout),\n clearTimeout: (id) => clearTimeout(id)\n};\nvar logging = createLogging(runtimeWindow);\nvar initialHydrationData = readInitialHydrationData(runtimeDocument);\nvar documentDependencyPinningCacheKey = readDocumentDependencyPinningCacheKey(\n initialHydrationData\n);\nvar routeTiming = createRouteTimingRecorder(runtimeWindow, logging);\nvar snapshotModules = createSnapshotModuleImporter({\n importModule: env.importModule,\n fetchModule: env.fetch,\n reloadDocument: () => runtimeWindow.location.reload(),\n recoveryState: runtimeWindow\n});\nvar componentLoader = createComponentLoader({\n window: runtimeWindow,\n logging,\n moduleServerUrl: moduleServerUrl(runtimeWindow),\n snapshotModules\n});\nruntimeWindow.__veryfrontClearComponentCache = componentLoader.clearComponentCache;\nruntimeWindow.__veryfrontSetStudioEmbed = componentLoader.setStudioEmbed;\nruntimeWindow.__veryfrontSetReleaseId = componentLoader.setReleaseId;\nruntimeWindow.__veryfrontSetReleaseAssetModules = componentLoader.setReleaseAssetModules;\nruntimeWindow.__veryfrontSetHMRRefreshTimestamp = componentLoader.setHMRRefreshTimestamp;\nvar { usesRegistryFallback, getNavigationStore } = resolveNavigationStore(RouterRuntime);\nvar routerRuntime = createRouterRuntime({\n env,\n logging,\n routeTiming,\n componentLoader,\n snapshotModules,\n initialHydrationData,\n documentDependencyPinningCacheKey,\n getNavigationStore,\n navigationStoreUsesRegistryFallback: usesRegistryFallback\n});\ncreateHydrationRenderer({\n env,\n logging,\n componentLoader,\n snapshotModules,\n moduleServerUrl: moduleServerUrl(runtimeWindow),\n router: routerRuntime.router\n}).start();\n';
@@ -3,6 +3,12 @@ import type { AgentServiceSandboxToolsOptions, AgentServiceSandboxToolsResult }
3
3
  import { type Tool } from "../tool/index.js";
4
4
  import { type AgentRunSessionManager } from "./session-manager.js";
5
5
  import type { RuntimeRunAgentInput } from "./schema.js";
6
+ /**
7
+ * SSE frame name carrying AGENT_RUN_MODEL_CALL_CONTEXT to veryfront-api. Not an
8
+ * AG-UI event: veryfront-api persists it under its own event type rather than
9
+ * folding it into the run's public event sequence.
10
+ */
11
+ export declare const MODEL_CALL_CONTEXT_SSE_EVENT_NAME = "AgentRunModelCallContext";
6
12
  export interface RuntimeAgentStreamExecutionDeps {
7
13
  sessionManager: AgentRunSessionManager;
8
14
  localTools?: Record<string, Tool | boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAc3B,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAGL,KAAK,IAAI,EAGV,MAAM,kBAAkB,CAAC;AAgB1B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAsCxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;IAC5C,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IACnE,8BAA8B,CAAC,EAAE,CAC/B,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAoCD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,sBAAsB,EACtC,2BAA2B,CAAC,EAAE,MAAM,EAAE,EACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;;cAuFrD;AAsYD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,QAAQ,CAAC,CAkhBnB"}
1
+ {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAc3B,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAGL,KAAK,IAAI,EAGV,MAAM,kBAAkB,CAAC;AAkB1B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAWxD;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,6BAA6B,CAAC;AA4B5E,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;IAC5C,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IACnE,8BAA8B,CAAC,EAAE,CAC/B,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAoCD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,sBAAsB,EACtC,2BAA2B,CAAC,EAAE,MAAM,EAAE,EACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;;cAuFrD;AA+ZD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,QAAQ,CAAC,CAwiBnB"}
@@ -16,6 +16,7 @@ import { skillRegistry } from "../skill/registry.js";
16
16
  import { addSpanEvent, setSpanAttributes, withSpan, } from "../observability/tracing/otlp-setup.js";
17
17
  import { defineSchema, lazySchema } from "../schemas/index.js";
18
18
  import { createStreamTransformState, finalizeRunEvents, formatAgUiEvent, mapRuntimeEventToAgUi, parseSseJsonEvents, } from "./ag-ui-sse.js";
19
+ import { runWithMandatoryRunEventSink } from "../runtime/run-event-sink-context.js";
19
20
  import { AgentRunCancelledError } from "./session-manager.js";
20
21
  import { composeInternalAgentRunSystemPrompt } from "./run-system-prompt.js";
21
22
  import { serverLogger } from "../utils/index.js";
@@ -25,6 +26,12 @@ const logger = serverLogger.component("internal-agent-run-stream");
25
26
  const PROJECT_AGENT_SANDBOX_BASH_TOOL_NAME = "bash";
26
27
  const INTERNAL_AGENT_RUNTIME_HEARTBEAT_INTERVAL_MS = 25_000;
27
28
  const INTERNAL_AGENT_RUNTIME_HEARTBEAT_FRAME = new TextEncoder().encode(": internal-agent-runtime-heartbeat\n\n");
29
+ /**
30
+ * SSE frame name carrying AGENT_RUN_MODEL_CALL_CONTEXT to veryfront-api. Not an
31
+ * AG-UI event: veryfront-api persists it under its own event type rather than
32
+ * folding it into the run's public event sequence.
33
+ */
34
+ export const MODEL_CALL_CONTEXT_SSE_EVENT_NAME = "AgentRunModelCallContext";
28
35
  function getAgentAllowedRemoteToolNames(agent) {
29
36
  const raw = agent.config.__vfAllowedRemoteTools;
30
37
  return Array.isArray(raw) && raw.every((toolName) => typeof toolName === "string") ? raw : [];
@@ -414,6 +421,30 @@ async function getDeclaredRemoteSourceToolNames(input) {
414
421
  function compactRuntimeMessagesForStream(messages, systemPrompt, toolCount) {
415
422
  return convertProviderMessagesToAgentRuntimeMessages(compactForStep(convertAgentRuntimeMessagesToProviderMessages(messages), estimateOverhead(systemPrompt, toolCount)));
416
423
  }
424
+ /**
425
+ * Relays run events produced by the runtime into the run's SSE stream.
426
+ *
427
+ * The first model call is dispatched while `runtime.stream()` is still being
428
+ * awaited, before there is a controller to enqueue into, so events raised
429
+ * before `attach` are buffered and replayed once the stream opens.
430
+ */
431
+ function createModelCallContextRelay() {
432
+ const buffered = [];
433
+ let emit;
434
+ return {
435
+ sink: (event) => {
436
+ if (emit)
437
+ emit(event);
438
+ else
439
+ buffered.push(event);
440
+ },
441
+ attach: (next) => {
442
+ emit = next;
443
+ for (const event of buffered.splice(0))
444
+ next(event);
445
+ },
446
+ };
447
+ }
417
448
  export async function createRuntimeAgentStreamResponse(input, agent, deps) {
418
449
  logger.info("Starting internal agent runtime stream", {
419
450
  runId: input.runId,
@@ -430,6 +461,7 @@ export async function createRuntimeAgentStreamResponse(input, agent, deps) {
430
461
  let completedResponse = null;
431
462
  let runtimeStream;
432
463
  let closeSandbox = createIdempotentAsyncCleanup();
464
+ const modelCallContextRelay = createModelCallContextRelay();
433
465
  try {
434
466
  const forwardedAllowedRemoteToolNames = getAllowedRemoteToolNames(input.forwardedProps);
435
467
  const sourceAllowedRemoteToolNames = getAgentAllowedRemoteToolNames(agent);
@@ -523,7 +555,10 @@ export async function createRuntimeAgentStreamResponse(input, agent, deps) {
523
555
  new AgentRuntime(runtimeAgent.id, runtimeAgent.config);
524
556
  const runtimeMessages = compactRuntimeMessagesForStream(normalizeAgUiRuntimeMessages(input.messages), systemPrompt, runtimeToolNames.length);
525
557
  const maxOutputTokens = getForwardedMaxOutputTokens(input.forwardedProps);
526
- const candidateRuntimeStream = await runtime.stream(runtimeMessages, {
558
+ // Scoped here because the runtime dispatches the run's first model call
559
+ // before stream() resolves. Later steps inherit this scope through the
560
+ // stream they are pumped from.
561
+ const candidateRuntimeStream = await runWithMandatoryRunEventSink(modelCallContextRelay.sink, () => runtime.stream(runtimeMessages, {
527
562
  threadId: input.threadId,
528
563
  runId: input.runId,
529
564
  ...(deps.projectAgentSandbox?.authToken
@@ -537,7 +572,7 @@ export async function createRuntimeAgentStreamResponse(input, agent, deps) {
537
572
  onFinish: (response) => {
538
573
  completedResponse = response;
539
574
  },
540
- }, undefined, maxOutputTokens, abortSignal);
575
+ }, undefined, maxOutputTokens, abortSignal));
541
576
  if (candidateRuntimeStream.locked) {
542
577
  throw new TypeError("Internal agent runtime returned a locked stream");
543
578
  }
@@ -669,10 +704,16 @@ export async function createRuntimeAgentStreamResponse(input, agent, deps) {
669
704
  threadId: input.threadId,
670
705
  agentId: agent.id,
671
706
  });
707
+ // Replays whatever the first model call already produced, then
708
+ // forwards later steps as they happen. RunStarted stays first.
709
+ modelCallContextRelay.attach((event) => enqueueIfAttached(MODEL_CALL_CONTEXT_SSE_EVENT_NAME, event));
672
710
  heartbeatTimer = setInterval(enqueueHeartbeatIfAttached, INTERNAL_AGENT_RUNTIME_HEARTBEAT_INTERVAL_MS);
673
711
  while (true) {
674
712
  throwIfAborted();
675
- const { done, value } = await reader.read();
713
+ // A runtime that dispatches later model calls from its pull()
714
+ // rather than from a continuation of stream() needs the sink in
715
+ // scope on the read that triggers the pull.
716
+ const { done, value } = await runWithMandatoryRunEventSink(modelCallContextRelay.sink, () => reader.read());
676
717
  throwIfAborted();
677
718
  if (done) {
678
719
  readerReachedEof = true;
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/proxy-manager.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAA0B,MAAM,YAAY,CAAC;AAmEtF,UAAU,2BAA2B;IACnC,UAAU,EAAE,eAAe,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,kBAAkB,CAAC;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,eAAe,CAAkD;IACzE,OAAO,CAAC,cAAc,CAAkD;IACxE,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAC,CAAiC;gBAE1C,MAAM,EAAE,2BAA2B;IAuBzC,UAAU,CACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,OAAO,EACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,kBAAkB,CAAC;IAsL9B,OAAO,CAAC,oBAAoB;IAiD5B,OAAO,CAAC,yBAAyB;IAmBjC,OAAO,CAAC,wBAAwB;IAwChC,OAAO,CAAC,aAAa;IA6HrB,OAAO,CAAC,sBAAsB;IAwB9B,OAAO,CAAC,mBAAmB;IAc3B,UAAU,CACR,WAAW,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,OAAO,EACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO;IAeV,YAAY,CACV,WAAW,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,OAAO,EACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI;IAqBP,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,uBAAuB;IAoB/B,OAAO,CAAC,oBAAoB;IAY5B,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;KAAE;IAenE,OAAO,IAAI,IAAI;CAgBhB"}
1
+ {"version":3,"file":"proxy-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/proxy-manager.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAA0B,MAAM,YAAY,CAAC;AAmEtF,UAAU,2BAA2B;IACnC,UAAU,EAAE,eAAe,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,kBAAkB,CAAC;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,eAAe,CAAkD;IACzE,OAAO,CAAC,cAAc,CAAkD;IACxE,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAC,CAAiC;gBAE1C,MAAM,EAAE,2BAA2B;IAuBzC,UAAU,CACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,OAAO,EACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,kBAAkB,CAAC;IAwL9B,OAAO,CAAC,oBAAoB;IAiD5B,OAAO,CAAC,yBAAyB;IAmBjC,OAAO,CAAC,wBAAwB;IAwChC,OAAO,CAAC,aAAa;IA6HrB,OAAO,CAAC,sBAAsB;IAwB9B,OAAO,CAAC,mBAAmB;IAc3B,UAAU,CACR,WAAW,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,OAAO,EACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO;IAeV,YAAY,CACV,WAAW,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,OAAO,EACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI;IAqBP,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,uBAAuB;IAoB/B,OAAO,CAAC,oBAAoB;IAY5B,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;KAAE;IAenE,OAAO,IAAI,IAAI;CAgBhB"}
@@ -62,9 +62,11 @@ export class ProxyFSAdapterManager {
62
62
  async getAdapter(projectSlug, token, projectId, productionMode, releaseId, environmentName, branch) {
63
63
  const getAdapterStartTime = performance.now();
64
64
  const effectiveProductionMode = productionMode ?? false;
65
- const effectiveReleaseId = releaseId ?? null;
66
- const effectiveEnvironmentName = environmentName ?? null;
67
- const effectiveBranch = branch ?? (effectiveProductionMode ? null : "main");
65
+ // All three must use the same predicate the cache key uses, or an identity
66
+ // that is not part of the key can still differ and fail the reuse assertion.
67
+ const effectiveReleaseId = effectiveProductionMode ? (releaseId ?? null) : null;
68
+ const effectiveEnvironmentName = environmentName || null;
69
+ const effectiveBranch = effectiveProductionMode ? null : (branch ?? "main");
68
70
  if (this.baseConfig.veryfront?.proxyMode === true &&
69
71
  (!projectId?.trim() || projectId !== projectId.trim())) {
70
72
  throw INVALID_ARGUMENT.create({
@@ -7,7 +7,7 @@
7
7
  * Client identity for guarded egress, standing in for the runtime-supplied
8
8
  * `user-agent` (`node`, `Deno/x.y.z`) that this transport cannot inherit.
9
9
  */
10
- export declare const DEFAULT_OUTBOUND_USER_AGENT = "veryfront/0.1.1197";
10
+ export declare const DEFAULT_OUTBOUND_USER_AGENT = "veryfront/0.1.1199";
11
11
  /**
12
12
  * Fill in the request headers a plain `fetch` attaches on its own, leaving any
13
13
  * the caller set untouched. This transport talks to `node:http` directly, so
@@ -1 +1 @@
1
- {"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAoBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAS7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IAsCnB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA8HvE;;;;;OAKG;YACW,wBAAwB;IAuCtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,+BAA+B,IAAI,MAAM,IAAI;IAWpD,MAAM,CAAC,QAAQ,IAAI,IAAI;CAaxB"}
1
+ {"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAoBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAS7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IAsCnB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA8HvE;;;;;OAKG;YACW,wBAAwB;IA2CtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,+BAA+B,IAAI,MAAM,IAAI;IAWpD,MAAM,CAAC,QAAQ,IAAI,IAAI;CAaxB"}
@@ -194,6 +194,10 @@ export class HMRHandler extends BaseHandler {
194
194
  }, ctx.projectId, {
195
195
  productionMode: false,
196
196
  branch: ctx.requestContext?.branch ?? "main",
197
+ // The named environment, not the mode in `resolvedEnvironment`. Must
198
+ // match what renders resolve, or HMR warms a different adapter and
199
+ // its WebSocketManager never receives pokes.
200
+ environmentName: ctx.environmentName ?? null,
197
201
  });
198
202
  }
199
203
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"agent-run-cancel.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-run-cancel.handler.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,6CAA6C,CAAC;AAMrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AASnG,qBAAa,qBAAsB,SAAQ,WAAW;IASxC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAR3C,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,cAAc,GAAE,sBAA+C;IAItF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAkDxE"}
1
+ {"version":3,"file":"agent-run-cancel.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-run-cancel.handler.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,6CAA6C,CAAC;AAMrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAanG,qBAAa,qBAAsB,SAAQ,WAAW;IASxC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAR3C,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,cAAc,GAAE,sBAA+C;IAItF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA0DxE"}
@@ -3,7 +3,8 @@ import { ControlPlaneRequestError, verifyControlPlaneRequest, } from "../../../i
3
3
  import { agentRunSessionManager, } from "../../../internal-agents/session-manager.js";
4
4
  import { INTERNAL_AGENT_CONTROL_PLANE_MAX_BODY_BYTES, InternalAgentRequestBodyTooLargeError, readInternalAgentRequestBody, } from "../../../internal-agents/request-body.js";
5
5
  import { BaseHandler } from "../response/base.js";
6
- import { PRIORITY_MEDIUM_API } from "../../../utils/constants/index.js";
6
+ import { HTTP_INTERNAL_SERVER_ERROR, PRIORITY_MEDIUM_API, } from "../../../utils/constants/index.js";
7
+ import { reportHandlerFailure } from "./report-handler-failure.js";
7
8
  const CANCEL_PATH_REGEX = /^\/api\/control-plane\/runs\/([^/]+)$/;
8
9
  function getRunId(pathname) {
9
10
  return CANCEL_PATH_REGEX.exec(pathname)?.[1] ?? null;
@@ -58,6 +59,14 @@ export class AgentRunCancelHandler extends BaseHandler {
58
59
  projectId: ctx.projectId,
59
60
  projectSlug: ctx.projectSlug,
60
61
  });
62
+ reportHandlerFailure(error, {
63
+ boundary: "agent.run.cancel",
64
+ method: req.method,
65
+ status: HTTP_INTERNAL_SERVER_ERROR,
66
+ runId,
67
+ projectId: ctx.projectId,
68
+ projectSlug: ctx.projectSlug,
69
+ });
61
70
  return this.respond(builder.json({ error: "Internal cancel failed" }, 500));
62
71
  }
63
72
  });
@@ -1 +1 @@
1
- {"version":3,"file":"agent-run-resume.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-run-resume.handler.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,sBAAsB,EAK5B,MAAM,6CAA6C,CAAC;AAOrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AASnG,qBAAa,qBAAsB,SAAQ,WAAW;IASxC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAR3C,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,cAAc,GAAE,sBAA+C;IAItF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAoExE"}
1
+ {"version":3,"file":"agent-run-resume.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-run-resume.handler.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,sBAAsB,EAK5B,MAAM,6CAA6C,CAAC;AAOrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAanG,qBAAa,qBAAsB,SAAQ,WAAW;IASxC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAR3C,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,cAAc,GAAE,sBAA+C;IAItF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA4ExE"}
@@ -4,7 +4,8 @@ import { agentRunSessionManager, RunNotActiveError, ToolResultConflictError, Too
4
4
  import { INTERNAL_AGENT_CONTROL_PLANE_MAX_BODY_BYTES, InternalAgentRequestBodyTooLargeError, readInternalAgentRequestBody, } from "../../../internal-agents/request-body.js";
5
5
  import { getResumeSignalSchema } from "../../../internal-agents/schema.js";
6
6
  import { BaseHandler } from "../response/base.js";
7
- import { PRIORITY_MEDIUM_API } from "../../../utils/constants/index.js";
7
+ import { HTTP_INTERNAL_SERVER_ERROR, PRIORITY_MEDIUM_API, } from "../../../utils/constants/index.js";
8
+ import { reportHandlerFailure } from "./report-handler-failure.js";
8
9
  const RESUME_PATH_REGEX = /^\/api\/control-plane\/runs\/([^/]+)\/resume$/;
9
10
  function getRunId(pathname) {
10
11
  return RESUME_PATH_REGEX.exec(pathname)?.[1] ?? null;
@@ -73,6 +74,14 @@ export class AgentRunResumeHandler extends BaseHandler {
73
74
  projectId: ctx.projectId,
74
75
  projectSlug: ctx.projectSlug,
75
76
  });
77
+ reportHandlerFailure(error, {
78
+ boundary: "agent.run.resume",
79
+ method: req.method,
80
+ status: HTTP_INTERNAL_SERVER_ERROR,
81
+ runId,
82
+ projectId: ctx.projectId,
83
+ projectSlug: ctx.projectSlug,
84
+ });
76
85
  return this.respond(builder.json({ error: "Internal resume failed" }, 500));
77
86
  }
78
87
  });
@@ -1 +1 @@
1
- {"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAGpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;AAchD,OAAO,EACL,4BAA4B,EAE7B,MAAM,2CAA2C,CAAC;AAkBnD,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAG/B,MAAM,oCAAoC,CAAC;AAQ5C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAuBnG,MAAM,WAAW,sBACf,SAAQ,yBAAyB,EAAE,+BAA+B;IAClE,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;IACnE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,+BAA+B,CAAC,YAAY,CAAC,CAAC;IACnF,0BAA0B,CAAC,EAAE,4BAA4B,CAAC;CAC3D;AAED,KAAK,yBAAyB,GAAG,IAAI,CACnC,0BAA0B,EAC1B,mBAAmB,GAAG,4BAA4B,GAAG,uBAAuB,CAC7E,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,CACzC,GAAG,EAAE,cAAc,EACnB,aAAa,EAAE,yBAAyB,EACxC,cAAc,EAAE,yBAAyB,EACzC,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AA4oBrC,qBAAa,kBAAmB,SAAQ,WAAW;IASrC,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,IAAI,GAAE,sBAAoC;IAIvE,OAAO,CAAC,sBAAsB;IAsBxB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAkQxE"}
1
+ {"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAGpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;AAchD,OAAO,EACL,4BAA4B,EAE7B,MAAM,2CAA2C,CAAC;AAkBnD,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAG/B,MAAM,oCAAoC,CAAC;AAQ5C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAuBnG,MAAM,WAAW,sBACf,SAAQ,yBAAyB,EAAE,+BAA+B;IAClE,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;IACnE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,+BAA+B,CAAC,YAAY,CAAC,CAAC;IACnF,0BAA0B,CAAC,EAAE,4BAA4B,CAAC;CAC3D;AAED,KAAK,yBAAyB,GAAG,IAAI,CACnC,0BAA0B,EAC1B,mBAAmB,GAAG,4BAA4B,GAAG,uBAAuB,CAC7E,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,CACzC,GAAG,EAAE,cAAc,EACnB,aAAa,EAAE,yBAAyB,EACxC,cAAc,EAAE,yBAAyB,EACzC,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAomBrC,qBAAa,kBAAmB,SAAQ,WAAW;IASrC,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,IAAI,GAAE,sBAAoC;IAIvE,OAAO,CAAC,sBAAsB;IAsBxB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA0QxE"}
@@ -16,7 +16,7 @@ import { getInternalAgentStreamRequestSchema, toRuntimeRunAgentInput, } from "..
16
16
  import { AUTHENTICATION_REQUIRED, errorToResponse, INVALID_ARGUMENT, isVeryfrontError, PERMISSION_DENIED, } from "../../../errors/index.js";
17
17
  import { BaseHandler } from "../response/base.js";
18
18
  import { HTTP_INTERNAL_SERVER_ERROR, PRIORITY_MEDIUM_API, } from "../../../utils/constants/index.js";
19
- import { captureApplicationError } from "../../../observability/application-errors.js";
19
+ import { reportHandlerFailure } from "./report-handler-failure.js";
20
20
  import { buildRuntimeShuttingDownResponse } from "./runtime-shutdown-response.js";
21
21
  import { isServerShuttingDown } from "../../shutdown-state.js";
22
22
  import { getHostEnv } from "../../../platform/compat/process.js";
@@ -455,47 +455,14 @@ function getPathRunId(pathname) {
455
455
  const match = RUN_STREAM_PATH_REGEX.exec(pathname);
456
456
  return match?.[1] ? decodeURIComponent(match[1]) : null;
457
457
  }
458
- /**
459
- * Report a 5xx agent stream failure.
460
- *
461
- * Handlers convert every error into a response, so nothing escapes to a global
462
- * handler and these would otherwise never reach Sentry. 4xx is excluded: it is
463
- * mostly validation and auth noise. `detail` is forwarded because
464
- * errorToResponse strips it from 5xx bodies. No-op when no reporter is
465
- * installed, so Sentry stays optional.
466
- */
467
- function reportAgentStreamFailure(error, req, ctx, details) {
468
- const attributes = {
469
- "http.status": details.status,
470
- };
471
- // `pathRunId` is scoped to the try block, so re-derive it here. Reporting runs
472
- // inside a catch, so a malformed percent escape must not throw past it and
473
- // take out the response this is describing.
474
- let runId = null;
458
+ /** getPathRunId decodes, which throws on a malformed escape; reporting must not. */
459
+ function safeRunId(req) {
475
460
  try {
476
- runId = getPathRunId(new URL(req.url).pathname);
461
+ return getPathRunId(new URL(req.url).pathname);
477
462
  }
478
463
  catch {
479
- runId = null;
464
+ return null;
480
465
  }
481
- if (details.slug)
482
- attributes["error.slug"] = details.slug;
483
- if (details.category)
484
- attributes["error.category"] = details.category;
485
- if (details.detail)
486
- attributes["error.detail"] = details.detail;
487
- if (details.cause)
488
- attributes["error.cause"] = details.cause;
489
- if (ctx.projectId)
490
- attributes["project.id"] = ctx.projectId;
491
- if (ctx.projectSlug)
492
- attributes["project.slug"] = ctx.projectSlug;
493
- captureApplicationError(error, {
494
- boundary: details.boundary,
495
- method: req.method,
496
- ...(runId ? { requestId: runId } : {}),
497
- attributes,
498
- });
499
466
  }
500
467
  export class AgentStreamHandler extends BaseHandler {
501
468
  deps;
@@ -678,8 +645,8 @@ export class AgentStreamHandler extends BaseHandler {
678
645
  }
679
646
  if (isVeryfrontError(error)) {
680
647
  const response = errorToResponse(error, new URL(req.url).pathname);
681
- // errorToResponse strips `detail` from 5xx bodies, and this branch is
682
- // otherwise silent, so the detail would be lost entirely.
648
+ // errorToResponse strips `detail` from 5xx bodies, so the log and the
649
+ // reported event are the only places it survives.
683
650
  if (response.status >= 500) {
684
651
  const cause = describeErrorCause(error.cause);
685
652
  logger.error("Internal agent stream request failed", {
@@ -692,9 +659,13 @@ export class AgentStreamHandler extends BaseHandler {
692
659
  error: error.message,
693
660
  cause,
694
661
  });
695
- reportAgentStreamFailure(error, req, ctx, {
662
+ reportHandlerFailure(error, {
696
663
  boundary: "agent.stream.request",
664
+ method: req.method,
697
665
  status: response.status,
666
+ runId: safeRunId(req),
667
+ projectId: ctx.projectId,
668
+ projectSlug: ctx.projectSlug,
698
669
  slug: error.slug,
699
670
  category: error.category,
700
671
  detail: error.detail,
@@ -715,9 +686,13 @@ export class AgentStreamHandler extends BaseHandler {
715
686
  });
716
687
  // Unexpected failures have no slug or detail, so the captured stack is
717
688
  // the only real diagnostic.
718
- reportAgentStreamFailure(error, req, ctx, {
689
+ reportHandlerFailure(error, {
719
690
  boundary: "agent.stream.handler",
691
+ method: req.method,
720
692
  status: HTTP_INTERNAL_SERVER_ERROR,
693
+ runId: safeRunId(req),
694
+ projectId: ctx.projectId,
695
+ projectSlug: ctx.projectSlug,
721
696
  });
722
697
  return this.respond(builder.json({ error: "Internal agent stream failed" }, 500));
723
698
  }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Report a 5xx handler failure. Handlers convert errors into responses, so
3
+ * these never escape to a global handler and would not otherwise reach Sentry.
4
+ * Anything below 500 is dropped as noise. No-op when no reporter is installed.
5
+ */
6
+ export declare function reportHandlerFailure(error: unknown, details: {
7
+ boundary: string;
8
+ method: string;
9
+ status: number;
10
+ runId?: string | null;
11
+ projectId?: string;
12
+ projectSlug?: string;
13
+ slug?: string;
14
+ category?: string;
15
+ detail?: string;
16
+ cause?: string;
17
+ }): void;
18
+ //# sourceMappingURL=report-handler-failure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-handler-failure.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/report-handler-failure.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,IAAI,CAqBN"}
@@ -0,0 +1,33 @@
1
+ import { captureApplicationError } from "../../../observability/application-errors.js";
2
+ /**
3
+ * Report a 5xx handler failure. Handlers convert errors into responses, so
4
+ * these never escape to a global handler and would not otherwise reach Sentry.
5
+ * Anything below 500 is dropped as noise. No-op when no reporter is installed.
6
+ */
7
+ export function reportHandlerFailure(error, details) {
8
+ // Enforced here, not just documented: a future caller passing a 4xx would
9
+ // otherwise flood Sentry with the validation and auth noise this excludes.
10
+ if (details.status < 500)
11
+ return;
12
+ const attributes = {
13
+ "http.status": details.status,
14
+ };
15
+ if (details.slug)
16
+ attributes["error.slug"] = details.slug;
17
+ if (details.category)
18
+ attributes["error.category"] = details.category;
19
+ if (details.detail)
20
+ attributes["error.detail"] = details.detail;
21
+ if (details.cause)
22
+ attributes["error.cause"] = details.cause;
23
+ if (details.projectId)
24
+ attributes["project.id"] = details.projectId;
25
+ if (details.projectSlug)
26
+ attributes["project.slug"] = details.projectSlug;
27
+ captureApplicationError(error, {
28
+ boundary: details.boundary,
29
+ method: details.method,
30
+ ...(details.runId ? { requestId: details.runId } : {}),
31
+ attributes,
32
+ });
33
+ }
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.1197";
2
+ export declare const VERSION = "0.1.1199";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.1197";
4
+ export const VERSION = "0.1.1199";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.1197",
3
+ "version": "0.1.1199",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -421,13 +421,13 @@
421
421
  "@deno/shim-crypto": "0.3.1",
422
422
  "@types/react": "19.2.14",
423
423
  "@types/react-dom": "19.2.3",
424
- "@veryfront/ext-bundler-esbuild": "0.1.1197",
425
- "@veryfront/ext-content-mdx": "0.1.1197",
426
- "@veryfront/ext-css-tailwind": "0.1.1197",
427
- "@veryfront/ext-dev-ui-react": "0.1.1197",
428
- "@veryfront/ext-node-websocket-ws": "0.1.1197",
429
- "@veryfront/ext-parser-babel": "0.1.1197",
430
- "@veryfront/ext-yaml": "0.1.1197"
424
+ "@veryfront/ext-bundler-esbuild": "0.1.1199",
425
+ "@veryfront/ext-content-mdx": "0.1.1199",
426
+ "@veryfront/ext-css-tailwind": "0.1.1199",
427
+ "@veryfront/ext-dev-ui-react": "0.1.1199",
428
+ "@veryfront/ext-node-websocket-ws": "0.1.1199",
429
+ "@veryfront/ext-parser-babel": "0.1.1199",
430
+ "@veryfront/ext-yaml": "0.1.1199"
431
431
  },
432
432
  "devDependencies": {
433
433
  "@types/node": "20.9.0"