veryfront 0.1.131 → 0.1.136

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 (140) hide show
  1. package/esm/_dnt.polyfills.d.ts +11 -0
  2. package/esm/_dnt.polyfills.d.ts.map +1 -1
  3. package/esm/_dnt.polyfills.js +14 -0
  4. package/esm/cli/commands/build/handler.js +2 -0
  5. package/esm/cli/commands/deploy/command.d.ts.map +1 -1
  6. package/esm/cli/commands/deploy/command.js +2 -0
  7. package/esm/cli/commands/files/command.d.ts.map +1 -1
  8. package/esm/cli/commands/files/command.js +1 -0
  9. package/esm/cli/commands/uploads/command.d.ts.map +1 -1
  10. package/esm/cli/commands/uploads/command.js +1 -0
  11. package/esm/cli/help/tips.d.ts +3 -0
  12. package/esm/cli/help/tips.d.ts.map +1 -1
  13. package/esm/cli/help/tips.js +15 -1
  14. package/esm/cli/router.d.ts.map +1 -1
  15. package/esm/cli/router.js +4 -0
  16. package/esm/cli/shared/animation.d.ts +3 -0
  17. package/esm/cli/shared/animation.d.ts.map +1 -0
  18. package/esm/cli/shared/animation.js +23 -0
  19. package/esm/cli/templates/manifest.d.ts +6 -0
  20. package/esm/cli/templates/manifest.js +12 -6
  21. package/esm/cli/ui/progress.d.ts.map +1 -1
  22. package/esm/cli/ui/progress.js +13 -1
  23. package/esm/deno.js +1 -1
  24. package/esm/src/agent/index.d.ts +1 -1
  25. package/esm/src/agent/index.d.ts.map +1 -1
  26. package/esm/src/agent/runtime/ai-stream-handler.d.ts.map +1 -1
  27. package/esm/src/agent/runtime/ai-stream-handler.js +56 -5
  28. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  29. package/esm/src/agent/runtime/index.js +21 -3
  30. package/esm/src/agent/runtime/model-tool-converter.d.ts +5 -1
  31. package/esm/src/agent/runtime/model-tool-converter.d.ts.map +1 -1
  32. package/esm/src/agent/runtime/model-tool-converter.js +35 -4
  33. package/esm/src/agent/runtime/tool-helpers.d.ts +2 -1
  34. package/esm/src/agent/runtime/tool-helpers.d.ts.map +1 -1
  35. package/esm/src/agent/runtime/tool-helpers.js +6 -3
  36. package/esm/src/agent/types.d.ts +19 -0
  37. package/esm/src/agent/types.d.ts.map +1 -1
  38. package/esm/src/channels/control-plane.d.ts +67 -0
  39. package/esm/src/channels/control-plane.d.ts.map +1 -1
  40. package/esm/src/channels/control-plane.js +27 -0
  41. package/esm/src/discovery/handlers/tool-handler.d.ts.map +1 -1
  42. package/esm/src/discovery/handlers/tool-handler.js +12 -2
  43. package/esm/src/html/html-injection.d.ts +2 -0
  44. package/esm/src/html/html-injection.d.ts.map +1 -1
  45. package/esm/src/html/html-injection.js +10 -5
  46. package/esm/src/html/nonce-injection.d.ts +3 -0
  47. package/esm/src/html/nonce-injection.d.ts.map +1 -0
  48. package/esm/src/html/nonce-injection.js +249 -0
  49. package/esm/src/internal-agents/ag-ui-sse.d.ts +1 -0
  50. package/esm/src/internal-agents/ag-ui-sse.d.ts.map +1 -1
  51. package/esm/src/internal-agents/ag-ui-sse.js +18 -0
  52. package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
  53. package/esm/src/internal-agents/run-stream.js +26 -4
  54. package/esm/src/platform/adapters/fs/veryfront/proxy-manager.d.ts +1 -0
  55. package/esm/src/platform/adapters/fs/veryfront/proxy-manager.d.ts.map +1 -1
  56. package/esm/src/platform/adapters/fs/veryfront/proxy-manager.js +15 -1
  57. package/esm/src/platform/adapters/fs/veryfront/types.d.ts +2 -0
  58. package/esm/src/platform/adapters/fs/veryfront/types.d.ts.map +1 -1
  59. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts.map +1 -1
  60. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.js +2 -0
  61. package/esm/src/proxy/handler.d.ts.map +1 -1
  62. package/esm/src/proxy/handler.js +25 -5
  63. package/esm/src/react/components/Head.d.ts +9 -0
  64. package/esm/src/react/components/Head.d.ts.map +1 -1
  65. package/esm/src/react/components/Head.js +9 -0
  66. package/esm/src/react/context/index.d.ts +9 -0
  67. package/esm/src/react/context/index.d.ts.map +1 -1
  68. package/esm/src/react/context/index.js +9 -0
  69. package/esm/src/react/router/index.d.ts +9 -0
  70. package/esm/src/react/router/index.d.ts.map +1 -1
  71. package/esm/src/react/router/index.js +9 -0
  72. package/esm/src/rendering/orchestrator/html.d.ts +1 -0
  73. package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
  74. package/esm/src/rendering/orchestrator/html.js +81 -89
  75. package/esm/src/rendering/script-page-handling.js +1 -0
  76. package/esm/src/server/handlers/dev/framework-candidates.generated.d.ts.map +1 -1
  77. package/esm/src/server/handlers/dev/framework-candidates.generated.js +9 -0
  78. package/esm/src/server/handlers/request/ssr/ssr-response-builder.d.ts.map +1 -1
  79. package/esm/src/server/handlers/request/ssr/ssr-response-builder.js +3 -7
  80. package/esm/src/server/handlers/request/static.handler.d.ts.map +1 -1
  81. package/esm/src/server/handlers/request/static.handler.js +18 -10
  82. package/esm/src/tool/factory.d.ts.map +1 -1
  83. package/esm/src/tool/factory.js +14 -4
  84. package/esm/src/tool/types.d.ts +2 -0
  85. package/esm/src/tool/types.d.ts.map +1 -1
  86. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/constants.d.ts +1 -0
  87. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/constants.d.ts.map +1 -1
  88. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/constants.js +3 -0
  89. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/import-finder.d.ts.map +1 -1
  90. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/import-finder.js +4 -2
  91. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/index.d.ts +1 -1
  92. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/index.d.ts.map +1 -1
  93. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/index.js +10 -9
  94. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.d.ts.map +1 -1
  95. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.js +3 -1
  96. package/esm/src/utils/version-constant.d.ts +1 -1
  97. package/esm/src/utils/version-constant.js +1 -1
  98. package/package.json +1 -1
  99. package/src/_dnt.polyfills.ts +27 -0
  100. package/src/cli/commands/build/handler.ts +3 -0
  101. package/src/cli/commands/deploy/command.ts +3 -0
  102. package/src/cli/commands/files/command.ts +1 -0
  103. package/src/cli/commands/uploads/command.ts +3 -0
  104. package/src/cli/help/tips.ts +18 -1
  105. package/src/cli/router.ts +5 -0
  106. package/src/cli/shared/animation.ts +25 -0
  107. package/src/cli/templates/manifest.js +12 -6
  108. package/src/cli/ui/progress.ts +13 -1
  109. package/src/deno.js +1 -1
  110. package/src/src/agent/index.ts +2 -0
  111. package/src/src/agent/runtime/ai-stream-handler.ts +64 -6
  112. package/src/src/agent/runtime/index.ts +26 -1
  113. package/src/src/agent/runtime/model-tool-converter.ts +47 -3
  114. package/src/src/agent/runtime/tool-helpers.ts +15 -3
  115. package/src/src/agent/types.ts +23 -0
  116. package/src/src/channels/control-plane.ts +31 -0
  117. package/src/src/discovery/handlers/tool-handler.ts +13 -2
  118. package/src/src/html/html-injection.ts +16 -5
  119. package/src/src/html/nonce-injection.ts +300 -0
  120. package/src/src/internal-agents/ag-ui-sse.ts +20 -0
  121. package/src/src/internal-agents/run-stream.ts +35 -4
  122. package/src/src/platform/adapters/fs/veryfront/proxy-manager.ts +29 -3
  123. package/src/src/platform/adapters/fs/veryfront/types.ts +2 -0
  124. package/src/src/platform/adapters/fs/veryfront/websocket-manager.ts +2 -0
  125. package/src/src/proxy/handler.ts +43 -5
  126. package/src/src/react/components/Head.tsx +10 -0
  127. package/src/src/react/context/index.tsx +10 -0
  128. package/src/src/react/router/index.tsx +10 -0
  129. package/src/src/rendering/orchestrator/html.ts +125 -100
  130. package/src/src/rendering/script-page-handling.ts +1 -0
  131. package/src/src/server/handlers/dev/framework-candidates.generated.ts +9 -0
  132. package/src/src/server/handlers/request/ssr/ssr-response-builder.ts +7 -11
  133. package/src/src/server/handlers/request/static.handler.ts +22 -10
  134. package/src/src/tool/factory.ts +17 -4
  135. package/src/src/tool/types.ts +2 -0
  136. package/src/src/transforms/pipeline/stages/ssr-vf-modules/constants.ts +4 -0
  137. package/src/src/transforms/pipeline/stages/ssr-vf-modules/import-finder.ts +4 -2
  138. package/src/src/transforms/pipeline/stages/ssr-vf-modules/index.ts +18 -15
  139. package/src/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.ts +4 -1
  140. package/src/src/utils/version-constant.ts +1 -1
