veryfront 0.1.112 → 0.1.113
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/cli/commands/completions/command-help.d.ts +3 -0
- package/esm/cli/commands/completions/command-help.d.ts.map +1 -0
- package/esm/cli/commands/completions/command-help.js +13 -0
- package/esm/cli/commands/completions/command.d.ts +28 -0
- package/esm/cli/commands/completions/command.d.ts.map +1 -0
- package/esm/cli/commands/completions/command.js +133 -0
- package/esm/cli/commands/completions/handler.d.ts +3 -0
- package/esm/cli/commands/completions/handler.d.ts.map +1 -0
- package/esm/cli/commands/completions/handler.js +20 -0
- package/esm/cli/help/command-definitions.d.ts.map +1 -1
- package/esm/cli/help/command-definitions.js +2 -0
- package/esm/cli/router.d.ts.map +1 -1
- package/esm/cli/router.js +17 -1
- package/esm/cli/shared/suggest.d.ts +8 -0
- package/esm/cli/shared/suggest.d.ts.map +1 -0
- package/esm/cli/shared/suggest.js +25 -0
- package/esm/deno.js +1 -1
- package/esm/src/html/dev-scripts.d.ts.map +1 -1
- package/esm/src/html/dev-scripts.js +3 -2
- package/esm/src/html/html-injection.d.ts.map +1 -1
- package/esm/src/html/html-injection.js +2 -1
- package/esm/src/html/html-shell-generator.js +1 -1
- package/esm/src/html/hydration-script-builder/dev-client-renderer.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/dev-client-renderer.js +2 -1
- package/esm/src/html/hydration-script-builder/dev-component-manifest.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/dev-component-manifest.js +2 -1
- package/esm/src/html/hydration-script-builder/dev-error-logger.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/dev-error-logger.js +2 -1
- package/esm/src/html/hydration-script-builder/dev-scripts.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/dev-scripts.js +2 -1
- package/esm/src/html/hydration-script-builder/prod-hydration.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/prod-hydration.js +2 -1
- package/esm/src/html/hydration-script-builder/prod-scripts.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/prod-scripts.js +2 -1
- package/esm/src/html/styles-builder/dev-styles.d.ts.map +1 -1
- package/esm/src/html/styles-builder/dev-styles.js +2 -1
- package/esm/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.d.ts +10 -0
- package/esm/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.js +51 -24
- package/esm/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.js +3 -3
- package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/html.js +93 -5
- package/esm/src/rendering/snippet-renderer.js +1 -1
- package/esm/src/security/http/response/security-handler.d.ts.map +1 -1
- package/esm/src/security/http/response/security-handler.js +3 -2
- package/esm/src/server/dev-server/error-overlay/html-template.d.ts +1 -1
- package/esm/src/server/dev-server/error-overlay/html-template.d.ts.map +1 -1
- package/esm/src/server/dev-server/error-overlay/html-template.js +4 -3
- package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts +1 -1
- package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts.map +1 -1
- package/esm/src/server/dev-server/error-overlay/overlay-renderer.js +2 -2
- package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
- package/esm/src/server/services/rendering/ssr.service.js +3 -3
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.d.ts.map +1 -1
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.js +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts +2 -3
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.js +61 -51
- package/esm/src/utils/version.d.ts +1 -1
- package/esm/src/utils/version.js +1 -1
- package/package.json +1 -1
- package/src/cli/commands/completions/command-help.ts +15 -0
- package/src/cli/commands/completions/command.ts +163 -0
- package/src/cli/commands/completions/handler.ts +29 -0
- package/src/cli/help/command-definitions.ts +2 -0
- package/src/cli/router.ts +16 -1
- package/src/cli/shared/suggest.ts +33 -0
- package/src/deno.js +1 -1
- package/src/src/html/dev-scripts.ts +4 -2
- package/src/src/html/html-injection.ts +2 -1
- package/src/src/html/html-shell-generator.ts +1 -1
- package/src/src/html/hydration-script-builder/dev-client-renderer.ts +2 -1
- package/src/src/html/hydration-script-builder/dev-component-manifest.ts +2 -1
- package/src/src/html/hydration-script-builder/dev-error-logger.ts +3 -1
- package/src/src/html/hydration-script-builder/dev-scripts.ts +2 -1
- package/src/src/html/hydration-script-builder/prod-hydration.ts +2 -1
- package/src/src/html/hydration-script-builder/prod-scripts.ts +2 -1
- package/src/src/html/styles-builder/dev-styles.ts +2 -1
- package/src/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.ts +63 -29
- package/src/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.ts +4 -4
- package/src/src/rendering/orchestrator/html.ts +112 -4
- package/src/src/rendering/snippet-renderer.ts +1 -1
- package/src/src/security/http/response/security-handler.ts +3 -2
- package/src/src/server/dev-server/error-overlay/html-template.ts +4 -2
- package/src/src/server/dev-server/error-overlay/overlay-renderer.ts +2 -1
- package/src/src/server/services/rendering/ssr.service.ts +12 -7
- package/src/src/server/services/rsc/endpoints/rsc-bundles.generated.ts +1 -1
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.ts +83 -52
- package/src/src/utils/version.ts +1 -1
|
@@ -32,42 +32,23 @@ function extractVfModulePaths(code) {
|
|
|
32
32
|
return paths;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
35
|
+
* Visit VF module code blocks imported by the given module, including nested VF modules.
|
|
36
|
+
* The visitor receives both the module code and the absolute vfmod file path.
|
|
37
37
|
*/
|
|
38
|
-
export async function
|
|
39
|
-
const allBundles = [];
|
|
40
|
-
const seenHashes = new Set();
|
|
38
|
+
export async function visitImportedVfModules(code, visitor) {
|
|
41
39
|
const seenVfModules = new Set();
|
|
42
|
-
const fs = createFileSystem();
|
|
43
|
-
// Helper to add bundles without duplicates
|
|
44
|
-
const addBundles = (bundles) => {
|
|
45
|
-
for (const bundle of bundles) {
|
|
46
|
-
if (!seenHashes.has(bundle.hash)) {
|
|
47
|
-
seenHashes.add(bundle.hash);
|
|
48
|
-
allBundles.push(bundle);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
// Process initial code
|
|
53
|
-
const directBundles = extractHttpBundlePaths(code);
|
|
54
|
-
addBundles(directBundles);
|
|
55
|
-
// Process VF module imports recursively
|
|
56
40
|
const pendingVfModules = extractVfModulePaths(code);
|
|
41
|
+
const fs = createFileSystem();
|
|
57
42
|
while (pendingVfModules.length > 0) {
|
|
58
43
|
const vfModulePath = pendingVfModules.pop();
|
|
59
44
|
if (seenVfModules.has(vfModulePath))
|
|
60
45
|
continue;
|
|
61
46
|
seenVfModules.add(vfModulePath);
|
|
62
|
-
// Check if the VF module exists locally
|
|
63
47
|
if (!(await exists(vfModulePath)))
|
|
64
48
|
continue;
|
|
65
49
|
try {
|
|
66
50
|
const vfModuleCode = await fs.readTextFile(vfModulePath);
|
|
67
|
-
|
|
68
|
-
const vfBundles = extractHttpBundlePaths(vfModuleCode);
|
|
69
|
-
addBundles(vfBundles);
|
|
70
|
-
// Extract more VF modules for recursive processing
|
|
51
|
+
await visitor(vfModuleCode, vfModulePath);
|
|
71
52
|
const nestedVfModules = extractVfModulePaths(vfModuleCode);
|
|
72
53
|
for (const nestedPath of nestedVfModules) {
|
|
73
54
|
if (!seenVfModules.has(nestedPath)) {
|
|
@@ -79,6 +60,31 @@ export async function extractAllHttpBundlePathsRecursive(code) {
|
|
|
79
60
|
/* expected: VF module file may fail to read */
|
|
80
61
|
}
|
|
81
62
|
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Recursively extract all HTTP bundle paths from code and any VF modules it imports.
|
|
66
|
+
* This ensures transitive HTTP bundle dependencies through VF modules are discovered.
|
|
67
|
+
*/
|
|
68
|
+
export async function extractAllHttpBundlePathsRecursive(code) {
|
|
69
|
+
const allBundles = [];
|
|
70
|
+
const seenHashes = new Set();
|
|
71
|
+
// Helper to add bundles without duplicates
|
|
72
|
+
const addBundles = (bundles) => {
|
|
73
|
+
for (const bundle of bundles) {
|
|
74
|
+
if (!seenHashes.has(bundle.hash)) {
|
|
75
|
+
seenHashes.add(bundle.hash);
|
|
76
|
+
allBundles.push(bundle);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
// Process initial code
|
|
81
|
+
const directBundles = extractHttpBundlePaths(code);
|
|
82
|
+
addBundles(directBundles);
|
|
83
|
+
await visitImportedVfModules(code, (vfModuleCode) => {
|
|
84
|
+
// Extract HTTP bundles from this VF module
|
|
85
|
+
const vfBundles = extractHttpBundlePaths(vfModuleCode);
|
|
86
|
+
addBundles(vfBundles);
|
|
87
|
+
});
|
|
82
88
|
return allBundles;
|
|
83
89
|
}
|
|
84
90
|
/** Extract HTTP bundle paths from transformed code for proactive recovery */
|
|
@@ -132,6 +138,27 @@ export function extractAllFilePaths(code) {
|
|
|
132
138
|
}
|
|
133
139
|
return paths;
|
|
134
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Extract all file:// paths from cached code and any transitively imported VF modules.
|
|
143
|
+
* This catches stale pod-local paths that only appear in nested vfmod dependencies.
|
|
144
|
+
*/
|
|
145
|
+
export async function extractAllFilePathsRecursive(code) {
|
|
146
|
+
const paths = [];
|
|
147
|
+
const seen = new Set();
|
|
148
|
+
const addPaths = (entries) => {
|
|
149
|
+
for (const path of entries) {
|
|
150
|
+
if (seen.has(path))
|
|
151
|
+
continue;
|
|
152
|
+
seen.add(path);
|
|
153
|
+
paths.push(path);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
addPaths(extractAllFilePaths(code));
|
|
157
|
+
await visitImportedVfModules(code, (vfModuleCode) => {
|
|
158
|
+
addPaths(extractAllFilePaths(vfModuleCode));
|
|
159
|
+
});
|
|
160
|
+
return paths;
|
|
161
|
+
}
|
|
135
162
|
/**
|
|
136
163
|
* Track modules whose HTTP bundles have been verified, keyed by tempPath:contentHash.
|
|
137
164
|
* Bounded LRU to prevent unbounded memory growth in long-running pods.
|
|
@@ -17,7 +17,7 @@ import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
|
17
17
|
import { ensureHttpBundlesExist } from "../../../transforms/esm/http-cache.js";
|
|
18
18
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
|
|
19
19
|
import { globalModuleCache, globalTmpDirs } from "./cache/index.js";
|
|
20
|
-
import {
|
|
20
|
+
import { extractAllFilePathsRecursive, extractAllHttpBundlePathsRecursive, verifiedHttpBundlePaths, } from "./http-bundle-helpers.js";
|
|
21
21
|
import { buildTempModulePath, buildTmpDirPath, getTmpDirCacheKey } from "./tmp-paths.js";
|
|
22
22
|
import { ensureMdxModuleDependencies } from "../../../transforms/mdx/esm-module-loader/module-fetcher/dependency-recovery.js";
|
|
23
23
|
const logger = rendererLogger.component("ssr-module-loader");
|
|
@@ -160,7 +160,7 @@ export class SSRCacheManager {
|
|
|
160
160
|
return UNRESOLVED_VF_MODULE_IMPORT_PATTERN.test(code);
|
|
161
161
|
}
|
|
162
162
|
async hasMissingHttpBundles(code, filePath, source) {
|
|
163
|
-
const bundlePaths =
|
|
163
|
+
const bundlePaths = await extractAllHttpBundlePathsRecursive(code);
|
|
164
164
|
if (bundlePaths.length === 0)
|
|
165
165
|
return false;
|
|
166
166
|
const cacheDir = getHttpBundleCacheDir();
|
|
@@ -177,7 +177,7 @@ export class SSRCacheManager {
|
|
|
177
177
|
return true;
|
|
178
178
|
}
|
|
179
179
|
async hasMissingLocalPaths(code, filePath) {
|
|
180
|
-
const allPaths =
|
|
180
|
+
const allPaths = await extractAllFilePathsRecursive(code);
|
|
181
181
|
let hasMissingPath = false;
|
|
182
182
|
for (const path of allPaths) {
|
|
183
183
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAuHhD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;IACpC,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAajE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAsCZ,sBAAsB;YA8BtB,wBAAwB;YAmBxB,gBAAgB;YAehB,kBAAkB;IAsDhC,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAwE9B;;;;OAIG;YACW,gBAAgB;IA2D9B,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,qBAAqB;YAOf,6BAA6B;CAyD5C"}
|
|
@@ -2,6 +2,7 @@ import { join } from "../../platform/compat/path/index.js";
|
|
|
2
2
|
import { getExtensionName } from "../../utils/path-utils.js";
|
|
3
3
|
import { buildImportMapJson, extractHTMLMetadata, generateHTMLShellParts, injectHTMLContent, isFullHTMLDocument, } from "../../html/index.js";
|
|
4
4
|
import { DEFAULT_DASHBOARD_PORT, rendererLogger } from "../../utils/index.js";
|
|
5
|
+
import { escapeHtml } from "../../utils/html-escape.js";
|
|
5
6
|
import { injectElementSelectors } from "../../studio/element-selector-injector.js";
|
|
6
7
|
import { computeSourceHash } from "../../studio/hash-utils.js";
|
|
7
8
|
import { extractRelativePath } from "../../utils/route-path-utils.js";
|
|
@@ -12,6 +13,92 @@ import { getRouteCandidates } from "./css-candidate-manifest.js";
|
|
|
12
13
|
import { resolveStyleContentVersion } from "../../html/styles-builder/content-version.js";
|
|
13
14
|
import { createStyleScopeProfile } from "../../html/styles-builder/style-scope-profile.js";
|
|
14
15
|
const logger = rendererLogger.component("html-generator");
|
|
16
|
+
function findTagEnd(html, start) {
|
|
17
|
+
let activeQuote = null;
|
|
18
|
+
for (let index = start + 1; index < html.length; index++) {
|
|
19
|
+
const char = html[index];
|
|
20
|
+
if (activeQuote) {
|
|
21
|
+
if (char === activeQuote)
|
|
22
|
+
activeQuote = null;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (char === '"' || char === "'") {
|
|
26
|
+
activeQuote = char;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (char === ">")
|
|
30
|
+
return index;
|
|
31
|
+
}
|
|
32
|
+
return -1;
|
|
33
|
+
}
|
|
34
|
+
function getOpeningTagName(tag) {
|
|
35
|
+
const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
|
|
36
|
+
const tagName = match?.[1]?.toLowerCase();
|
|
37
|
+
if (tagName === "script" || tagName === "style")
|
|
38
|
+
return tagName;
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
function injectNonceIntoOpeningTag(tag, escapedNonce) {
|
|
42
|
+
if (/\bnonce\s*=/iu.test(tag))
|
|
43
|
+
return tag;
|
|
44
|
+
const closeIndex = tag.lastIndexOf(">");
|
|
45
|
+
if (closeIndex === -1)
|
|
46
|
+
return tag;
|
|
47
|
+
const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
|
|
48
|
+
return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
|
|
49
|
+
}
|
|
50
|
+
function addNonceToRenderedTags(html, nonce) {
|
|
51
|
+
if (!nonce)
|
|
52
|
+
return html;
|
|
53
|
+
const escapedNonce = escapeHtml(nonce);
|
|
54
|
+
const lowerHtml = html.toLowerCase();
|
|
55
|
+
let result = "";
|
|
56
|
+
let index = 0;
|
|
57
|
+
let rawTextTag = null;
|
|
58
|
+
while (index < html.length) {
|
|
59
|
+
if (rawTextTag) {
|
|
60
|
+
const closingIndex = lowerHtml.indexOf(`</${rawTextTag}`, index);
|
|
61
|
+
if (closingIndex === -1) {
|
|
62
|
+
result += html.slice(index);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
result += html.slice(index, closingIndex);
|
|
66
|
+
index = closingIndex;
|
|
67
|
+
rawTextTag = null;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (html.startsWith("<!--", index)) {
|
|
71
|
+
const commentEnd = html.indexOf("-->", index + 4);
|
|
72
|
+
const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
|
|
73
|
+
result += html.slice(index, endIndex);
|
|
74
|
+
index = endIndex;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (html[index] !== "<") {
|
|
78
|
+
result += html[index];
|
|
79
|
+
index++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const tagEnd = findTagEnd(html, index);
|
|
83
|
+
if (tagEnd === -1) {
|
|
84
|
+
result += html.slice(index);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
const tag = html.slice(index, tagEnd + 1);
|
|
88
|
+
const tagName = getOpeningTagName(tag);
|
|
89
|
+
if (!tagName) {
|
|
90
|
+
result += tag;
|
|
91
|
+
index = tagEnd + 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
result += injectNonceIntoOpeningTag(tag, escapedNonce);
|
|
95
|
+
index = tagEnd + 1;
|
|
96
|
+
if (!/\/\s*>$/u.test(tag)) {
|
|
97
|
+
rawTextTag = tagName;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
15
102
|
export class HTMLGenerator {
|
|
16
103
|
config;
|
|
17
104
|
constructor(config) {
|
|
@@ -21,10 +108,11 @@ export class HTMLGenerator {
|
|
|
21
108
|
const html = isFullHTMLDocument(context.html)
|
|
22
109
|
? await this.handleFullHTMLDocument(context)
|
|
23
110
|
: await this.wrapHTMLFragment(context);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
111
|
+
const finalHtml = context.options?.studioEmbed ? injectElementSelectors(html) : html;
|
|
112
|
+
if (context.options?.studioEmbed) {
|
|
113
|
+
logger.debug("Injected element selectors for Studio");
|
|
114
|
+
}
|
|
115
|
+
return addNonceToRenderedTags(finalHtml, context.options?.nonce);
|
|
28
116
|
}
|
|
29
117
|
async generateHTMLStream(reactStream, context) {
|
|
30
118
|
const fullContext = context;
|
|
@@ -44,7 +132,7 @@ export class HTMLGenerator {
|
|
|
44
132
|
}
|
|
45
133
|
const { start, end } = await this.generateShellParts(fullContext, mergedFrontmatter, htmlOptions, reactContent);
|
|
46
134
|
const encoder = new TextEncoder();
|
|
47
|
-
const fullHtml = `${start}${reactContent}${end}
|
|
135
|
+
const fullHtml = addNonceToRenderedTags(`${start}${reactContent}${end}`, context.options?.nonce);
|
|
48
136
|
return new ReadableStream({
|
|
49
137
|
start(controller) {
|
|
50
138
|
controller.enqueue(encoder.encode(fullHtml));
|
|
@@ -240,7 +240,7 @@ export function renderSnippet(mdxContent, options) {
|
|
|
240
240
|
function generateErrorHTML(error, options) {
|
|
241
241
|
const message = error instanceof Error ? error.message : String(error);
|
|
242
242
|
const stack = error instanceof Error ? error.stack : undefined;
|
|
243
|
-
const nonce = options.nonce ? ` nonce="${options.nonce}"` : "";
|
|
243
|
+
const nonce = options.nonce ? ` nonce="${escapeHtml(options.nonce)}"` : "";
|
|
244
244
|
const stackHtml = options.mode === "development" && stack
|
|
245
245
|
? `<div class="error-stack">${escapeHtml(stack)}</div>`
|
|
246
246
|
: "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/security/http/response/security-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQjD,wBAAgB,aAAa,IAAI,MAAM,CAItC;
|
|
1
|
+
{"version":3,"file":"security-handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/security/http/response/security-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQjD,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAmCD,wBAAgB,QAAQ,CACtB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,MAAM,CA4BR;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,MAAM,CAMR;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,cAAc,EACxB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,IAAI,CA6DN"}
|
|
@@ -15,8 +15,8 @@ export function generateNonce() {
|
|
|
15
15
|
* - Scripts: nonce-based + cdn.jsdelivr.net (Scalar API docs, html2canvas,
|
|
16
16
|
* React UMD, browser inference)
|
|
17
17
|
* - Styles: 'self' + 'unsafe-inline' + nonce + Google Fonts + cdn.veryfront.com
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* plus style-src-attr 'unsafe-inline' so React style="" attributes remain
|
|
19
|
+
* compatible while inline <style> tags continue to use the nonce
|
|
20
20
|
* - Images/media/fonts: 'self' + data: + https: + cdn.veryfront.com
|
|
21
21
|
* - Connections: 'self' + wss: + https: (WebSocket for HMR/live reload, API calls)
|
|
22
22
|
* - Objects: 'none' (block Flash/plugins)
|
|
@@ -30,6 +30,7 @@ function buildDefaultCSP(nonce) {
|
|
|
30
30
|
`default-src 'self'`,
|
|
31
31
|
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net`,
|
|
32
32
|
`style-src 'self' 'unsafe-inline' 'nonce-${nonce}' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
33
|
+
`style-src-attr 'unsafe-inline'`,
|
|
33
34
|
`img-src 'self' data: https:`,
|
|
34
35
|
`font-src 'self' data: https://fonts.gstatic.com https://cdn.veryfront.com`,
|
|
35
36
|
`connect-src 'self' wss: https:`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type ErrorInfo } from "./error-formatter.js";
|
|
2
2
|
export declare function generateRuntimeScript(): string;
|
|
3
|
-
export declare function generateErrorHTML(errorInfo: ErrorInfo, suggestion?: string, projectSlug?: string): string;
|
|
3
|
+
export declare function generateErrorHTML(errorInfo: ErrorInfo, suggestion?: string, projectSlug?: string, nonce?: string): string;
|
|
4
4
|
//# sourceMappingURL=html-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-template.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/dev-server/error-overlay/html-template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,sBAAsB,CAAC;AAmBvE,wBAAgB,qBAAqB,IAAI,MAAM,CA6L9C;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"html-template.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/dev-server/error-overlay/html-template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,sBAAsB,CAAC;AAmBvE,wBAAgB,qBAAqB,IAAI,MAAM,CA6L9C;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAwOR"}
|
|
@@ -202,7 +202,7 @@ export function generateRuntimeScript() {
|
|
|
202
202
|
});
|
|
203
203
|
`;
|
|
204
204
|
}
|
|
205
|
-
export function generateErrorHTML(errorInfo, suggestion, projectSlug) {
|
|
205
|
+
export function generateErrorHTML(errorInfo, suggestion, projectSlug, nonce) {
|
|
206
206
|
const errorType = escapeHtml(formatErrorType(errorInfo.type));
|
|
207
207
|
const errorName = escapeHtml(errorInfo.error.name);
|
|
208
208
|
const errorMessage = escapeHtml(errorInfo.error.message);
|
|
@@ -211,6 +211,7 @@ export function generateErrorHTML(errorInfo, suggestion, projectSlug) {
|
|
|
211
211
|
const errorColumn = errorInfo.column ? escapeHtml(String(errorInfo.column)) : "";
|
|
212
212
|
const errorSuggestion = suggestion ? escapeHtml(suggestion) : "";
|
|
213
213
|
const errorStack = errorInfo.error.stack ? escapeHtml(errorInfo.error.stack) : "";
|
|
214
|
+
const nonceAttr = nonce ? ` nonce="${escapeHtml(nonce)}"` : "";
|
|
214
215
|
const fileSection = errorFile
|
|
215
216
|
? `
|
|
216
217
|
<div class="error-file">
|
|
@@ -243,7 +244,7 @@ export function generateErrorHTML(errorInfo, suggestion, projectSlug) {
|
|
|
243
244
|
<head>
|
|
244
245
|
<meta charset="UTF-8">
|
|
245
246
|
<title>${errorType} Error - Veryfront</title>
|
|
246
|
-
<style>
|
|
247
|
+
<style${nonceAttr}>
|
|
247
248
|
body {
|
|
248
249
|
margin: 0;
|
|
249
250
|
padding: 20px;
|
|
@@ -350,7 +351,7 @@ export function generateErrorHTML(errorInfo, suggestion, projectSlug) {
|
|
|
350
351
|
</div>
|
|
351
352
|
${fixButtonHtml}
|
|
352
353
|
</div>
|
|
353
|
-
<script>${projectSlug
|
|
354
|
+
<script${nonceAttr}>${projectSlug
|
|
354
355
|
? `
|
|
355
356
|
(function() {
|
|
356
357
|
var slug = ${jsonForScript(projectSlug)};
|
|
@@ -3,6 +3,6 @@ import { generateRuntimeScript } from "./html-template.js";
|
|
|
3
3
|
export declare const ErrorOverlay: {
|
|
4
4
|
getRuntime: typeof generateRuntimeScript;
|
|
5
5
|
getSuggestion: typeof getSuggestion;
|
|
6
|
-
createHTML(errorInfo: ErrorInfo, projectSlug?: string): string;
|
|
6
|
+
createHTML(errorInfo: ErrorInfo, projectSlug?: string, nonce?: string): string;
|
|
7
7
|
};
|
|
8
8
|
//# sourceMappingURL=overlay-renderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-renderer.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/dev-server/error-overlay/overlay-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAqB,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE9E,eAAO,MAAM,YAAY;;;0BAGD,SAAS,gBAAgB,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"overlay-renderer.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/dev-server/error-overlay/overlay-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAqB,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE9E,eAAO,MAAM,YAAY;;;0BAGD,SAAS,gBAAgB,MAAM,UAAU,MAAM,GAAG,MAAM;CAQ/E,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { generateErrorHTML, generateRuntimeScript } from "./html-template.js";
|
|
|
3
3
|
export const ErrorOverlay = {
|
|
4
4
|
getRuntime: generateRuntimeScript,
|
|
5
5
|
getSuggestion,
|
|
6
|
-
createHTML(errorInfo, projectSlug) {
|
|
7
|
-
return generateErrorHTML(errorInfo, errorInfo.suggestion ?? getSuggestion(errorInfo.error), projectSlug);
|
|
6
|
+
createHTML(errorInfo, projectSlug, nonce) {
|
|
7
|
+
return generateErrorHTML(errorInfo, errorInfo.suggestion ?? getSuggestion(errorInfo.error), projectSlug, nonce);
|
|
8
8
|
},
|
|
9
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/rendering/ssr.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,kCAAkC,CAAC;AAmB1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,mBAAmB,IAAI,YAAY,CAAC;IACpC,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrF,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC;CAC3D;AAUD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACpC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KACrC;IAKD,mBAAmB,IAAI,YAAY;IAW7B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAiG1F,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"ssr.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/rendering/ssr.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,kCAAkC,CAAC;AAmB1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,mBAAmB,IAAI,YAAY,CAAC;IACpC,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrF,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC;CAC3D;AAUD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACpC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KACrC;IAKD,mBAAmB,IAAI,YAAY;IAW7B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAiG1F,OAAO,CAAC,iBAAiB;IAiGzB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;CAS1D"}
|
|
@@ -108,10 +108,10 @@ export class SSRService {
|
|
|
108
108
|
}
|
|
109
109
|
catch (error) {
|
|
110
110
|
endRenderSession(renderSessionId);
|
|
111
|
-
return this.handleRenderError(error, ctx, slug, request);
|
|
111
|
+
return this.handleRenderError(error, ctx, slug, request, nonce);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
handleRenderError(error, ctx, slug, request) {
|
|
114
|
+
handleRenderError(error, ctx, slug, request, nonce) {
|
|
115
115
|
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
116
116
|
const isDev = ctx.isLocalProject || ctx.requestContext?.mode === "preview";
|
|
117
117
|
if (error instanceof VeryfrontError && error.slug === "file-not-found") {
|
|
@@ -167,7 +167,7 @@ export class SSRService {
|
|
|
167
167
|
type: "runtime",
|
|
168
168
|
...(sourceFile ? { file: sourceFile } : {}),
|
|
169
169
|
...location,
|
|
170
|
-
}, ctx.projectSlug),
|
|
170
|
+
}, ctx.projectSlug, nonce),
|
|
171
171
|
isStreaming: false,
|
|
172
172
|
cacheStrategy: "no-cache",
|
|
173
173
|
error: errorObj,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-bundles.generated.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/services/rsc/endpoints/rsc-bundles.generated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"rsc-bundles.generated.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/services/rsc/endpoints/rsc-bundles.generated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,kBAAkB,EAAE,MAC6whE,CAAC;AAE/yhE,eAAO,MAAM,iBAAiB,EAAE,MACgpiB,CAAC"}
|