veryfront 0.1.831 → 0.1.832

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.832",
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) {
@@ -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,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.831";
2
+ export declare const VERSION = "0.1.832";
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.832";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.831",
3
+ "version": "0.1.832",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",