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 +1 -1
- package/esm/src/html/html-shell-generator.d.ts.map +1 -1
- package/esm/src/html/html-shell-generator.js +26 -7
- package/esm/src/modules/server/module-server.d.ts.map +1 -1
- package/esm/src/modules/server/module-server.js +45 -9
- package/esm/src/release-assets/constants.d.ts +4 -0
- package/esm/src/release-assets/constants.d.ts.map +1 -1
- package/esm/src/release-assets/constants.js +4 -0
- package/esm/src/release-assets/manifest-cache.d.ts.map +1 -1
- package/esm/src/release-assets/manifest-cache.js +40 -10
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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
|
|
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;
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
708
|
+
function getModuleHeaders(modulePath, options = {}) {
|
|
675
709
|
return {
|
|
676
710
|
"Content-Type": getDevModuleContentType(modulePath),
|
|
677
|
-
"Cache-Control":
|
|
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;
|
|
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
|
-
|
|
131
|
+
}
|
|
132
|
+
if (!isReleaseAssetManifestEnabled()) {
|
|
133
|
+
markManifestDecision("disabled");
|
|
127
134
|
return null;
|
|
128
|
-
|
|
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
|
-
|
|
169
|
+
}
|
|
170
|
+
if (!isReleaseAssetManifestEnabled()) {
|
|
171
|
+
markManifestDecision("disabled");
|
|
156
172
|
return null;
|
|
157
|
-
|
|
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 =
|
|
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
|
}
|