@@ -1,3 +1,12 @@
1
+ /**
2
+ * React router exports for client navigation and route context.
3
+ *
4
+ * @module
5
+ * @example
6
+ * ```tsx
7
+ * import { Link, RouterProvider, useRouter } from "veryfront/router";
8
+ * ```
9
+ */
1
10
  import "../../../_dnt.polyfills.js";
2
11
  export { Link, Router, RouterProvider, useRouter } from "../runtime/core.js";
3
12
  export type { LinkProps, RouterProviderProps, RouterValue } from "../runtime/core.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/react/router/index.tsx"],"names":[],"mappings":"AAAA,OAAO,4BAA4B,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC7E,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/react/router/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,4BAA4B,CAAC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC7E,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1,2 +1,11 @@
1
+ /**
2
+ * React router exports for client navigation and route context.
3
+ *
4
+ * @module
5
+ * @example
6
+ * ```tsx
7
+ * import { Link, RouterProvider, useRouter } from "veryfront/router";
8
+ * ```
9
+ */
1
10
  import "../../../_dnt.polyfills.js";
2
11
  export { Link, Router, RouterProvider, useRouter } from "../runtime/core.js";
@@ -29,6 +29,7 @@ export declare class HTMLGenerator {
29
29
  generateFullHTML(context: HTMLGenerationContext): Promise<string>;
30
30
  generateHTMLStream(reactStream: ReadableStream, context: Omit<HTMLGenerationContext, "html">): Promise<ReadableStream>;
31
31
  private handleFullHTMLDocument;
32
+ private resolveProjectStylesheetHref;
32
33
  private detectUseClientDirective;
33
34
  private wrapHTMLFragment;
34
35
  private generateShellParts;
@@ -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;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA2HhD,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;YAgDZ,sBAAsB;YAiCtB,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAgF9B;;;;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;AA6EhD,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;IA0BjE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAqEZ,sBAAsB;YAqDtB,4BAA4B;YAiB5B,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAgF9B;;;;OAIG;YACW,gBAAgB;IA2D9B,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,qBAAqB;YAOf,6BAA6B;CAyD5C"}
@@ -2,7 +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
+ import { addNonceToHtmlTags } from "../../html/nonce-injection.js";
6
6
  import { injectElementSelectors } from "../../studio/element-selector-injector.js";
7
7
  import { computeSourceHash } from "../../studio/hash-utils.js";
8
8
  import { extractRelativePath } from "../../utils/route-path-utils.js";
@@ -16,91 +16,44 @@ import { getRouteCandidates } from "./css-candidate-manifest.js";
16
16
  import { resolveStyleContentVersion } from "../../html/styles-builder/content-version.js";
17
17
  import { createStyleScopeProfile } from "../../html/styles-builder/style-scope-profile.js";
18
18
  const logger = rendererLogger.component("html-generator");
19
- function findTagEnd(html, start) {
20
- let activeQuote = null;
21
- for (let index = start + 1; index < html.length; index++) {
22
- const char = html[index];
23
- if (activeQuote) {
24
- if (char === activeQuote)
25
- activeQuote = null;
26
- continue;
27
- }
28
- if (char === '"' || char === "'") {
29
- activeQuote = char;
30
- continue;
31
- }
32
- if (char === ">")
33
- return index;
34
- }
35
- return -1;
36
- }
37
- function getOpeningTagName(tag) {
38
- const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
39
- const tagName = match?.[1]?.toLowerCase();
40
- if (tagName === "script" || tagName === "style")
41
- return tagName;
42
- return undefined;
43
- }
44
- function injectNonceIntoOpeningTag(tag, escapedNonce) {
45
- if (/\bnonce\s*=/iu.test(tag))
46
- return tag;
47
- const closeIndex = tag.lastIndexOf(">");
48
- if (closeIndex === -1)
49
- return tag;
50
- const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
51
- return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
52
- }
53
- function addNonceToRenderedTags(html, nonce) {
54
- if (!nonce)
19
+ function applyExplicitThemeToDocument(html, colorScheme, enabled) {
20
+ if (!enabled || !colorScheme)
55
21
  return html;
56
- const escapedNonce = escapeHtml(nonce);
57
- const lowerHtml = html.toLowerCase();
58
- let result = "";
59
- let index = 0;
60
- let rawTextTag = null;
61
- while (index < html.length) {
62
- if (rawTextTag) {
63
- const closingIndex = lowerHtml.indexOf(`</${rawTextTag}`, index);
64
- if (closingIndex === -1) {
65
- result += html.slice(index);
66
- break;
67
- }
68
- result += html.slice(index, closingIndex);
69
- index = closingIndex;
70
- rawTextTag = null;
71
- continue;
22
+ return html.replace(/<html\b([^>]*)>/i, (_match, attrs) => {
23
+ let nextAttrs = attrs;
24
+ if (/\sdata-theme\s*=/i.test(nextAttrs)) {
25
+ nextAttrs = nextAttrs.replace(/\sdata-theme\s*=\s*(["']).*?\1/i, "");
72
26
  }
73
- if (html.startsWith("<!--", index)) {
74
- const commentEnd = html.indexOf("-->", index + 4);
75
- const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
76
- result += html.slice(index, endIndex);
77
- index = endIndex;
78
- continue;
79
- }
80
- if (html[index] !== "<") {
81
- result += html[index];
82
- index++;
83
- continue;
84
- }
85
- const tagEnd = findTagEnd(html, index);
86
- if (tagEnd === -1) {
87
- result += html.slice(index);
88
- break;
89
- }
90
- const tag = html.slice(index, tagEnd + 1);
91
- const tagName = getOpeningTagName(tag);
92
- if (!tagName) {
93
- result += tag;
94
- index = tagEnd + 1;
95
- continue;
27
+ nextAttrs += ` data-theme="${colorScheme}"`;
28
+ const styleMatch = nextAttrs.match(/\sstyle\s*=\s*(["'])(.*?)\1/i);
29
+ if (styleMatch) {
30
+ let styleValue = (styleMatch[2] ?? "").trim();
31
+ if (/color-scheme\s*:/i.test(styleValue)) {
32
+ styleValue = styleValue.replace(/color-scheme\s*:\s*[^;]+/i, `color-scheme: ${colorScheme}`);
33
+ }
34
+ else {
35
+ styleValue = styleValue
36
+ ? `${styleValue.replace(/;?\s*$/, ";")} color-scheme: ${colorScheme};`
37
+ : `color-scheme: ${colorScheme};`;
38
+ }
39
+ nextAttrs = nextAttrs.replace(styleMatch[0], ` style="${styleValue}"`);
96
40
  }
97
- result += injectNonceIntoOpeningTag(tag, escapedNonce);
98
- index = tagEnd + 1;
99
- if (!/\/\s*>$/u.test(tag)) {
100
- rawTextTag = tagName;
41
+ else {
42
+ nextAttrs += ` style="color-scheme: ${colorScheme};"`;
101
43
  }
102
- }
103
- return result;
44
+ return `<html${nextAttrs}>`;
45
+ });
46
+ }
47
+ function injectThemePersistenceScript(html, colorScheme, enabled, nonce) {
48
+ if (!enabled || !colorScheme || !/<\/head>/i.test(html))
49
+ return html;
50
+ if (html.includes(`localStorage.setItem('theme','${colorScheme}')`))
51
+ return html;
52
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
53
+ const script = `<script${nonceAttr}>
54
+ (function(){try{localStorage.setItem('theme','${colorScheme}')}catch(e){/* SILENT: localStorage may be unavailable */}})();
55
+ </script>`;
56
+ return html.replace(/<\/head>/i, `${script}\n</head>`);
104
57
  }
105
58
  export class HTMLGenerator {
106
59
  config;
@@ -108,14 +61,24 @@ export class HTMLGenerator {
108
61
  this.config = config;
109
62
  }
110
63
  async generateFullHTML(context) {
111
- const html = isFullHTMLDocument(context.html)
112
- ? await this.handleFullHTMLDocument(context)
113
- : await this.wrapHTMLFragment(context);
64
+ let html;
65
+ if (isFullHTMLDocument(context.html)) {
66
+ let projectCSSPromise;
67
+ if (this.config.mode === "production" && context.options?.environment === "production") {
68
+ const mergedFrontmatter = this.mergeFrontmatter(context);
69
+ const htmlOptions = await profilePhase("html.build_options", () => this.buildHTMLOptions(context, mergedFrontmatter));
70
+ projectCSSPromise = this.startProjectCSSPreparation(context, htmlOptions);
71
+ }
72
+ html = await this.handleFullHTMLDocument(context, projectCSSPromise);
73
+ }
74
+ else {
75
+ html = await this.wrapHTMLFragment(context);
76
+ }
114
77
  const finalHtml = context.options?.studioEmbed ? injectElementSelectors(html) : html;
115
78
  if (context.options?.studioEmbed) {
116
79
  logger.debug("Injected element selectors for Studio");
117
80
  }
118
- return addNonceToRenderedTags(finalHtml, context.options?.nonce);
81
+ return addNonceToHtmlTags(finalHtml, context.options?.nonce);
119
82
  }
120
83
  async generateHTMLStream(reactStream, context) {
121
84
  const fullContext = context;
@@ -135,9 +98,22 @@ export class HTMLGenerator {
135
98
  });
136
99
  reactContent = error.partialContent.trim();
137
100
  }
101
+ if (isFullHTMLDocument(reactContent)) {
102
+ const encoder = new TextEncoder();
103
+ const fullHtml = addNonceToHtmlTags(await this.handleFullHTMLDocument({
104
+ ...fullContext,
105
+ html: reactContent,
106
+ }, projectCSSPromise), context.options?.nonce);
107
+ return new ReadableStream({
108
+ start(controller) {
109
+ controller.enqueue(encoder.encode(fullHtml));
110
+ controller.close();
111
+ },
112
+ });
113
+ }
138
114
  const { start, end } = await profilePhase("html.generate_shell_parts", () => this.generateShellParts(fullContext, mergedFrontmatter, htmlOptions, reactContent, projectCSSPromise));
139
115
  const encoder = new TextEncoder();
140
- const fullHtml = addNonceToRenderedTags(`${start}${reactContent}${end}`, context.options?.nonce);
116
+ const fullHtml = addNonceToHtmlTags(`${start}${reactContent}${end}`, context.options?.nonce);
141
117
  return new ReadableStream({
142
118
  start(controller) {
143
119
  controller.enqueue(encoder.encode(fullHtml));
@@ -145,7 +121,7 @@ export class HTMLGenerator {
145
121
  },
146
122
  });
147
123
  }
148
- async handleFullHTMLDocument(context) {
124
+ async handleFullHTMLDocument(context, projectCSSPromise) {
149
125
  const metadata = extractHTMLMetadata((context.pageInfo.entity.frontmatter || {}), (context.layoutBundle?.frontmatter || {}));
150
126
  const pagePath = context.pageInfo.entity.path;
151
127
  const [isClientPage, importMapJson] = await Promise.all([
@@ -155,7 +131,9 @@ export class HTMLGenerator {
155
131
  config: this.config.config,
156
132
  }),
157
133
  ]);
158
- const injectedHtml = injectHTMLContent(context.html, "", metadata, {
134
+ const themedHtml = injectThemePersistenceScript(applyExplicitThemeToDocument(context.html, context.options?.colorScheme, context.options?.colorSchemeFromParam), context.options?.colorScheme, context.options?.colorSchemeFromParam, context.options?.nonce);
135
+ const projectStylesheetHref = await this.resolveProjectStylesheetHref(context, projectCSSPromise);
136
+ const injectedHtml = injectHTMLContent(themedHtml, "", metadata, {
159
137
  mode: this.config.mode,
160
138
  slug: context.slug,
161
139
  devPort: this.config.config?.dev?.port || DEFAULT_DASHBOARD_PORT,
@@ -166,11 +144,25 @@ export class HTMLGenerator {
166
144
  isLocalProject: this.config.mode === "development",
167
145
  nonce: context.options?.nonce,
168
146
  importMapJson,
147
+ projectStylesheetHref,
169
148
  });
170
149
  if (injectedHtml.trimStart().toLowerCase().startsWith("<!doctype"))
171
150
  return injectedHtml;
172
151
  return `<!DOCTYPE html>\n${injectedHtml}`;
173
152
  }
153
+ async resolveProjectStylesheetHref(context, projectCSSPromise) {
154
+ if (!projectCSSPromise)
155
+ return undefined;
156
+ const projectCSS = await profilePhase("html.project_css", () => projectCSSPromise);
157
+ const cssHash = projectCSS?.hash ?? "";
158
+ if (cssHash)
159
+ return `/_vf/css/${cssHash}.css`;
160
+ logger.error("Project CSS hash is empty for full-document HTML", {
161
+ slug: context.slug,
162
+ environment: context.options?.environment,
163
+ });
164
+ return undefined;
165
+ }
174
166
  async detectUseClientDirective(pagePath) {
175
167
  try {
176
168
  const pageContent = await this.config.adapter.fs.readFile(pagePath);
@@ -152,6 +152,7 @@ async function generateFullHtml(htmlBody, context) {
152
152
  mode: options.mode,
153
153
  slug,
154
154
  devPort: options.config?.dev?.port ?? DEFAULT_DASHBOARD_PORT,
155
+ nonce: options.nonce,
155
156
  });
156
157
  }
157
158
  const htmlOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"framework-candidates.generated.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/framework-candidates.generated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EA2wKjD,CAAC"}
1
+ {"version":3,"file":"framework-candidates.generated.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/framework-candidates.generated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAoxKjD,CAAC"}
@@ -1040,6 +1040,7 @@ export const FRAMEWORK_CANDIDATES = [
1040
1040
  "Hover",
1041
1041
  "HydratingChatRootFixture():",
1042
1042
  "HydratingChatStyleProviderFixture():",
1043
+ "HydratingColorModeScriptFixture():",
1043
1044
  "HydratingHeadStyleFixture():",
1044
1045
  "I",
1045
1046
  "IconElementSpec",
@@ -2039,6 +2040,7 @@ export const FRAMEWORK_CANDIDATES = [
2039
2040
  "as",
2040
2041
  "asking",
2041
2042
  "assert(root,",
2043
+ "assert(script,",
2042
2044
  "assert(style,",
2043
2045
  "assert,",
2044
2046
  "assertEquals",
@@ -3156,6 +3158,7 @@ export const FRAMEWORK_CANDIDATES = [
3156
3158
  "hover:underline",
3157
3159
  "href={doc.url}",
3158
3160
  "href={props.href}",
3161
+ "html",
3159
3162
  "html.replaceAll(",
3160
3163
  "html:",
3161
3164
  "html>",
@@ -3169,6 +3172,8 @@ export const FRAMEWORK_CANDIDATES = [
3169
3172
  "https://example.com/",
3170
3173
  "hydrateAndReadManagedHeadStyleNonce(",
3171
3174
  "hydrateAndReadManagedHeadStyleNonce(<HydratingHeadStyleFixture",
3175
+ "hydrateAndReadScriptNonce(<HydratingColorModeScriptFixture",
3176
+ "hydrateAndReadScriptNonce(element:",
3172
3177
  "hydrateAndReadStyleNonce(<HydratingChatRootFixture",
3173
3178
  "hydrateAndReadStyleNonce(<HydratingChatStyleProviderFixture",
3174
3179
  "hydrateAndReadStyleNonce(element:",
@@ -3237,6 +3242,8 @@ export const FRAMEWORK_CANDIDATES = [
3237
3242
  "initialContent:",
3238
3243
  "initialContent={content}",
3239
3244
  "initialize(config:",
3245
+ "injectNonceIntoInlineTags(html:",
3246
+ "injectNonceIntoInlineTags(renderToString(element),",
3240
3247
  "injectNonceIntoStyleTags(html:",
3241
3248
  "injectNonceIntoStyleTags(renderToString(element),",
3242
3249
  "injected",
@@ -4380,6 +4387,7 @@ export const FRAMEWORK_CANDIDATES = [
4380
4387
  "replace(",
4381
4388
  "replace(/",
4382
4389
  "replace(/:",
4390
+ "replaceAll(",
4383
4391
  "requestAnimationFrame(()",
4384
4392
  "requestAnimationFrame:",
4385
4393
  "reset",
@@ -4456,6 +4464,7 @@ export const FRAMEWORK_CANDIDATES = [
4456
4464
  "score:",
4457
4465
  "score?:",
4458
4466
  "script",
4467
+ "script.getAttribute(",
4459
4468
  "script[nonce],",
4460
4469
  "script}",
4461
4470
  "scrollAreaRef",
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-response-builder.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/ssr/ssr-response-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AAGxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAElF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAWrF;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAuD3B"}
1
+ {"version":3,"file":"ssr-response-builder.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/ssr/ssr-response-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AAGxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAElF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAGrF;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA2D3B"}
@@ -10,11 +10,7 @@ import * as dntShim from "../../../../../_dnt.shims.js";
10
10
  import { hasMatchingEtag } from "../../utils/etag.js";
11
11
  import { getContentType } from "../../utils/content-types.js";
12
12
  import { ErrorPages } from "../../../utils/error-html.js";
13
- import { escapeHtml } from "../../../../html/html-escape.js";
14
- function addNonceToInlineTags(html, nonce) {
15
- const escapedNonce = escapeHtml(nonce);
16
- return html.replace(/<(script|style)\b(?![^>]*\bnonce\s*=)([^>]*)>/giu, `<$1$2 nonce="${escapedNonce}">`);
17
- }
13
+ import { addNonceToHtmlStream, addNonceToHtmlTags } from "../../../../html/nonce-injection.js";
18
14
  /**
19
15
  * Build an HTTP response from an SSR render result.
20
16
  *
@@ -31,7 +27,7 @@ export async function buildSSRResponse(req, ctx, result, builder) {
31
27
  .withSecurity(ctx.securityConfig ?? undefined, req)
32
28
  .withClientHints()
33
29
  .withCache("no-cache")
34
- .withContentType(getContentType(".html"), result.stream, result.status);
30
+ .withContentType(getContentType(".html"), addNonceToHtmlStream(result.stream, builder.nonce), result.status);
35
31
  if (!isHeadRequest)
36
32
  return response;
37
33
  await response.body?.cancel().catch(() => { });
@@ -51,7 +47,7 @@ export async function buildSSRResponse(req, ctx, result, builder) {
51
47
  : typeof result.stream === "string"
52
48
  ? result.stream
53
49
  : ErrorPages.serverError();
54
- const html = addNonceToInlineTags(content, builder.nonce);
50
+ const html = addNonceToHtmlTags(content, builder.nonce);
55
51
  const body = isHeadRequest ? null : html;
56
52
  let response = builder
57
53
  .withCORS(req, ctx.securityConfig?.cors)
@@ -1 +1 @@
1
- {"version":3,"file":"static.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/static.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAUnG,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,EAAE,eAAe,CAOvB;IAEF,OAAO,CAAC,aAAa,CAA2B;IAEhD,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAazE,OAAO,CAAC,cAAc;CAiEvB"}
1
+ {"version":3,"file":"static.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/static.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBnG,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,EAAE,eAAe,CAOvB;IAEF,OAAO,CAAC,aAAa,CAA2B;IAEhD,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAazE,OAAO,CAAC,cAAc;CAuEvB"}
@@ -3,6 +3,11 @@ import { hasMatchingEtag } from "../utils/etag.js";
3
3
  import { HTTP_NOT_FOUND, HTTP_OK, PRIORITY_MEDIUM_STATIC, } from "../../../utils/constants/index.js";
4
4
  import { withSpan } from "../../../observability/tracing/otlp-setup.js";
5
5
  import { StaticFileService } from "../../services/static/index.js";
6
+ import { addNonceToHtmlTags } from "../../../html/nonce-injection.js";
7
+ import { computeEtag } from "../utils/etag.js";
8
+ function isHtmlResponse(contentType) {
9
+ return /\btext\/html\b/i.test(contentType);
10
+ }
6
11
  export class StaticHandler extends BaseHandler {
7
12
  metadata = {
8
13
  name: "StaticHandler",
@@ -31,6 +36,8 @@ export class StaticHandler extends BaseHandler {
31
36
  const isHead = method === "HEAD";
32
37
  const isLocal = !!ctx.isLocalProject;
33
38
  const isPreviewMode = ctx.requestContext?.mode === "preview" && !isLocal;
39
+ const builder = this.createResponseBuilder(ctx)
40
+ .withCORS(req, ctx.securityConfig?.cors);
34
41
  const result = await this.staticService.resolveFile(pathname, {
35
42
  projectDir: ctx.projectDir,
36
43
  adapter: ctx.adapter,
@@ -40,24 +47,25 @@ export class StaticHandler extends BaseHandler {
40
47
  if (!result) {
41
48
  if (!this.staticService.isAssetRequest(pathname))
42
49
  return null;
43
- return this.createResponseBuilder(ctx)
44
- .withCORS(req, ctx.securityConfig?.cors)
50
+ return builder
45
51
  .withSecurity(ctx.securityConfig ?? undefined, req)
46
52
  .withCache("no-cache")
47
53
  .withContentType("text/plain; charset=utf-8", isHead ? null : "Not Found", HTTP_NOT_FOUND);
48
54
  }
49
- if (hasMatchingEtag(req, result.etag)) {
50
- return this.createResponseBuilder(ctx)
51
- .withCORS(req, ctx.securityConfig?.cors)
55
+ const responseData = isHtmlResponse(result.contentType)
56
+ ? new TextEncoder().encode(addNonceToHtmlTags(new TextDecoder().decode(result.data), builder.nonce))
57
+ : result.data;
58
+ const etag = computeEtag(responseData);
59
+ if (hasMatchingEtag(req, etag)) {
60
+ return builder
52
61
  .withSecurity(ctx.securityConfig ?? undefined, req)
53
- .notModified(result.etag);
62
+ .notModified(etag);
54
63
  }
55
- const body = isHead ? null : result.data.slice();
56
- const response = this.createResponseBuilder(ctx)
57
- .withCORS(req, ctx.securityConfig?.cors)
64
+ const body = isHead ? null : responseData.slice();
65
+ const response = builder
58
66
  .withSecurity(ctx.securityConfig ?? undefined, req)
59
67
  .withCache(result.cacheStrategy)
60
- .withETag(result.etag)
68
+ .withETag(etag)
61
69
  .withContentType(result.contentType, body, HTTP_OK);
62
70
  this.logDebug(`Served static file: ${result.path}`, {
63
71
  contentType: result.contentType,
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/src/tool/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAiIzE,wBAAgB,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACtD,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAkCvB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC7C,GAAG,CAAC,EAAE;QACJ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;KACpD,CAAC;CACH;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAwB7E"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/src/tool/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAwIzE,wBAAgB,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACtD,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAqCvB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC7C,GAAG,CAAC,EAAE;QACJ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;KACpD,CAAC;CACH;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CA2B7E"}
@@ -68,10 +68,17 @@ let toolIdCounter = 0;
68
68
  function generateToolId() {
69
69
  return `tool_${Date.now()}_${toolIdCounter++}`;
70
70
  }
71
+ function markGeneratedToolId(tool) {
72
+ return {
73
+ ...tool,
74
+ __veryfrontGeneratedId: tool.id,
75
+ };
76
+ }
71
77
  export function tool(config) {
72
- const id = config.id || generateToolId();
78
+ const explicitId = typeof config.id === "string" && config.id.length > 0 ? config.id : undefined;
79
+ const id = explicitId ?? generateToolId();
73
80
  const inputSchemaJson = convertSchemaToJson(config.inputSchema, id, "TOOL", config.allowUnknownSchema ?? false);
74
- return {
81
+ const createdTool = {
75
82
  id,
76
83
  type: "function",
77
84
  description: config.description,
@@ -93,11 +100,13 @@ export function tool(config) {
93
100
  },
94
101
  mcp: config.mcp,
95
102
  };
103
+ return explicitId ? createdTool : markGeneratedToolId(createdTool);
96
104
  }
97
105
  export function dynamicTool(config) {
98
- const id = config.id || generateToolId();
106
+ const explicitId = typeof config.id === "string" && config.id.length > 0 ? config.id : undefined;
107
+ const id = explicitId ?? generateToolId();
99
108
  const inputSchemaJson = convertSchemaToJson(config.inputSchema, id, "DYNAMIC_TOOL", true);
100
- return {
109
+ const createdTool = {
101
110
  id,
102
111
  type: "dynamic",
103
112
  description: config.description,
@@ -118,4 +127,5 @@ export function dynamicTool(config) {
118
127
  },
119
128
  mcp: config.mcp,
120
129
  };
130
+ return explicitId ? createdTool : markGeneratedToolId(createdTool);
121
131
  }
@@ -60,6 +60,8 @@ type ToolType = "function" | "dynamic";
60
60
  export interface Tool<TInput = any, TOutput = any> {
61
61
  /** Tool ID */
62
62
  id: string;
63
+ /** Internal marker used to distinguish autogenerated placeholder ids from explicit ids. */
64
+ __veryfrontGeneratedId?: string;
63
65
  /**
64
66
  * Tool type discriminator
65
67
  * - 'function': Standard tool with known types (default)
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/tool/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;GAEG;AAEH,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG;IACrD,yDAAyD;IACzD,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IAEpB,gCAAgC;IAChC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAEvF,wBAAwB;IACxB,GAAG,CAAC,EAAE;QACJ,qBAAqB;QACrB,OAAO,CAAC,EAAE,OAAO,CAAC;QAElB,6BAA6B;QAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;QAEvB,mBAAmB;QACnB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;KACpD,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,sDAAsD;IACtD,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;GAIG;AACH,KAAK,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvC;;GAEG;AAEH,MAAM,WAAW,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG;IAC/C,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IAEX;;;;OAIG;IACH,IAAI,EAAE,QAAQ,CAAC;IAEf,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IAEpB,yBAAyB;IACzB,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,eAAe,CAAC,EAAE,UAAU,CAAC;IAE7B;;OAEG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7E,wBAAwB;IACxB,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;CACxB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/tool/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;GAEG;AAEH,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG;IACrD,yDAAyD;IACzD,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IAEpB,gCAAgC;IAChC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAEvF,wBAAwB;IACxB,GAAG,CAAC,EAAE;QACJ,qBAAqB;QACrB,OAAO,CAAC,EAAE,OAAO,CAAC;QAElB,6BAA6B;QAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;QAEvB,mBAAmB;QACnB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;KACpD,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,sDAAsD;IACtD,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;GAIG;AACH,KAAK,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvC;;GAEG;AAEH,MAAM,WAAW,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG;IAC/C,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IACX,2FAA2F;IAC3F,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,IAAI,EAAE,QAAQ,CAAC;IAEf,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IAEpB,yBAAyB;IACzB,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,eAAe,CAAC,EAAE,UAAU,CAAC;IAE7B;;OAEG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7E,wBAAwB;IACxB,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;CACxB"}
@@ -9,6 +9,7 @@ export declare const FRAMEWORK_ROOT: string;
9
9
  export declare const EMBEDDED_SRC_DIR: string;
10
10
  export declare const FRAMEWORK_LOOKUPS: Array<[prefix: string, frameworkDir: string]>;
11
11
  export declare const frameworkWriteFlight: Singleflight<string>;
12
+ export declare const frameworkTransformFlight: Singleflight<string>;
12
13
  export declare const veryfrontTransformCache: Map<string, string>;
13
14
  export declare const frameworkFileCache: Map<string, string>;
14
15
  export declare const transformingFiles: Set<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAG7C,eAAO,MAAM,UAAU,UAAiC,CAAC;AASzD,eAAO,MAAM,cAAc,QAAyB,CAAC;AAKrD,eAAO,MAAM,gBAAgB,QAAwD,CAAC;AAKtF,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,CAK3E,CAAC;AAGF,eAAO,MAAM,oBAAoB,sBAA6B,CAAC;AAG/D,eAAO,MAAM,uBAAuB,qBAA4B,CAAC;AAGjE,eAAO,MAAM,kBAAkB,qBAA4B,CAAC;AAG5D,eAAO,MAAM,iBAAiB,aAAoB,CAAC;AAGnD,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;CACzC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAG7C,eAAO,MAAM,UAAU,UAAiC,CAAC;AASzD,eAAO,MAAM,cAAc,QAAyB,CAAC;AAKrD,eAAO,MAAM,gBAAgB,QAAwD,CAAC;AAKtF,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,CAK3E,CAAC;AAGF,eAAO,MAAM,oBAAoB,sBAA6B,CAAC;AAI/D,eAAO,MAAM,wBAAwB,sBAA6B,CAAC;AAGnE,eAAO,MAAM,uBAAuB,qBAA4B,CAAC;AAGjE,eAAO,MAAM,kBAAkB,qBAA4B,CAAC;AAG5D,eAAO,MAAM,iBAAiB,aAAoB,CAAC;AAGnD,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;CACzC"}
@@ -29,6 +29,9 @@ export const FRAMEWORK_LOOKUPS = [
29
29
  ];
30
30
  // Singleflight for framework module file writes to prevent race conditions
31
31
  export const frameworkWriteFlight = new Singleflight();
32
+ // Singleflight for top-level framework source transforms so concurrent user
33
+ // modules importing the same veryfront/* module do not receive cycle placeholders.
34
+ export const frameworkTransformFlight = new Singleflight();
32
35
  // Cache for already-transformed #veryfront/ dependencies to avoid cycles and redundant work
33
36
  export const veryfrontTransformCache = new Map();
34
37
  // Cache for transformed framework files by absolute path to prevent cycles and redundant work
@@ -1 +1 @@
1
- {"version":3,"file":"import-finder.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/import-finder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAY1D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB1D"}
1
+ {"version":3,"file":"import-finder.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/import-finder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAc1D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB1D"}
@@ -8,8 +8,10 @@
8
8
  export function findVfModuleImports(code) {
9
9
  const imports = [];
10
10
  // Note: \s* allows zero whitespace (minified code: from"..." has no space)
11
- // Only match _veryfront/ framework modules, not user project files
12
- const pattern = /from\s*["'](\/\_vf\_modules\/_veryfront\/[^"']+)["']/g;
11
+ // Only match _veryfront/ framework modules, not user project files.
12
+ // Handle both raw "/_vf_modules/..." specifiers and malformed
13
+ // "file:///_vf_modules/..." variants that can leak out of stale caches.
14
+ const pattern = /from\s*["']((?:file:\/\/)?\/_vf_modules\/_veryfront\/[^"']+)["']/g;
13
15
  let match;
14
16
  while ((match = pattern.exec(code)) !== null) {
15
17
  imports.push(match[1]);
@@ -15,7 +15,7 @@ import { resolveAndTransformVeryfrontImport } from "./transform.js";
15
15
  export { findRelativeImports, findVfModuleImports } from "./import-finder.js";
16
16
  export { resolveFrameworkFile, resolveRelativeFrameworkImport, resolveVeryfrontSourcePath, tryReadWithExtensions, } from "./path-resolver.js";
17
17
  export { cacheTransformedCode, isCyclePlaceholder, resolveAndTransformVeryfrontImport, transformFrameworkCode, transformFrameworkSource, } from "./transform.js";
18
- export { EMBEDDED_SRC_DIR, EXTENSIONS, FRAMEWORK_LOOKUPS, FRAMEWORK_ROOT, frameworkFileCache, frameworkWriteFlight, LOG_PREFIX, MAX_RELATIVE_IMPORT_DEPTH, type TransformContext, transformingFiles, veryfrontTransformCache, } from "./constants.js";
18
+ export { EMBEDDED_SRC_DIR, EXTENSIONS, FRAMEWORK_LOOKUPS, FRAMEWORK_ROOT, frameworkFileCache, frameworkTransformFlight, frameworkWriteFlight, LOG_PREFIX, MAX_RELATIVE_IMPORT_DEPTH, type TransformContext, transformingFiles, veryfrontTransformCache, } from "./constants.js";
19
19
  export declare const _testExports: {
20
20
  findVfModuleImports: typeof findVfModuleImports;
21
21
  findRelativeImports: typeof findRelativeImports;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,0BAA0B,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,kCAAkC,EAEnC,MAAM,gBAAgB,CAAC;AAUxB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kCAAkC,EAClC,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,UAAU,EACV,yBAAyB,EACzB,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AAexB,eAAO,MAAM,YAAY;;;;;;;;;;CAUxB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,eA+EhC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,0BAA0B,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,kCAAkC,EAEnC,MAAM,gBAAgB,CAAC;AAWxB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kCAAkC,EAClC,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,UAAU,EACV,yBAAyB,EACzB,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AAexB,eAAO,MAAM,YAAY;;;;;;;;;;CAUxB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,eAgFhC,CAAC"}