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.
Files changed (89) hide show
  1. package/esm/cli/commands/completions/command-help.d.ts +3 -0
  2. package/esm/cli/commands/completions/command-help.d.ts.map +1 -0
  3. package/esm/cli/commands/completions/command-help.js +13 -0
  4. package/esm/cli/commands/completions/command.d.ts +28 -0
  5. package/esm/cli/commands/completions/command.d.ts.map +1 -0
  6. package/esm/cli/commands/completions/command.js +133 -0
  7. package/esm/cli/commands/completions/handler.d.ts +3 -0
  8. package/esm/cli/commands/completions/handler.d.ts.map +1 -0
  9. package/esm/cli/commands/completions/handler.js +20 -0
  10. package/esm/cli/help/command-definitions.d.ts.map +1 -1
  11. package/esm/cli/help/command-definitions.js +2 -0
  12. package/esm/cli/router.d.ts.map +1 -1
  13. package/esm/cli/router.js +17 -1
  14. package/esm/cli/shared/suggest.d.ts +8 -0
  15. package/esm/cli/shared/suggest.d.ts.map +1 -0
  16. package/esm/cli/shared/suggest.js +25 -0
  17. package/esm/deno.js +1 -1
  18. package/esm/src/html/dev-scripts.d.ts.map +1 -1
  19. package/esm/src/html/dev-scripts.js +3 -2
  20. package/esm/src/html/html-injection.d.ts.map +1 -1
  21. package/esm/src/html/html-injection.js +2 -1
  22. package/esm/src/html/html-shell-generator.js +1 -1
  23. package/esm/src/html/hydration-script-builder/dev-client-renderer.d.ts.map +1 -1
  24. package/esm/src/html/hydration-script-builder/dev-client-renderer.js +2 -1
  25. package/esm/src/html/hydration-script-builder/dev-component-manifest.d.ts.map +1 -1
  26. package/esm/src/html/hydration-script-builder/dev-component-manifest.js +2 -1
  27. package/esm/src/html/hydration-script-builder/dev-error-logger.d.ts.map +1 -1
  28. package/esm/src/html/hydration-script-builder/dev-error-logger.js +2 -1
  29. package/esm/src/html/hydration-script-builder/dev-scripts.d.ts.map +1 -1
  30. package/esm/src/html/hydration-script-builder/dev-scripts.js +2 -1
  31. package/esm/src/html/hydration-script-builder/prod-hydration.d.ts.map +1 -1
  32. package/esm/src/html/hydration-script-builder/prod-hydration.js +2 -1
  33. package/esm/src/html/hydration-script-builder/prod-scripts.d.ts.map +1 -1
  34. package/esm/src/html/hydration-script-builder/prod-scripts.js +2 -1
  35. package/esm/src/html/styles-builder/dev-styles.d.ts.map +1 -1
  36. package/esm/src/html/styles-builder/dev-styles.js +2 -1
  37. package/esm/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.d.ts +10 -0
  38. package/esm/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.d.ts.map +1 -1
  39. package/esm/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.js +51 -24
  40. package/esm/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.js +3 -3
  41. package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
  42. package/esm/src/rendering/orchestrator/html.js +93 -5
  43. package/esm/src/rendering/snippet-renderer.js +1 -1
  44. package/esm/src/security/http/response/security-handler.d.ts.map +1 -1
  45. package/esm/src/security/http/response/security-handler.js +3 -2
  46. package/esm/src/server/dev-server/error-overlay/html-template.d.ts +1 -1
  47. package/esm/src/server/dev-server/error-overlay/html-template.d.ts.map +1 -1
  48. package/esm/src/server/dev-server/error-overlay/html-template.js +4 -3
  49. package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts +1 -1
  50. package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts.map +1 -1
  51. package/esm/src/server/dev-server/error-overlay/overlay-renderer.js +2 -2
  52. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  53. package/esm/src/server/services/rendering/ssr.service.js +3 -3
  54. package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.d.ts.map +1 -1
  55. package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.js +1 -1
  56. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts +2 -3
  57. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts.map +1 -1
  58. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.js +61 -51
  59. package/esm/src/utils/version.d.ts +1 -1
  60. package/esm/src/utils/version.js +1 -1
  61. package/package.json +1 -1
  62. package/src/cli/commands/completions/command-help.ts +15 -0
  63. package/src/cli/commands/completions/command.ts +163 -0
  64. package/src/cli/commands/completions/handler.ts +29 -0
  65. package/src/cli/help/command-definitions.ts +2 -0
  66. package/src/cli/router.ts +16 -1
  67. package/src/cli/shared/suggest.ts +33 -0
  68. package/src/deno.js +1 -1
  69. package/src/src/html/dev-scripts.ts +4 -2
  70. package/src/src/html/html-injection.ts +2 -1
  71. package/src/src/html/html-shell-generator.ts +1 -1
  72. package/src/src/html/hydration-script-builder/dev-client-renderer.ts +2 -1
  73. package/src/src/html/hydration-script-builder/dev-component-manifest.ts +2 -1
  74. package/src/src/html/hydration-script-builder/dev-error-logger.ts +3 -1
  75. package/src/src/html/hydration-script-builder/dev-scripts.ts +2 -1
  76. package/src/src/html/hydration-script-builder/prod-hydration.ts +2 -1
  77. package/src/src/html/hydration-script-builder/prod-scripts.ts +2 -1
  78. package/src/src/html/styles-builder/dev-styles.ts +2 -1
  79. package/src/src/modules/react-loader/ssr-module-loader/http-bundle-helpers.ts +63 -29
  80. package/src/src/modules/react-loader/ssr-module-loader/ssr-cache-manager.ts +4 -4
  81. package/src/src/rendering/orchestrator/html.ts +112 -4
  82. package/src/src/rendering/snippet-renderer.ts +1 -1
  83. package/src/src/security/http/response/security-handler.ts +3 -2
  84. package/src/src/server/dev-server/error-overlay/html-template.ts +4 -2
  85. package/src/src/server/dev-server/error-overlay/overlay-renderer.ts +2 -1
  86. package/src/src/server/services/rendering/ssr.service.ts +12 -7
  87. package/src/src/server/services/rsc/endpoints/rsc-bundles.generated.ts +1 -1
  88. package/src/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.ts +83 -52
  89. package/src/src/utils/version.ts +1 -1
@@ -32,42 +32,23 @@ function extractVfModulePaths(code) {
32
32
  return paths;
33
33
  }
34
34
  /**
35
- * Recursively extract all HTTP bundle paths from code and any VF modules it imports.
36
- * This ensures transitive HTTP bundle dependencies through VF modules are discovered.
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 extractAllHttpBundlePathsRecursive(code) {
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
- // Extract HTTP bundles from this VF module
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 { extractAllFilePaths, extractHttpBundlePaths, verifiedHttpBundlePaths, } from "./http-bundle-helpers.js";
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 = extractHttpBundlePaths(code);
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 = extractAllFilePaths(code);
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;AAE9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiBhD,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;IAWjE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAmCZ,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"}
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
- if (!context.options?.studioEmbed)
25
- return html;
26
- logger.debug("Injected element selectors for Studio");
27
- return injectElementSelectors(html);
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;AAkCD,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"}
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
- * (CSS-in-JS needs unsafe-inline; nonce as migration path; veryfront CDN for
19
- * markdown rendering styles)
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,GACnB,MAAM,CAuOR"}
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;CAO/D,CAAC"}
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;IA4FzB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;CAS1D"}
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,MACgwhE,CAAC;AAElyhE,eAAO,MAAM,iBAAiB,EAAE,MACgpiB,CAAC"}
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"}