veryfront 0.1.831 → 0.1.833

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.
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.831",
3
+ "version": "0.1.833",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -1 +1 @@
1
- {"version":3,"file":"html-shell-generator.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-shell-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA2BxE,OAAO,EAGL,aAAa,EACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAqCxD,KAAK,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC;AAmFzE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC1C,KAAK,CAAC,EAAE,cAAc,EACtB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAC5C,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBzC;AAqRD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC1C,KAAK,CAAC,EAAE,cAAc,EACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
1
+ {"version":3,"file":"html-shell-generator.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-shell-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAmCxE,OAAO,EAGL,aAAa,EACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAgDxD,KAAK,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC;AA0FzE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC1C,KAAK,CAAC,EAAE,cAAc,EACtB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAC5C,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBzC;AAqRD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC1C,KAAK,CAAC,EAAE,cAAc,EACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
@@ -5,16 +5,18 @@ import { profilePhase } from "../observability/request-profiler.js";
5
5
  import { serverLogger } from "../utils/logger/logger.js";
6
6
  import { isMarkdownPreview as checkMarkdownPreview } from "../transforms/md/utils.js";
7
7
  import { generateModulePreloadHintsFromManifest, getRouteManifest, } from "../modules/manifest/route-module-manifest.js";
8
- import { getReadyManifestForRenderAsync } from "../release-assets/manifest-cache.js";
8
+ import { getReadyManifestForRenderAsync, isReleaseAssetManifestEnabled, } from "../release-assets/manifest-cache.js";
9
+ import { RELEASE_MODULE_RUNTIME_VERSION_PARAM, RELEASE_MODULE_VERSION_PARAM, } from "../release-assets/constants.js";
9
10
  import { resolveManifestModuleUrl, resolveManifestRoutePreloadUrls, } from "../release-assets/html-consumption.js";
10
11
  import { routeForPage } from "../release-assets/route-path.js";
12
+ import { VERSION } from "../utils/version.js";
11
13
  import { buildNonceAttribute, escapeHTML } from "./html-escape.js";
12
14
  import { generateHydrationData, getDevScripts, getProdHydrationModulePath, getProdScripts, } from "./hydration-script-builder/index.js";
13
15
  import { getPreviewStylesheetLink, getStudioScripts } from "./dev-scripts.js";
14
16
  import { processMetadata } from "./metadata-builder.js";
15
17
  import { extractCandidates, getDevStyles as getErrorOverlayStyles, getProjectCSS, } from "./styles-builder/index.js";
16
18
  import { buildImportMap, buildRootAttributes, shouldDisableLayout } from "./utils.js";
17
- function pathToModuleUrl(path, studioEmbed, manifest) {
19
+ function pathToModuleUrl(path, studioEmbed, manifest, fallbackReleaseId) {
18
20
  if (!path)
19
21
  return "";
20
22
  // Manifest hit → content-addressed asset URL (production only; never in
@@ -28,7 +30,17 @@ function pathToModuleUrl(path, studioEmbed, manifest) {
28
30
  const urlBase = withExtReplaced === path && !path.endsWith(".js")
29
31
  ? `/_vf_modules/${path}.js`
30
32
  : `/_vf_modules/${withExtReplaced}`;
31
- return studioEmbed ? `${urlBase}?studio_embed=true` : urlBase;
33
+ if (studioEmbed)
34
+ return `${urlBase}?studio_embed=true`;
35
+ return fallbackReleaseId ? appendReleaseModuleVersion(urlBase, fallbackReleaseId) : urlBase;
36
+ }
37
+ function appendReleaseModuleVersion(url, releaseId) {
38
+ const separator = url.includes("?") ? "&" : "?";
39
+ const params = new URLSearchParams({
40
+ [RELEASE_MODULE_VERSION_PARAM]: releaseId,
41
+ [RELEASE_MODULE_RUNTIME_VERSION_PARAM]: VERSION,
42
+ });
43
+ return `${url}${separator}${params.toString()}`;
32
44
  }
33
45
  function getRelativePagePath(fullPath, projectDir) {
34
46
  if (!fullPath)
@@ -46,6 +58,10 @@ function generateModulePreloadHints(options, releaseManifest) {
46
58
  const addedUrls = new Set();
47
59
  const projectDir = options.projectDir ?? "";
48
60
  const studioEmbed = options.studioEmbed;
61
+ const fallbackReleaseId = !studioEmbed && !releaseManifest && options.releaseId &&
62
+ isReleaseAssetManifestEnabled()
63
+ ? options.releaseId
64
+ : undefined;
49
65
  function addHint(moduleUrl) {
50
66
  if (!moduleUrl || addedUrls.has(moduleUrl))
51
67
  return;
@@ -54,14 +70,14 @@ function generateModulePreloadHints(options, releaseManifest) {
54
70
  }
55
71
  if (options.pagePath) {
56
72
  const relativePath = getRelativePagePath(options.pagePath, projectDir);
57
- addHint(pathToModuleUrl(relativePath, studioEmbed, releaseManifest));
73
+ addHint(pathToModuleUrl(relativePath, studioEmbed, releaseManifest, fallbackReleaseId));
58
74
  }
59
75
  for (const layout of options.nestedLayouts ?? []) {
60
76
  const layoutPath = layout.path ?? layout.componentPath ?? "";
61
77
  if (!layoutPath)
62
78
  continue;
63
79
  const relativePath = getRelativePagePath(layoutPath, projectDir);
64
- addHint(pathToModuleUrl(relativePath, studioEmbed, releaseManifest));
80
+ addHint(pathToModuleUrl(relativePath, studioEmbed, releaseManifest, fallbackReleaseId));
65
81
  }
66
82
  // Skip manifest-based preloads in preview/studio-embed mode:
67
83
  // HMR reloads modules with ?t=timestamp, so preloaded versions won't match
@@ -90,10 +106,13 @@ function generateModulePreloadHints(options, releaseManifest) {
90
106
  if (!manifest || manifest.renderCount <= 0)
91
107
  return hints.join("\n ");
92
108
  for (const hint of generateModulePreloadHintsFromManifest(projectSlug, legacyModuleManifestRoute, 50)) {
93
- const href = hint.match(/href="([^"]+)"/)?.[1];
109
+ const rawHref = hint.match(/href="([^"]+)"/)?.[1];
110
+ const href = rawHref && fallbackReleaseId && rawHref.startsWith("/_vf_modules/")
111
+ ? appendReleaseModuleVersion(rawHref, fallbackReleaseId)
112
+ : rawHref;
94
113
  if (!href || addedUrls.has(href))
95
114
  continue;
96
- hints.push(hint);
115
+ hints.push(href === rawHref ? hint : hint.replace(/href="([^"]+)"/, `href="${href}"`));
97
116
  addedUrls.add(href);
98
117
  }
99
118
  return hints.join("\n ");
@@ -1 +1 @@
1
- {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAuCtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAwDrD,CAAC;AAiBF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8XzF;AAwWD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
1
+ {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AA6CtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAwDrD,CAAC;AA4DF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+XzF;AAwWD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
@@ -15,11 +15,13 @@ import { injectNodePositions } from "../../transforms/plugins/babel-node-positio
15
15
  import { parseProjectDomain } from "../../server/utils/domain-parser.js";
16
16
  import { applySSRImportRewritesAsync, resolveSSRImportTargetModulePath, stripSSRModuleJsExtension, } from "./ssr-import-rewriter.js";
17
17
  import { addHMRTimestamps } from "../../transforms/esm/import-rewriter.js";
18
+ import { replaceSpecifiers } from "../../transforms/esm/lexer.js";
18
19
  import { FRAMEWORK_ROOT, resolveFrameworkSourcePath, } from "../../platform/compat/framework-source-resolver.js";
19
20
  import { getReactUrls, REACT_DEFAULT_VERSION } from "../../utils/constants/cdn.js";
20
21
  import { readLimitedCrossProjectSource } from "./cross-project-source-limit.js";
21
22
  import { sha256Short } from "../../cache/hash.js";
22
23
  import { rewriteReleaseDependencyImportsForModule } from "../../release-assets/module-consumption.js";
24
+ import { RELEASE_ASSET_IMMUTABLE_MAX_AGE_SECONDS, RELEASE_MODULE_RUNTIME_VERSION_PARAM, RELEASE_MODULE_VERSION_PARAM, } from "../../release-assets/constants.js";
23
25
  import { buildSourceMissCacheKey, hasSourceMiss, rememberSourceMiss, } from "./module-source-resolution-cache.js";
24
26
  import { ensureFilenameDefaultExport } from "../loader-shared/filename-default-export.js";
25
27
  const logger = serverLogger.component("module-server");
@@ -96,6 +98,37 @@ const SNIPPET_MODULE_PREFIX = /^\/_vf_modules\/_snippets\/([a-f0-9]+)\.js/;
96
98
  // Cross-project import patterns: /_vf_modules/_cross/<slug>[@<version>]/@/<path>
97
99
  const CROSS_PROJECT_VERSIONED_PREFIX = /^\/_vf_modules\/_cross\/([a-z0-9-]+)@([\d^~x][\d.x^~-]*)\/\@\/(.+)$/;
98
100
  const CROSS_PROJECT_LATEST_PREFIX = /^\/_vf_modules\/_cross\/([a-z0-9-]+)\/\@\/(.+)$/;
101
+ function appendReleaseModuleVersion(url, releaseId) {
102
+ if (url.includes(`${RELEASE_MODULE_VERSION_PARAM}=`) ||
103
+ url.includes(`${RELEASE_MODULE_RUNTIME_VERSION_PARAM}=`)) {
104
+ return url;
105
+ }
106
+ const separator = url.includes("?") ? "&" : "?";
107
+ const params = new URLSearchParams({
108
+ [RELEASE_MODULE_VERSION_PARAM]: releaseId,
109
+ [RELEASE_MODULE_RUNTIME_VERSION_PARAM]: VERSION,
110
+ });
111
+ return `${url}${separator}${params.toString()}`;
112
+ }
113
+ function shouldCacheReleaseVersionedModule(url, options, isSSR) {
114
+ if (options.dev || isSSR || !options.releaseId)
115
+ return false;
116
+ return url.searchParams.get(RELEASE_MODULE_VERSION_PARAM) === options.releaseId &&
117
+ url.searchParams.get(RELEASE_MODULE_RUNTIME_VERSION_PARAM) === VERSION;
118
+ }
119
+ function isSSRModuleRequest(req, url) {
120
+ const userAgent = req.headers.get("user-agent") ?? "";
121
+ return url.searchParams.get("ssr") === "true" || userAgent.startsWith("Deno/");
122
+ }
123
+ async function addReleaseVersionToFallbackImports(code, releaseId) {
124
+ if (!releaseId || !code.includes("/_vf_modules/"))
125
+ return code;
126
+ return await replaceSpecifiers(code, (specifier) => {
127
+ if (!specifier.startsWith("/_vf_modules/"))
128
+ return null;
129
+ return appendReleaseModuleVersion(specifier, releaseId);
130
+ });
131
+ }
99
132
  /** Serve transformed module at /_vf_modules/* path */
100
133
  export function serveModule(req, options) {
101
134
  const url = new URL(req.url);
@@ -152,8 +185,7 @@ export function serveModule(req, options) {
152
185
  });
153
186
  }
154
187
  const { slug: snippetProjectSlug, branch: snippetBranch } = parseProjectDomain(url.host);
155
- const userAgent = req.headers.get("user-agent") ?? "";
156
- const isSSR = url.searchParams.get("ssr") === "true" || userAgent.startsWith("Deno/");
188
+ const isSSR = isSSRModuleRequest(req, url);
157
189
  logger.debug("Transforming snippet", {
158
190
  hash,
159
191
  isSSR,
@@ -231,8 +263,7 @@ export function serveModule(req, options) {
231
263
  "Cache-Control": "no-cache",
232
264
  });
233
265
  }
234
- const userAgent = req.headers.get("user-agent") ?? "";
235
- const isSSR = url.searchParams.get("ssr") === "true" || userAgent.startsWith("Deno/");
266
+ const isSSR = isSSRModuleRequest(req, url);
236
267
  let code = await profileModuleTransform(() => transformToESM(source, crossPath, projectDir, adapter, {
237
268
  projectId: effectiveProjectId,
238
269
  dev,
@@ -325,7 +356,7 @@ export function serveModule(req, options) {
325
356
  : await secureFs.readFile(sourceFile);
326
357
  }
327
358
  const userAgent = req.headers.get("user-agent") ?? "";
328
- const isSSR = url.searchParams.get("ssr") === "true" || userAgent.startsWith("Deno/");
359
+ const isSSR = isSSRModuleRequest(req, url);
329
360
  const studioEmbed = url.searchParams.get("studio_embed") === "true";
330
361
  const shouldInjectPositions = dev || options.mode === "preview";
331
362
  const isJsxFile = /\.(tsx|jsx)$/i.test(sourceFile);
@@ -379,9 +410,12 @@ export function serveModule(req, options) {
379
410
  releaseId: options.releaseId,
380
411
  readDependencySource: (path) => platformFs.readTextFile(path),
381
412
  });
413
+ code = await addReleaseVersionToFallbackImports(code, options.releaseId);
382
414
  }
383
415
  }
384
- const headers = getDevModuleHeaders(modulePath);
416
+ const headers = getModuleHeaders(modulePath, {
417
+ cacheable: shouldCacheReleaseVersionedModule(url, options, isSSRModuleRequest(req, url)),
418
+ });
385
419
  logger.debug("Request complete", {
386
420
  path: modulePath,
387
421
  durationMs: (performance.now() - startTime).toFixed(1),
@@ -391,7 +425,7 @@ export function serveModule(req, options) {
391
425
  catch (error) {
392
426
  const errorMsg = getErrorMessage(error);
393
427
  logger.error("Module transform error", { modulePath, error: errorMsg });
394
- const headers = getDevModuleHeaders(modulePath);
428
+ const headers = getModuleHeaders(modulePath);
395
429
  const errorBody = createDevModuleErrorBody(modulePath, errorMsg);
396
430
  return createModuleResponse(method, errorBody, HTTP_SERVER_ERROR, headers);
397
431
  }
@@ -671,10 +705,12 @@ export function isModuleRequest(req) {
671
705
  const url = new URL(req.url);
672
706
  return DEV_MODULE_PREFIX.test(url.pathname);
673
707
  }
674
- function getDevModuleHeaders(modulePath) {
708
+ function getModuleHeaders(modulePath, options = {}) {
675
709
  return {
676
710
  "Content-Type": getDevModuleContentType(modulePath),
677
- "Cache-Control": "no-cache",
711
+ "Cache-Control": options.cacheable
712
+ ? `public, max-age=${RELEASE_ASSET_IMMUTABLE_MAX_AGE_SECONDS}, immutable`
713
+ : "no-cache",
678
714
  };
679
715
  }
680
716
  function getDevModuleContentType(modulePath) {
@@ -38,6 +38,7 @@ import { handleReleaseAssetRequest, isReleaseAssetPath } from "./asset-handler.j
38
38
  import { runProxyRequestLifecycle } from "./request-lifecycle.js";
39
39
  import { createUpstreamFailureResponse, createUpstreamTimeoutResponse, UPSTREAM_FAILURE_STATUS, UPSTREAM_TIMEOUT_STATUS, } from "./upstream-error-response.js";
40
40
  import { createProxyServerTiming, markProxyServerTimingPhase, profileProxyServerTimingPhase, withProxyServerTimingHeader, } from "./server-timing.js";
41
+ import { removeStickyCookieFromPublicCacheableResponse } from "./response-headers.js";
41
42
  function getLocalProjects() {
42
43
  const raw = getEnv("LOCAL_PROJECTS");
43
44
  return raw ? JSON.parse(raw) : {};
@@ -335,11 +336,11 @@ function forwardToServer(req, url) {
335
336
  else {
336
337
  reqLogger.info(`${response.status} ${req.method} ${url.pathname}`, { ms });
337
338
  }
338
- return withProxyTiming(new Response(response.body, {
339
+ return withProxyTiming(removeStickyCookieFromPublicCacheableResponse(new Response(response.body, {
339
340
  status: response.status,
340
341
  statusText: response.statusText,
341
342
  headers: response.headers,
342
- }));
343
+ })));
343
344
  }
344
345
  catch (error) {
345
346
  clearTimeout(timeoutId);
@@ -0,0 +1,2 @@
1
+ export declare function removeStickyCookieFromPublicCacheableResponse(response: Response): Response;
2
+ //# sourceMappingURL=response-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-headers.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/response-headers.ts"],"names":[],"mappings":"AA+DA,wBAAgB,6CAA6C,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAkB1F"}
@@ -0,0 +1,74 @@
1
+ const STICKY_COOKIE_NAME = "lb";
2
+ function parseCacheControl(cacheControl) {
3
+ const directives = new Map();
4
+ if (!cacheControl)
5
+ return directives;
6
+ for (const part of cacheControl.split(",")) {
7
+ const trimmed = part.trim();
8
+ if (!trimmed)
9
+ continue;
10
+ const [rawName, rawValue] = trimmed.split("=", 2);
11
+ const name = rawName?.trim().toLowerCase();
12
+ if (!name)
13
+ continue;
14
+ directives.set(name, rawValue === undefined ? true : rawValue.trim().replace(/^"|"$/g, ""));
15
+ }
16
+ return directives;
17
+ }
18
+ function readPositiveDirectiveSeconds(directives, name) {
19
+ const value = directives.get(name);
20
+ if (typeof value !== "string")
21
+ return 0;
22
+ const seconds = Number(value);
23
+ return Number.isFinite(seconds) && seconds > 0 ? seconds : 0;
24
+ }
25
+ function isPublicCacheable(headers) {
26
+ const directives = parseCacheControl(headers.get("cache-control"));
27
+ if (!directives.has("public"))
28
+ return false;
29
+ if (directives.has("private") || directives.has("no-store") || directives.has("no-cache")) {
30
+ return false;
31
+ }
32
+ return directives.has("immutable") ||
33
+ readPositiveDirectiveSeconds(directives, "s-maxage") > 0 ||
34
+ readPositiveDirectiveSeconds(directives, "max-age") > 0;
35
+ }
36
+ function readSetCookies(headers) {
37
+ const getSetCookie = headers.getSetCookie;
38
+ if (typeof getSetCookie === "function") {
39
+ const values = getSetCookie.call(headers);
40
+ if (values.length > 0)
41
+ return values;
42
+ }
43
+ const values = [];
44
+ for (const [key, value] of headers) {
45
+ if (key.toLowerCase() === "set-cookie")
46
+ values.push(value);
47
+ }
48
+ const directValue = headers.get("set-cookie");
49
+ if (values.length === 0 && directValue)
50
+ values.push(directValue);
51
+ return values;
52
+ }
53
+ function isStickyCookie(setCookie) {
54
+ const [name] = setCookie.split("=", 1);
55
+ return name?.trim().toLowerCase() === STICKY_COOKIE_NAME;
56
+ }
57
+ export function removeStickyCookieFromPublicCacheableResponse(response) {
58
+ if (!isPublicCacheable(response.headers))
59
+ return response;
60
+ const setCookies = readSetCookies(response.headers);
61
+ if (setCookies.length === 0 || !setCookies.some(isStickyCookie))
62
+ return response;
63
+ const headers = new Headers(response.headers);
64
+ headers.delete("set-cookie");
65
+ for (const setCookie of setCookies) {
66
+ if (!isStickyCookie(setCookie))
67
+ headers.append("Set-Cookie", setCookie);
68
+ }
69
+ return new Response(response.body, {
70
+ status: response.status,
71
+ statusText: response.statusText,
72
+ headers,
73
+ });
74
+ }
@@ -20,6 +20,10 @@ export declare const RELEASE_ASSET_CONTENT_TYPE_ALLOWLIST: readonly ReleaseAsset
20
20
  export declare const RELEASE_ASSET_MAX_SIZE_BYTES: number;
21
21
  /** Immutable cache max-age in seconds (1 year). */
22
22
  export declare const RELEASE_ASSET_IMMUTABLE_MAX_AGE_SECONDS = 31536000;
23
+ /** Query param that scopes fallback module URLs to an immutable release. */
24
+ export declare const RELEASE_MODULE_VERSION_PARAM: "vf_release";
25
+ /** Query param that scopes fallback module URLs to the Veryfront runtime build. */
26
+ export declare const RELEASE_MODULE_RUNTIME_VERSION_PARAM: "vf_runtime";
23
27
  /** Bounded upload concurrency when posting assets during a build. */
24
28
  export declare const RELEASE_ASSET_UPLOAD_CONCURRENCY = 8;
25
29
  /** Env flag that enables HTML manifest consumption in production (default OFF). */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/src/release-assets/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4CAA4C;AAC5C,eAAO,MAAM,qCAAqC,EAAG,CAAU,CAAC;AAEhE,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,EAAG,aAAsB,CAAC;AAE9D,kDAAkD;AAClD,eAAO,MAAM,2BAA2B;;;CAG9B,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,2BAA2B,CAAC;AAC7E,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,qBAAqB,CAAC,CAAC;AAElG,0EAA0E;AAC1E,eAAO,MAAM,oCAAoC,EAAE,SAAS,uBAAuB,EAGlF,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D,mDAAmD;AACnD,eAAO,MAAM,uCAAuC,WAAa,CAAC;AAElE,qEAAqE;AACrE,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,mFAAmF;AACnF,eAAO,MAAM,+BAA+B,qCAAqC,CAAC;AAElF,mFAAmF;AACnF,eAAO,MAAM,4CAA4C,kDACR,CAAC;AAElD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,GAAG,MAAM,CAE7F;AAED,yEAAyE;AACzE,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAIhC;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,KAAK,IAAI,uBAAuB,CAIlC;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/src/release-assets/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4CAA4C;AAC5C,eAAO,MAAM,qCAAqC,EAAG,CAAU,CAAC;AAEhE,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,EAAG,aAAsB,CAAC;AAE9D,kDAAkD;AAClD,eAAO,MAAM,2BAA2B;;;CAG9B,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,2BAA2B,CAAC;AAC7E,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,qBAAqB,CAAC,CAAC;AAElG,0EAA0E;AAC1E,eAAO,MAAM,oCAAoC,EAAE,SAAS,uBAAuB,EAGlF,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D,mDAAmD;AACnD,eAAO,MAAM,uCAAuC,WAAa,CAAC;AAElE,4EAA4E;AAC5E,eAAO,MAAM,4BAA4B,EAAG,YAAqB,CAAC;AAElE,mFAAmF;AACnF,eAAO,MAAM,oCAAoC,EAAG,YAAqB,CAAC;AAE1E,qEAAqE;AACrE,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,mFAAmF;AACnF,eAAO,MAAM,+BAA+B,qCAAqC,CAAC;AAElF,mFAAmF;AACnF,eAAO,MAAM,4CAA4C,kDACR,CAAC;AAElD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,GAAG,MAAM,CAE7F;AAED,yEAAyE;AACzE,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAIhC;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,KAAK,IAAI,uBAAuB,CAIlC;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD"}
@@ -21,6 +21,10 @@ export const RELEASE_ASSET_CONTENT_TYPE_ALLOWLIST = [
21
21
  export const RELEASE_ASSET_MAX_SIZE_BYTES = 10 * 1024 * 1024;
22
22
  /** Immutable cache max-age in seconds (1 year). */
23
23
  export const RELEASE_ASSET_IMMUTABLE_MAX_AGE_SECONDS = 31_536_000;
24
+ /** Query param that scopes fallback module URLs to an immutable release. */
25
+ export const RELEASE_MODULE_VERSION_PARAM = "vf_release";
26
+ /** Query param that scopes fallback module URLs to the Veryfront runtime build. */
27
+ export const RELEASE_MODULE_RUNTIME_VERSION_PARAM = "vf_runtime";
24
28
  /** Bounded upload concurrency when posting assets during a build. */
25
29
  export const RELEASE_ASSET_UPLOAD_CONCURRENCY = 8;
26
30
  /** Env flag that enables HTML manifest consumption in production (default OFF). */
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-cache.d.ts","sourceRoot":"","sources":["../../../src/src/release-assets/manifest-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,EAA6B,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAmC5F;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAC1B;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAChE,CAAC;CACH;AAKD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,2BAA2B,GACnC,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,2BAA2B,GAAG,SAAS,GAC/C,IAAI,CAMN;AASD,yEAAyE;AACzE,wBAAgB,6BAA6B,IAAI,OAAO,CAKvD;AA6BD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,oBAAoB,GAAG,IAAI,CAoB7B;AAED;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAetC;AAqED,6EAA6E;AAC7E,wBAAgB,gCAAgC,IAAI,IAAI,CAIvD;AAED,uEAAuE;AACvE,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
1
+ {"version":3,"file":"manifest-cache.d.ts","sourceRoot":"","sources":["../../../src/src/release-assets/manifest-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAWH,OAAO,EAA6B,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAmC5F;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAC1B;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAChE,CAAC;CACH;AAKD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,2BAA2B,GACnC,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,2BAA2B,GAAG,SAAS,GAC/C,IAAI,CAMN;AASD,yEAAyE;AACzE,wBAAgB,6BAA6B,IAAI,OAAO,CAKvD;AAiCD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,oBAAoB,GAAG,IAAI,CAgC7B;AAED;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA4BtC;AA+ED,6EAA6E;AAC7E,wBAAgB,gCAAgC,IAAI,IAAI,CAIvD;AAED,uEAAuE;AACvE,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
@@ -26,6 +26,7 @@ import { serverLogger } from "../utils/index.js";
26
26
  import { LRUCache } from "../utils/lru-wrapper.js";
27
27
  import { registerLRUCache } from "../cache/index.js";
28
28
  import { getHostEnv } from "../platform/compat/process.js";
29
+ import { markRequestProfilePhase, profilePhase, } from "../observability/request-profiler.js";
29
30
  import { RELEASE_ASSET_MANIFEST_ENV_FLAG } from "./constants.js";
30
31
  import { parseReleaseAssetManifest } from "./manifest-schema.js";
31
32
  const logger = serverLogger.component("release-asset-manifest");
@@ -92,6 +93,9 @@ export function isReleaseAssetManifestEnabled() {
92
93
  function cacheKey(releaseId, manifestVersion) {
93
94
  return manifestVersion !== undefined ? `${releaseId}:${manifestVersion}` : releaseId;
94
95
  }
96
+ function markManifestDecision(decision) {
97
+ markRequestProfilePhase(`release_manifest.${decision}`);
98
+ }
95
99
  function findCachedReadyEntry(releaseId) {
96
100
  let best = null;
97
101
  for (const [k, v] of manifestCache.entries()) {
@@ -121,14 +125,21 @@ function maybeScheduleReadyRefresh(releaseId, entry) {
121
125
  * the flag is off or no fetcher is registered for this releaseId.
122
126
  */
123
127
  export function getReadyManifestForRender(releaseId) {
124
- if (!releaseId)
128
+ if (!releaseId) {
129
+ markManifestDecision("no_release_id");
125
130
  return null;
126
- if (!isReleaseAssetManifestEnabled())
131
+ }
132
+ if (!isReleaseAssetManifestEnabled()) {
133
+ markManifestDecision("disabled");
127
134
  return null;
128
- if (!resolveFetcher(releaseId))
135
+ }
136
+ if (!resolveFetcher(releaseId)) {
137
+ markManifestDecision("no_fetcher");
129
138
  return null;
139
+ }
130
140
  const best = findCachedReadyEntry(releaseId);
131
141
  if (best) {
142
+ markManifestDecision("cached_ready");
132
143
  maybeScheduleReadyRefresh(releaseId, best);
133
144
  return best.manifest;
134
145
  }
@@ -136,8 +147,10 @@ export function getReadyManifestForRender(releaseId) {
136
147
  const plain = manifestCache.get(releaseId);
137
148
  if (plain && plain.expiresAt > Date.now()) {
138
149
  // Non-ready entry still warm — return null without scheduling another fetch.
150
+ markManifestDecision("cached_null");
139
151
  return null;
140
152
  }
153
+ markManifestDecision("cache_miss");
141
154
  scheduleFetch(releaseId);
142
155
  return null;
143
156
  }
@@ -150,20 +163,29 @@ export function getReadyManifestForRender(releaseId) {
150
163
  * manifest is unavailable, or the fetch fails.
151
164
  */
152
165
  export async function getReadyManifestForRenderAsync(releaseId) {
153
- if (!releaseId)
166
+ if (!releaseId) {
167
+ markManifestDecision("no_release_id");
154
168
  return null;
155
- if (!isReleaseAssetManifestEnabled())
169
+ }
170
+ if (!isReleaseAssetManifestEnabled()) {
171
+ markManifestDecision("disabled");
156
172
  return null;
157
- if (!resolveFetcher(releaseId))
173
+ }
174
+ if (!resolveFetcher(releaseId)) {
175
+ markManifestDecision("no_fetcher");
158
176
  return null;
177
+ }
159
178
  const best = findCachedReadyEntry(releaseId);
160
179
  if (best) {
180
+ markManifestDecision("cached_ready");
161
181
  maybeScheduleReadyRefresh(releaseId, best);
162
182
  return best.manifest;
163
183
  }
164
184
  const plain = manifestCache.get(releaseId);
165
- if (plain && plain.expiresAt > Date.now())
185
+ if (plain && plain.expiresAt > Date.now()) {
186
+ markManifestDecision("cached_null");
166
187
  return null;
188
+ }
167
189
  return await fetchManifest(releaseId);
168
190
  }
169
191
  function scheduleFetch(releaseId) {
@@ -171,19 +193,24 @@ function scheduleFetch(releaseId) {
171
193
  }
172
194
  function fetchManifest(releaseId) {
173
195
  const existing = inFlight.get(releaseId);
174
- if (existing)
196
+ if (existing) {
197
+ markManifestDecision("await_inflight");
175
198
  return existing.promise;
199
+ }
176
200
  const active = resolveFetcher(releaseId);
177
- if (!active)
201
+ if (!active) {
202
+ markManifestDecision("no_fetcher");
178
203
  return Promise.resolve(null);
204
+ }
179
205
  const fetchGeneration = cacheGeneration;
180
206
  const token = Symbol(releaseId);
181
- const promise = Promise.resolve().then(async () => {
207
+ const promise = profilePhase("release_manifest.fetch", async () => {
182
208
  try {
183
209
  const result = await active(releaseId);
184
210
  if (fetchGeneration !== cacheGeneration)
185
211
  return null;
186
212
  if (!result) {
213
+ markManifestDecision("fetch_missing");
187
214
  manifestCache.set(releaseId, { manifest: null, expiresAt: Date.now() + NON_READY_TTL_MS });
188
215
  return null;
189
216
  }
@@ -191,6 +218,7 @@ function fetchManifest(releaseId) {
191
218
  ? parseReleaseAssetManifest(result.manifest)
192
219
  : null;
193
220
  if (manifest) {
221
+ markManifestDecision("fetch_ready");
194
222
  const key = cacheKey(releaseId, manifest.manifestVersion);
195
223
  manifestCache.set(key, {
196
224
  manifest,
@@ -206,6 +234,7 @@ function fetchManifest(releaseId) {
206
234
  return manifest;
207
235
  }
208
236
  else {
237
+ markManifestDecision("fetch_not_ready");
209
238
  manifestCache.set(releaseId, {
210
239
  manifest: null,
211
240
  expiresAt: Date.now() + NON_READY_TTL_MS,
@@ -220,6 +249,7 @@ function fetchManifest(releaseId) {
220
249
  });
221
250
  if (fetchGeneration !== cacheGeneration)
222
251
  return null;
252
+ markManifestDecision("fetch_failed");
223
253
  manifestCache.set(releaseId, { manifest: null, expiresAt: Date.now() + NON_READY_TTL_MS });
224
254
  return null;
225
255
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAuBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA+ChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACxE,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrF;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,OAAO,qBAAqB,EAAE,sBAAsB,CAAC;CAC1E;AA0BD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,kBAAkB,CAAqB;gBAEnC,MAAM,EAAE,oBAAoB;IAaxC;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAKxB,OAAO,CAAC,UAAU;YAIJ,0BAA0B;IAaxC;;;;;;;;;OASG;YACW,qBAAqB;IAyDnC;;;OAGG;YACW,mBAAmB;IAiGjC,OAAO,CAAC,uBAAuB;IAkCzB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA2Q9E,+EAA+E;IACzE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAsFzE,kBAAkB;YA2ClB,cAAc;IAW5B,OAAO,CAAC,uBAAuB;YAYjB,kBAAkB;IA8EhC,OAAO,CAAC,kBAAkB;YAQZ,uBAAuB;IAmBrC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;CAStB"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAwBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA+ChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACxE,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrF;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,OAAO,qBAAqB,EAAE,sBAAsB,CAAC;CAC1E;AA0BD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,kBAAkB,CAAqB;gBAEnC,MAAM,EAAE,oBAAoB;IAaxC;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAKxB,OAAO,CAAC,UAAU;YAIJ,0BAA0B;IAaxC;;;;;;;;;OASG;YACW,qBAAqB;IAyDnC;;;OAGG;YACW,mBAAmB;IA8GjC,OAAO,CAAC,uBAAuB;IAkCzB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAsS9E,+EAA+E;IACzE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAiGzE,kBAAkB;YA2ClB,cAAc;IAW5B,OAAO,CAAC,uBAAuB;YAYjB,kBAAkB;IAyFhC,OAAO,CAAC,kBAAkB;YAQZ,uBAAuB;IAmBrC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;CAStB"}
@@ -17,6 +17,7 @@ import { rendererLogger as logger } from "../../utils/index.js";
17
17
  import { getExtensionName } from "../../utils/path-utils.js";
18
18
  import { createBuildVersion } from "../../utils/version.js";
19
19
  import { withSpan } from "../../observability/tracing/otlp-setup.js";
20
+ import { profilePhase } from "../../observability/request-profiler.js";
20
21
  import { SpanNames } from "../../observability/tracing/span-names.js";
21
22
  import { VeryfrontError } from "../../errors/index.js";
22
23
  import { FILE_NOT_FOUND, RENDER_ERROR } from "../../errors/error-registry.js";
@@ -178,12 +179,12 @@ export class RenderPipeline {
178
179
  if (modulesToLoad.length === 0) {
179
180
  return { params, pageProps, layoutProps };
180
181
  }
181
- const loadedModules = await withSpan(SpanNames.RENDER_LOAD_MODULES, () => withTimeoutThrow(this.loadModulesInParallel(modulesToLoad), MODULE_LOAD_TIMEOUT_MS, `Module loading for ${slug}`), { "render.module_count": modulesToLoad.length });
182
+ const loadedModules = await profilePhase("render.load_modules", () => withSpan(SpanNames.RENDER_LOAD_MODULES, () => withTimeoutThrow(this.loadModulesInParallel(modulesToLoad), MODULE_LOAD_TIMEOUT_MS, `Module loading for ${slug}`), { "render.module_count": modulesToLoad.length }));
182
183
  const dataJobs = loadedModules.filter((m) => hasDataFetchingFunction(m.mod));
183
184
  if (dataJobs.length === 0) {
184
185
  return { params, pageProps, layoutProps };
185
186
  }
186
- const dataResults = await withSpan(SpanNames.RENDER_FETCH_DATA, () => withTimeoutThrow(Promise.all(dataJobs.map(async (job) => {
187
+ const dataResults = await profilePhase("render.fetch_data", () => withSpan(SpanNames.RENDER_FETCH_DATA, () => withTimeoutThrow(Promise.all(dataJobs.map(async (job) => {
187
188
  try {
188
189
  const jobPath = job.path;
189
190
  const fetchOptions = {
@@ -197,7 +198,7 @@ export class RenderPipeline {
197
198
  catch (error) {
198
199
  return { ...job, result: null, error: error };
199
200
  }
200
- })), DATA_FETCH_TIMEOUT_MS, `Data fetch for ${slug}`), { "render.data_job_count": dataJobs.length });
201
+ })), DATA_FETCH_TIMEOUT_MS, `Data fetch for ${slug}`), { "render.data_job_count": dataJobs.length }));
201
202
  this.applyFetchedDataResults(slug, dataResults, pageProps, layoutProps);
202
203
  return { params, pageProps, layoutProps };
203
204
  }
@@ -255,13 +256,13 @@ export class RenderPipeline {
255
256
  const renderOnce = () => withSpan("render.page", async () => {
256
257
  const { result } = await runWithCSSCollector(async () => {
257
258
  const pageResolveStart = performance.now();
258
- const pageInfo = await withSpan("render.resolve_page", () => this.config.pageResolver.resolvePage(slug), { "render.slug": slug });
259
+ const pageInfo = await profilePhase("render.resolve_page", () => withSpan("render.resolve_page", () => this.config.pageResolver.resolvePage(slug), { "render.slug": slug }));
259
260
  timing.pageResolve = Math.round(performance.now() - pageResolveStart);
260
261
  const sourceFile = extractRelativePathShared(pageInfo.entity.path, this.config.projectDir);
261
262
  try {
262
263
  const skipLayouts = isDotPath(slug, pageInfo.entity.path);
263
264
  const layoutCollectStart = performance.now();
264
- const layoutResult = skipLayouts ? EMPTY_LAYOUT_RESULT : await withSpan("render.collect_layouts", () => this.config.layoutOrchestrator.collectLayouts(pageInfo), { "render.slug": slug });
265
+ const layoutResult = skipLayouts ? EMPTY_LAYOUT_RESULT : await profilePhase("render.collect_layouts", () => withSpan("render.collect_layouts", () => this.config.layoutOrchestrator.collectLayouts(pageInfo), { "render.slug": slug }));
265
266
  timing.layoutCollect = Math.round(performance.now() - layoutCollectStart);
266
267
  const layoutPreloadPromise = !skipLayouts && layoutResult.nestedLayouts.length > 0
267
268
  ? this.config.layoutOrchestrator.preloadLayoutModules(layoutResult.nestedLayouts)
@@ -273,7 +274,7 @@ export class RenderPipeline {
273
274
  let layoutDataMap = new Map();
274
275
  const dataFetchStart = performance.now();
275
276
  if (options?.request && options?.url) {
276
- await withSpan("render.data_fetching", async () => {
277
+ await profilePhase("render.data_fetching", () => withSpan("render.data_fetching", async () => {
277
278
  try {
278
279
  const dataResolution = await this.resolveDataFetching(slug, pageInfo.entity.path, layoutResult.nestedLayouts, options);
279
280
  resolvedParams = dataResolution.params;
@@ -291,7 +292,7 @@ export class RenderPipeline {
291
292
  });
292
293
  throw error;
293
294
  }
294
- }, { "render.slug": slug });
295
+ }, { "render.slug": slug }));
295
296
  }
296
297
  timing.dataFetch = Math.round(performance.now() - dataFetchStart);
297
298
  const hasResolvedParams = Object.keys(resolvedParams).length > 0;
@@ -305,7 +306,7 @@ export class RenderPipeline {
305
306
  }
306
307
  : options;
307
308
  const bundlePrepStart = performance.now();
308
- const pageBundleResult = await withSpan("render.prepare_bundles", () => this.config.pageRenderer.preparePageBundles(pageInfo, slug, cacheResult?.cachedModule, mergedOptions), { "render.slug": slug });
309
+ const pageBundleResult = await profilePhase("render.prepare_bundles", () => withSpan("render.prepare_bundles", () => this.config.pageRenderer.preparePageBundles(pageInfo, slug, cacheResult?.cachedModule, mergedOptions), { "render.slug": slug }));
309
310
  timing.bundlePrep = Math.round(performance.now() - bundlePrepStart);
310
311
  if (pageBundleResult.scriptResult)
311
312
  return pageBundleResult.scriptResult;
@@ -323,13 +324,16 @@ export class RenderPipeline {
323
324
  const headings = pageBundle.headings || [];
324
325
  await layoutPreloadPromise;
325
326
  const layoutApplyStart = performance.now();
326
- const wrappedElement = await withSpan("render.apply_layouts", () => this.config.layoutOrchestrator.applyLayoutsAndWrappers(pageElement, pageInfo, layoutResult.layoutBundle, layoutResult.nestedLayouts, layoutDataMap, options?.url, resolvedParams, mergedFrontmatter, headings, options?.projectSlug), { "render.slug": slug, "render.layout_count": layoutResult.nestedLayouts.length });
327
+ const wrappedElement = await profilePhase("render.apply_layouts", () => withSpan("render.apply_layouts", () => this.config.layoutOrchestrator.applyLayoutsAndWrappers(pageElement, pageInfo, layoutResult.layoutBundle, layoutResult.nestedLayouts, layoutDataMap, options?.url, resolvedParams, mergedFrontmatter, headings, options?.projectSlug), {
328
+ "render.slug": slug,
329
+ "render.layout_count": layoutResult.nestedLayouts.length,
330
+ }));
327
331
  timing.layoutApply = Math.round(performance.now() - layoutApplyStart);
328
332
  // Snapshot CSS imports collected during module loading (before SSR rendering).
329
333
  // These are passed to the HTML generator to be included in the output.
330
334
  const collectedCSSImports = getCSSImports();
331
335
  const ssrStart = performance.now();
332
- const ssrResult = await withSpan("render.ssr", () => withTimeoutThrow(this.config.ssrOrchestrator.performSSRRendering(wrappedElement, {
336
+ const ssrResult = await profilePhase("render.ssr", () => withSpan("render.ssr", () => withTimeoutThrow(this.config.ssrOrchestrator.performSSRRendering(wrappedElement, {
333
337
  pageInfo,
334
338
  pageBundle,
335
339
  layoutBundle: layoutResult.layoutBundle,
@@ -337,7 +341,7 @@ export class RenderPipeline {
337
341
  collectedMetadata: pageBundleResult.collectedMetadata,
338
342
  slug,
339
343
  cssImports: collectedCSSImports,
340
- }, mergedOptions), SSR_RENDER_TIMEOUT_MS, `SSR rendering for ${slug}`), { "render.slug": slug, "render.delivery": mergedOptions?.delivery || "full" });
344
+ }, mergedOptions), SSR_RENDER_TIMEOUT_MS, `SSR rendering for ${slug}`), { "render.slug": slug, "render.delivery": mergedOptions?.delivery || "full" }));
341
345
  timing.ssr = Math.round(performance.now() - ssrStart);
342
346
  if (collectedCSSImports.length > 0) {
343
347
  renderPipelineLog.debug("CSS imports collected for HTML generation", {
@@ -411,24 +415,22 @@ export class RenderPipeline {
411
415
  if (this.config.mode === "development") {
412
416
  clearSSRModuleCacheForProject(projectId);
413
417
  }
414
- const pageInfo = await this.config.pageResolver.resolvePage(slug);
418
+ const pageInfo = await profilePhase("page_data.resolve_page", () => this.config.pageResolver.resolvePage(slug));
415
419
  const skipLayouts = isDotPath(slug, pageInfo.entity.path);
416
- const layoutResult = skipLayouts
417
- ? EMPTY_LAYOUT_RESULT
418
- : await this.config.layoutOrchestrator.collectLayouts(pageInfo);
420
+ const layoutResult = skipLayouts ? EMPTY_LAYOUT_RESULT : await profilePhase("page_data.collect_layouts", () => this.config.layoutOrchestrator.collectLayouts(pageInfo));
419
421
  const pagePath = extractRelativePathShared(pageInfo.entity.path, this.config.projectDir);
420
422
  const fileExtension = getExtensionName(pageInfo.entity.path);
421
423
  const pageType = fileExtension;
422
- const dataResolution = await this.resolveDataFetching(slug, pageInfo.entity.path, layoutResult.nestedLayouts, options);
424
+ const dataResolution = await profilePhase("page_data.resolve_data", () => this.resolveDataFetching(slug, pageInfo.entity.path, layoutResult.nestedLayouts, options));
423
425
  const pageProps = dataResolution.pageProps;
424
426
  const params = dataResolution.params;
425
427
  const layoutProps = serializeLayoutProps(dataResolution.layoutProps);
426
- const { frontmatter, headings } = await this.extractMdxMetadata(pageType, pageInfo, slug, options, params);
428
+ const { frontmatter, headings } = await profilePhase("page_data.extract_mdx_metadata", () => this.extractMdxMetadata(pageType, pageInfo, slug, options, params));
427
429
  const layouts = serializeLayouts(layoutResult.nestedLayouts, this.config.projectDir);
428
430
  const providers = [];
429
431
  const projectUpdatedAt = this.resolveProjectUpdatedAt();
430
- const appPath = await this.resolveAppPath();
431
- const { css, cssAction, cssError } = await this.resolvePageDataCss(slug, options, projectUpdatedAt);
432
+ const appPath = await profilePhase("page_data.resolve_app_path", () => this.resolveAppPath());
433
+ const { css, cssAction, cssError } = await profilePhase("page_data.resolve_css", () => this.resolvePageDataCss(slug, options, projectUpdatedAt));
432
434
  resolvePageDataLog.debug("Resolved page data", {
433
435
  slug,
434
436
  pagePath,
@@ -515,17 +517,17 @@ export class RenderPipeline {
515
517
  return { css: cachedCss, cssAction: undefined, cssError: undefined };
516
518
  }
517
519
  try {
518
- const renderResult = await withTimeout(this.renderPage(slug, {
520
+ const renderResult = await profilePhase("page_data.css.render_html", () => withTimeout(this.renderPage(slug, {
519
521
  ...options,
520
522
  delivery: "string",
521
523
  skipCacheCheck: true,
522
524
  skipCachePersist: true,
523
- }), CSS_SSR_TIMEOUT_MS, `CSS SSR for ${slug}`);
525
+ }), CSS_SSR_TIMEOUT_MS, `CSS SSR for ${slug}`));
524
526
  if (!renderResult?.html) {
525
527
  return { css: undefined, cssAction: undefined, cssError: undefined };
526
528
  }
527
529
  let cssAction;
528
- let css = await this.resolveCssFromRenderedHtml(renderResult.html, options?.projectSlug ?? options?.projectId);
530
+ let css = await profilePhase("page_data.css.extract_from_html", () => this.resolveCssFromRenderedHtml(renderResult.html, options?.projectSlug ?? options?.projectId));
529
531
  if (css) {
530
532
  resolvePageDataLog.debug("Reused SSR CSS for page data", {
531
533
  slug,
@@ -540,7 +542,7 @@ export class RenderPipeline {
540
542
  });
541
543
  }
542
544
  else {
543
- css = await this.generatePageCssFromHtml(slug, renderResult.html, options);
545
+ css = await profilePhase("page_data.css.generate_from_html", () => this.generatePageCssFromHtml(slug, renderResult.html, options));
544
546
  }
545
547
  if (css)
546
548
  cachePageCss(cssCacheKey, css);
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.831";
2
+ export declare const VERSION = "0.1.833";
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.831";
4
+ export const VERSION = "0.1.833";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.831",
3
+ "version": "0.1.833",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",