veryfront 0.1.1099 → 0.1.1100

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 (42) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/data/helpers.d.ts +21 -0
  3. package/esm/src/data/helpers.d.ts.map +1 -1
  4. package/esm/src/data/helpers.js +35 -0
  5. package/esm/src/data/server-data-fetcher.d.ts.map +1 -1
  6. package/esm/src/data/server-data-fetcher.js +17 -3
  7. package/esm/src/data/static-data-fetcher.d.ts.map +1 -1
  8. package/esm/src/data/static-data-fetcher.js +15 -2
  9. package/esm/src/html/hydration-script-builder/templates/renderer.d.ts.map +1 -1
  10. package/esm/src/html/hydration-script-builder/templates/renderer.js +36 -2
  11. package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
  12. package/esm/src/internal-agents/run-stream.js +8 -6
  13. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts +2 -0
  14. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts.map +1 -1
  15. package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.js +17 -16
  16. package/esm/src/tool/host-tools.d.ts.map +1 -1
  17. package/esm/src/tool/host-tools.js +3 -1
  18. package/esm/src/transforms/esm/transform-utils.d.ts +12 -0
  19. package/esm/src/transforms/esm/transform-utils.d.ts.map +1 -1
  20. package/esm/src/transforms/esm/transform-utils.js +10 -0
  21. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.d.ts +11 -0
  22. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.d.ts.map +1 -1
  23. package/esm/src/transforms/mdx/esm-module-loader/utils/source-spans.js +74 -0
  24. package/esm/src/transforms/pipeline/index.d.ts.map +1 -1
  25. package/esm/src/transforms/pipeline/index.js +3 -1
  26. package/esm/src/transforms/pipeline/stages/browser-node-builtin-imports.d.ts +33 -0
  27. package/esm/src/transforms/pipeline/stages/browser-node-builtin-imports.d.ts.map +1 -0
  28. package/esm/src/transforms/pipeline/stages/browser-node-builtin-imports.js +116 -0
  29. package/esm/src/transforms/pipeline/stages/browser-server-exports-strip.d.ts +45 -0
  30. package/esm/src/transforms/pipeline/stages/browser-server-exports-strip.d.ts.map +1 -0
  31. package/esm/src/transforms/pipeline/stages/browser-server-exports-strip.js +300 -0
  32. package/esm/src/transforms/pipeline/stages/compile.d.ts.map +1 -1
  33. package/esm/src/transforms/pipeline/stages/compile.js +2 -1
  34. package/esm/src/transforms/pipeline/stages/index.d.ts +2 -0
  35. package/esm/src/transforms/pipeline/stages/index.d.ts.map +1 -1
  36. package/esm/src/transforms/pipeline/stages/index.js +2 -0
  37. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts +11 -0
  38. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts.map +1 -1
  39. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.js +17 -0
  40. package/esm/src/utils/version-constant.d.ts +1 -1
  41. package/esm/src/utils/version-constant.js +1 -1
  42. package/package.json +5 -5
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.1099",
3
+ "version": "0.1.1100",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -3,4 +3,25 @@ import type { DataResult } from "./types.js";
3
3
  export declare function redirect(destination: string, permanent?: boolean): DataResult;
4
4
  /** Return a 404 result from a data loader. */
5
5
  export declare function notFound(): DataResult;
6
+ /**
7
+ * True when `value` is a control-flow result produced by {@link notFound} or
8
+ * {@link redirect}.
9
+ *
10
+ * These helpers are documented as return values, but `throw notFound()` reads
11
+ * naturally and is what people coming from other frameworks reach for. Thrown,
12
+ * the plain object is not an `Error`, so the SSR error handler stringified it
13
+ * to `[object Object]` and returned a 500 instead of the intended 404 or
14
+ * redirect. Recognising the shape lets a thrown result behave like a returned
15
+ * one.
16
+ */
17
+ export declare function isDataControlResult(value: unknown): value is DataResult;
18
+ /**
19
+ * Reduce a thrown control result to the shape a returned one produces.
20
+ *
21
+ * Callers apply this inside whatever wraps the data loader, not in an outer
22
+ * `catch`. A 404 is a routing decision, and a circuit breaker that sees it as a
23
+ * failure will open on the fifth legitimate one and fail every later data route
24
+ * for the project.
25
+ */
26
+ export declare function toDataControlResult(result: DataResult): DataResult;
6
27
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/src/data/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,UAAU,CAE3E;AAED,8CAA8C;AAC9C,wBAAgB,QAAQ,IAAI,UAAU,CAErC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/src/data/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,UAAU,CAE3E;AAED,8CAA8C;AAC9C,wBAAgB,QAAQ,IAAI,UAAU,CAErC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAUvE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAGlE"}
@@ -6,3 +6,38 @@ export function redirect(destination, permanent = false) {
6
6
  export function notFound() {
7
7
  return { notFound: true };
8
8
  }
9
+ /**
10
+ * True when `value` is a control-flow result produced by {@link notFound} or
11
+ * {@link redirect}.
12
+ *
13
+ * These helpers are documented as return values, but `throw notFound()` reads
14
+ * naturally and is what people coming from other frameworks reach for. Thrown,
15
+ * the plain object is not an `Error`, so the SSR error handler stringified it
16
+ * to `[object Object]` and returned a 500 instead of the intended 404 or
17
+ * redirect. Recognising the shape lets a thrown result behave like a returned
18
+ * one.
19
+ */
20
+ export function isDataControlResult(value) {
21
+ if (value === null || typeof value !== "object")
22
+ return false;
23
+ if (value instanceof Error)
24
+ return false;
25
+ const candidate = value;
26
+ if (candidate.notFound === true)
27
+ return true;
28
+ const destination = candidate.redirect?.destination;
29
+ return typeof destination === "string";
30
+ }
31
+ /**
32
+ * Reduce a thrown control result to the shape a returned one produces.
33
+ *
34
+ * Callers apply this inside whatever wraps the data loader, not in an outer
35
+ * `catch`. A 404 is a routing decision, and a circuit breaker that sees it as a
36
+ * failure will open on the fifth legitimate one and fail every later data route
37
+ * for the project.
38
+ */
39
+ export function toDataControlResult(result) {
40
+ if (result.redirect)
41
+ return { redirect: result.redirect };
42
+ return { notFound: true };
43
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"server-data-fetcher.d.ts","sourceRoot":"","sources":["../../../src/src/data/server-data-fetcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAaxE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,iBAAiB;IAC5B,KAAK,CACH,UAAU,EAAE,YAAY,EACxB,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,UAAU,CAAC;IA8EtB;;OAEG;YACW,aAAa;IAqE3B;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAGjB"}
1
+ {"version":3,"file":"server-data-fetcher.d.ts","sourceRoot":"","sources":["../../../src/src/data/server-data-fetcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAcxE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,iBAAiB;IAC5B,KAAK,CACH,UAAU,EAAE,YAAY,EACxB,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,UAAU,CAAC;IAuFtB;;OAEG;YACW,aAAa;IAqE3B;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAGjB"}
@@ -1,4 +1,5 @@
1
1
  import * as dntShim from "../../_dnt.shims.js";
2
+ import { isDataControlResult, toDataControlResult } from "./helpers.js";
2
3
  import { serverLogger } from "../utils/index.js";
3
4
  import { DATA_FETCH_TIMEOUT_MS } from "../config/defaults.js";
4
5
  import { TimeoutError, withTimeoutThrow } from "../rendering/utils/stream-utils.js";
@@ -26,9 +27,22 @@ export class ServerDataFetcher {
26
27
  return withSpan("data.fetch_server", async () => {
27
28
  const start = performance.now();
28
29
  try {
29
- const result = await circuitBreaker.execute(() => withTimeoutThrow(useIsolation
30
- ? this.fetchIsolated(options.modulePath, options.projectDir, context)
31
- : Promise.resolve(pageModule.getServerData(context)), DATA_FETCH_TIMEOUT_MS, `getServerData for ${pathname}`));
30
+ const result = await circuitBreaker.execute(async () => {
31
+ try {
32
+ return await withTimeoutThrow(useIsolation
33
+ ? this.fetchIsolated(options.modulePath, options.projectDir, context)
34
+ : Promise.resolve(pageModule.getServerData(context)), DATA_FETCH_TIMEOUT_MS, `getServerData for ${pathname}`);
35
+ }
36
+ catch (error) {
37
+ // `throw notFound()` / `throw redirect(...)`: treat a thrown
38
+ // control result exactly like a returned one. This has to happen
39
+ // inside the breaker, or five legitimate 404s on the same project
40
+ // open it and every data route after that fails fast for 30s.
41
+ if (isDataControlResult(error))
42
+ return toDataControlResult(error);
43
+ throw error;
44
+ }
45
+ });
32
46
  if (result.redirect)
33
47
  return { redirect: result.redirect };
34
48
  if (result.notFound)
@@ -1 +1 @@
1
- {"version":3,"file":"static-data-fetcher.d.ts","sourceRoot":"","sources":["../../../src/src/data/static-data-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA2DxE,qBAAa,iBAAiB;IAGhB,OAAO,CAAC,YAAY;IAFhC,OAAO,CAAC,oBAAoB,CAAoC;gBAE5C,YAAY,EAAE,YAAY;IAExC,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA4ChF,OAAO,CAAC,uBAAuB;IAM/B,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,eAAe;YAQT,iBAAiB;YA+BjB,UAAU;YAqEV,sBAAsB;IAoEpC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;CAIjB"}
1
+ {"version":3,"file":"static-data-fetcher.d.ts","sourceRoot":"","sources":["../../../src/src/data/static-data-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA2DxE,qBAAa,iBAAiB;IAGhB,OAAO,CAAC,YAAY;IAFhC,OAAO,CAAC,oBAAoB,CAAoC;gBAE5C,YAAY,EAAE,YAAY;IAExC,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA4ChF,OAAO,CAAC,uBAAuB;YAMjB,iBAAiB;IAuB/B,OAAO,CAAC,eAAe;YAQT,iBAAiB;YA+BjB,UAAU;YAqEV,sBAAsB;IAoEpC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;CAIjB"}
@@ -1,3 +1,4 @@
1
+ import { isDataControlResult, toDataControlResult } from "./helpers.js";
1
2
  import { serverLogger } from "../utils/index.js";
2
3
  import { DATA_FETCH_TIMEOUT_MS } from "../config/defaults.js";
3
4
  import { TimeoutError, withTimeoutThrow } from "../rendering/utils/stream-utils.js";
@@ -78,8 +79,20 @@ export class StaticDataFetcher {
78
79
  createStaticDataContext(context) {
79
80
  return { params: context.params, url: context.url };
80
81
  }
81
- executeStaticData(getStaticData, context, timeoutMs, label) {
82
- return withTimeoutThrow(Promise.resolve(getStaticData(this.createStaticDataContext(context))), timeoutMs, label);
82
+ async executeStaticData(getStaticData, context, timeoutMs, label) {
83
+ try {
84
+ return await withTimeoutThrow(Promise.resolve(getStaticData(this.createStaticDataContext(context))), timeoutMs, label);
85
+ }
86
+ catch (error) {
87
+ // `throw notFound()` / `throw redirect(...)`: treat a thrown control
88
+ // result exactly like a returned one. Normalising at the one place every
89
+ // path runs the handler covers the cached path as well as the preview
90
+ // one, and keeps a 404 from counting against the caller's circuit
91
+ // breaker.
92
+ if (isDataControlResult(error))
93
+ return toDataControlResult(error);
94
+ throw error;
95
+ }
83
96
  }
84
97
  storeCacheEntry(cacheKey, result) {
85
98
  this.cacheManager.set(cacheKey, {
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/renderer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,cA0P7B,CAAC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/renderer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,cA4R7B,CAAC"}
@@ -1,6 +1,19 @@
1
1
  export const getRendererScript = () => `
2
2
  // Note: DEBUG, log, logError are defined in router.ts which loads first
3
3
 
4
+ // True when a dynamic import failed because the module could not be
5
+ // fetched (404 / network), as opposed to being fetched and then failing to
6
+ // link or evaluate. Browsers report the former as a TypeError with a
7
+ // "dynamically imported module" message; link failures are SyntaxErrors and
8
+ // evaluation failures are whatever the module threw.
9
+ function isModuleNotFoundError(error) {
10
+ if (!error) return false;
11
+ if (error instanceof SyntaxError) return false;
12
+ const message = String((error && error.message) || error);
13
+ return /(?:Failed to fetch|error loading|Importing a module script failed|Failed to load)/i
14
+ .test(message);
15
+ }
16
+
4
17
  async function renderPage(pathname) {
5
18
  const resolvedPathname = (() => {
6
19
  const input = typeof pathname === 'string' ? pathname : window.location.pathname;
@@ -92,6 +105,8 @@ export const getRendererScript = () => `
92
105
  };
93
106
  }
94
107
 
108
+ let pageModuleError = null;
109
+
95
110
  if (data.pagePath) {
96
111
  const moduleUrl = shouldRenderRscClientPage
97
112
  ? '/_veryfront/rsc/module?rel=' + encodeURIComponent(data.pagePath)
@@ -101,6 +116,7 @@ export const getRendererScript = () => `
101
116
  try {
102
117
  pageModule = await import(moduleUrl);
103
118
  } catch (error) {
119
+ pageModuleError = error;
104
120
  logError('Failed to load page from hydration data:', error);
105
121
  }
106
122
  }
@@ -115,8 +131,26 @@ export const getRendererScript = () => `
115
131
  try {
116
132
  pageModule = await import(basePath + '.js');
117
133
  } catch (error) {
118
- if (pageSlug === 'index' || pageSlug.endsWith('/index')) throw error;
119
- pageModule = await import(basePath + '/index.js');
134
+ pageModuleError = pageModuleError || error;
135
+
136
+ // Only retry at <route>/index.js when the module genuinely could not
137
+ // be found. If it was found but failed to link or evaluate, retrying
138
+ // a path that does not exist replaces a precise error ("does not
139
+ // provide an export named 'createHash'") with a misleading 404.
140
+ const canRetryAsIndex = isModuleNotFoundError(error) &&
141
+ pageSlug !== 'index' && !pageSlug.endsWith('/index');
142
+
143
+ if (!canRetryAsIndex) throw pageModuleError;
144
+
145
+ try {
146
+ pageModule = await import(basePath + '/index.js');
147
+ } catch (indexError) {
148
+ // For a real <route>/index.tsx page, the first 404 was expected
149
+ // and this retry is the path that matters: if it reached a module
150
+ // and failed to link or evaluate, its error is the real one. Only
151
+ // when the retry 404s as well does the original describe more.
152
+ throw isModuleNotFoundError(indexError) ? pageModuleError : indexError;
153
+ }
120
154
  }
121
155
  }
122
156
 
@@ -1 +1 @@
1
- {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAY3B,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EAEL,KAAK,IAAI,EAGV,MAAM,kBAAkB,CAAC;AAe1B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAsCxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;IAC5C,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IACnE,8BAA8B,CAAC,EAAE,CAC/B,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAoCD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,sBAAsB,EACtC,2BAA2B,CAAC,EAAE,MAAM,EAAE,EACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;;cAsFrD;AAyVD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,QAAQ,CAAC,CA2anB"}
1
+ {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAY3B,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EAGL,KAAK,IAAI,EAGV,MAAM,kBAAkB,CAAC;AAe1B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAsCxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;IAC5C,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IACnE,8BAA8B,CAAC,EAAE,CAC/B,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAoCD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,sBAAsB,EACtC,2BAA2B,CAAC,EAAE,MAAM,EAAE,EACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;;cAsFrD;AA6VD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,QAAQ,CAAC,CA2anB"}
@@ -10,7 +10,7 @@ import { importFirstPartyExtensionModule } from "../extensions/first-party-impor
10
10
  import { SandboxShellToolsProviderName, } from "../extensions/sandbox/index.js";
11
11
  import { resolveHostedRuntimeAllowedToolNames } from "../agent/hosted/runtime-essential-tools.js";
12
12
  import { SKILL_TOOL_IDS } from "../skill/types.js";
13
- import { isToolVisibleTo, toolRegistry, } from "../tool/index.js";
13
+ import { createToolsFromHostDefinitions, isToolVisibleTo, toolRegistry, } from "../tool/index.js";
14
14
  import { addSpanEvent, setSpanAttributes, withSpan, } from "../observability/tracing/otlp-setup.js";
15
15
  import { defineSchema, lazySchema } from "../schemas/index.js";
16
16
  import { createStreamTransformState, finalizeRunEvents, formatAgUiEvent, mapRuntimeEventToAgUi, parseSseJsonEvents, } from "./ag-ui-sse.js";
@@ -210,15 +210,17 @@ async function buildProjectAgentSandboxTools(input) {
210
210
  : {}),
211
211
  getProjectId: () => sandboxConfig.projectId ?? input.deps.projectAgentSandbox?.projectId,
212
212
  });
213
- const bash = sandboxResult.tools[PROJECT_AGENT_SANDBOX_BASH_TOOL_NAME];
214
- if (!bash) {
213
+ const declaredTools = input.agent.config.tools;
214
+ const materializedTools = createToolsFromHostDefinitions(sandboxResult.tools);
215
+ const configuredTools = isRecord(declaredTools)
216
+ ? Object.fromEntries(Object.entries(materializedTools).filter(([toolName]) => declaredTools[toolName] === true))
217
+ : {};
218
+ if (!configuredTools[PROJECT_AGENT_SANDBOX_BASH_TOOL_NAME]) {
215
219
  await sandboxResult.closeSandbox();
216
220
  return {};
217
221
  }
218
222
  return {
219
- tools: {
220
- [PROJECT_AGENT_SANDBOX_BASH_TOOL_NAME]: bash,
221
- },
223
+ tools: configuredTools,
222
224
  closeSandbox: sandboxResult.closeSandbox,
223
225
  };
224
226
  }
@@ -8,6 +8,8 @@ export type ResolvedModuleDependency = {
8
8
  relativePath: string;
9
9
  depFilePath: string | null;
10
10
  isLocalLib: boolean;
11
+ /** True when discovered inside `import("…")` rather than a static import. */
12
+ isDynamic: boolean;
11
13
  };
12
14
  /** Resolved dependency after its source module has been transformed to a temp file. */
13
15
  export type TransformedModuleDependency = ResolvedModuleDependency & {
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/dependency-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAczE,sEAAsE;AACtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,GAAG;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,sEAAsE;AACtE,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;CACzB;AAgGD,yEAAyE;AACzE,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAuBrC;AAED,2EAA2E;AAC3E,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,2BAA2B,EAAE,GAC7C,MAAM,CAQR"}
1
+ {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/dependency-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA4BzE,sEAAsE;AACtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,GAAG;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,sEAAsE;AACtE,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;CACzB;AA4GD,yEAAyE;AACzE,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAuBrC;AAED,2EAA2E;AAC3E,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,2BAA2B,EAAE,GAC7C,MAAM,CAUR"}
@@ -1,25 +1,23 @@
1
1
  import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
2
2
  import { parallelMap, rendererLogger } from "../../../utils/index.js";
3
- import { findStaticImportFromSpans, replaceSourceSpans, } from "../../../transforms/mdx/esm-module-loader/utils/source-spans.js";
3
+ import { findDynamicImportSpans, findStaticImportFromSpans, replaceSourceSpans, } from "../../../transforms/mdx/esm-module-loader/utils/source-spans.js";
4
4
  import { findSourceFile } from "../file-resolver/index.js";
5
5
  const logger = rendererLogger.component("module-loader");
6
+ const matchAlias = (specifier) => specifier.startsWith("@/") ? specifier : null;
7
+ const matchRelative = (specifier) => specifier.match(/^(\.\.?\/[^?]+)(?:\?.*)?$/)?.[1];
6
8
  function collectAliasImports(fileContent) {
7
- return findStaticImportFromSpans(fileContent, (specifier) => specifier.startsWith("@/") ? specifier : null).map(({ original, path, start, end }) => ({
8
- full: original,
9
- path,
10
- start,
11
- end,
12
- }));
9
+ const toAlias = (isDynamic) => ({ original, path, start, end }) => ({ full: original, path, start, end, isDynamic });
10
+ return [
11
+ ...findStaticImportFromSpans(fileContent, matchAlias).map(toAlias(false)),
12
+ ...findDynamicImportSpans(fileContent, matchAlias).map(toAlias(true)),
13
+ ];
13
14
  }
14
15
  function collectRelativeImports(fileContent, fileDir) {
15
- return findStaticImportFromSpans(fileContent, (specifier) => specifier.match(/^(\.\.?\/[^?]+)(?:\?.*)?$/)?.[1])
16
- .map(({ original, path, start, end }) => ({
17
- full: original,
18
- path,
19
- fromDir: fileDir,
20
- start,
21
- end,
22
- }))
16
+ const toRelative = (isDynamic) => ({ original, path, start, end }) => ({ full: original, path, fromDir: fileDir, start, end, isDynamic });
17
+ return [
18
+ ...findStaticImportFromSpans(fileContent, matchRelative).map(toRelative(false)),
19
+ ...findDynamicImportSpans(fileContent, matchRelative).map(toRelative(true)),
20
+ ]
23
21
  // Ignore already-transformed file:// imports.
24
22
  .filter((imp) => !imp.path.includes("file://"));
25
23
  }
@@ -70,6 +68,7 @@ async function resolveRelativeImport(imp, adapter) {
70
68
  relativePath: imp.path,
71
69
  depFilePath,
72
70
  isLocalLib: false,
71
+ isDynamic: imp.isDynamic,
73
72
  };
74
73
  }
75
74
  /** Resolves @/ alias and relative local imports from a source module. */
@@ -94,7 +93,9 @@ export function rewriteResolvedDependencyImports(fileContent, transformedDeps) {
94
93
  start: dep.start,
95
94
  end: dep.end,
96
95
  expected: dep.full,
97
- replacement: `from "file://${dep.depTempPath}"`,
96
+ // A dynamic span covers only the quoted specifier; a static one covers the
97
+ // whole `from "…"` clause.
98
+ replacement: dep.isDynamic ? `"file://${dep.depTempPath}"` : `from "file://${dep.depTempPath}"`,
98
99
  }));
99
100
  return replaceSourceSpans(fileContent, replacements);
100
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"host-tools.d.ts","sourceRoot":"","sources":["../../../src/src/tool/host-tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAU,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElF,KAAK,eAAe,GAAG;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAChG,CAAC,gBAAgB,CAAC,CAAC;AAEpB,gCAAgC;AAChC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,eAAe,CAAC;IAC5C,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;CACzB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAQ7D,qDAAqD;AACrD,MAAM,WAAW,8BAA8B;IAC7C,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACnD;AAuDD,0CAA0C;AAC1C,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,WAAW,EACxB,OAAO,CAAC,EAAE,8BAA8B,GACvC,OAAO,CAAC;AACX,0CAA0C;AAC1C,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE,8BAA8B,GACvC,OAAO,CAAC"}
1
+ {"version":3,"file":"host-tools.d.ts","sourceRoot":"","sources":["../../../src/src/tool/host-tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAU,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElF,KAAK,eAAe,GAAG;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAChG,CAAC,gBAAgB,CAAC,CAAC;AAEpB,gCAAgC;AAChC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,eAAe,CAAC;IAC5C,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;CACzB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAO7D,qDAAqD;AACrD,MAAM,WAAW,8BAA8B;IAC7C,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACnD;AA2DD,0CAA0C;AAC1C,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,WAAW,EACxB,OAAO,CAAC,EAAE,8BAA8B,GACvC,OAAO,CAAC;AACX,0CAA0C;AAC1C,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE,8BAA8B,GACvC,OAAO,CAAC"}
@@ -24,7 +24,9 @@ function isParserBackedPrecomputedSchema(input) {
24
24
  function isHostToolDefinition(value) {
25
25
  return (isRecord(value) &&
26
26
  typeof value.description === "string" &&
27
- (isSchemaLike(value.inputSchema) || isParserBackedPrecomputedSchema(value)) &&
27
+ (isSchemaLike(value.inputSchema) ||
28
+ isParserBackedPrecomputedSchema(value) ||
29
+ (value.inputSchema === undefined && isRecord(value.inputSchemaJson))) &&
28
30
  typeof value.execute === "function");
29
31
  }
30
32
  function defaultToolCallId(toolName) {
@@ -4,6 +4,18 @@ import type { Loader } from "../../extensions/bundler/index.js";
4
4
  * Use this for transform cache keys where a compact hash is preferred.
5
5
  */
6
6
  export declare function computeShortContentHash(content: string): Promise<string>;
7
+ /**
8
+ * esbuild feature overrides shared by every source transform.
9
+ *
10
+ * Import attributes post-date the `es20xx` targets we lower to, so esbuild
11
+ * would silently *drop* `with { type: "json" }` rather than fail. Every runtime
12
+ * that consumes this output requires the attribute to load a JSON module, so
13
+ * dropping it turns a working import into a load-time error:
14
+ * `Attempted to load JSON module without specifying "type": "json"`.
15
+ */
16
+ export declare const ESBUILD_SUPPORTED_FEATURES: {
17
+ readonly "import-attributes": true;
18
+ };
7
19
  export declare function getLoaderFromPath(filePath: string): Loader;
8
20
  export declare function needsTransform(filePath: string): boolean;
9
21
  //# sourceMappingURL=transform-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/transform-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAGhE;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExE;AAaD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD"}
1
+ {"version":3,"file":"transform-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/transform-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAGhE;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExE;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B;;CAAyC,CAAC;AAajF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD"}
@@ -6,6 +6,16 @@ import { shortHash } from "../../utils/hash-utils.js";
6
6
  export function computeShortContentHash(content) {
7
7
  return shortHash(content);
8
8
  }
9
+ /**
10
+ * esbuild feature overrides shared by every source transform.
11
+ *
12
+ * Import attributes post-date the `es20xx` targets we lower to, so esbuild
13
+ * would silently *drop* `with { type: "json" }` rather than fail. Every runtime
14
+ * that consumes this output requires the attribute to load a JSON module, so
15
+ * dropping it turns a working import into a load-time error:
16
+ * `Attempted to load JSON module without specifying "type": "json"`.
17
+ */
18
+ export const ESBUILD_SUPPORTED_FEATURES = { "import-attributes": true };
9
19
  const EXTENSION_LOADERS = {
10
20
  ".tsx": "tsx",
11
21
  ".ts": "ts",
@@ -18,6 +18,17 @@ export interface StaticImportSpan {
18
18
  type SpecifierMatcher = (specifier: string) => string | null | undefined;
19
19
  export declare function replaceSourceSpans(source: string, replacements: SourceSpanReplacement[]): string;
20
20
  export declare function findStaticImportFromSpans(source: string, matcher: SpecifierMatcher): StaticImportSpan[];
21
+ /**
22
+ * Find `import("…")` expressions with a literal specifier.
23
+ *
24
+ * The returned span covers the quoted specifier itself (quotes included), not
25
+ * the surrounding `import(...)`, so a replacement is a bare quoted string.
26
+ * Dynamic imports whose argument is not a string literal are skipped, since
27
+ * their target is only known at runtime. That includes an argument the literal
28
+ * merely starts: rewriting the `"./foo"` in `import("./foo" + suffix)` would
29
+ * build a path out of a resolved prefix and an unresolved tail.
30
+ */
31
+ export declare function findDynamicImportSpans(source: string, matcher: SpecifierMatcher): StaticImportSpan[];
21
32
  export declare function findStaticSideEffectImportSpans(source: string, matcher: SpecifierMatcher): StaticImportSpan[];
22
33
  export {};
23
34
  //# sourceMappingURL=source-spans.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-spans.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/utils/source-spans.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,KAAK,gBAAgB,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEzE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,qBAAqB,EAAE,GACpC,MAAM,CAkCR;AAqID,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,EAAE,CAoCpB;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,EAAE,CAqCpB"}
1
+ {"version":3,"file":"source-spans.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/utils/source-spans.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,KAAK,gBAAgB,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEzE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,qBAAqB,EAAE,GACpC,MAAM,CAkCR;AAyJD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,EAAE,CAoCpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,EAAE,CAwDpB;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,EAAE,CAqCpB"}
@@ -72,6 +72,23 @@ function skipWhitespace(source, index) {
72
72
  cursor++;
73
73
  return cursor;
74
74
  }
75
+ // Comments are legal wherever whitespace is, so a dynamic import can carry a
76
+ // bundler hint between the keyword, the parentheses and the specifier. Treating
77
+ // the comment as an unexpected character would leave the specifier unresolved.
78
+ function skipWhitespaceAndComments(source, index) {
79
+ let cursor = index;
80
+ while (cursor < source.length) {
81
+ const afterWhitespace = skipWhitespace(source, cursor);
82
+ const char = source[afterWhitespace];
83
+ const next = source[afterWhitespace + 1];
84
+ if (char === "/" && (next === "/" || next === "*")) {
85
+ cursor = skipIgnored(source, afterWhitespace);
86
+ continue;
87
+ }
88
+ return afterWhitespace;
89
+ }
90
+ return cursor;
91
+ }
75
92
  function nextStatementCursor(source, index) {
76
93
  const semicolon = source.indexOf(";", index);
77
94
  const newline = source.indexOf("\n", index);
@@ -164,6 +181,63 @@ export function findStaticImportFromSpans(source, matcher) {
164
181
  }
165
182
  return spans;
166
183
  }
184
+ /**
185
+ * Find `import("…")` expressions with a literal specifier.
186
+ *
187
+ * The returned span covers the quoted specifier itself (quotes included), not
188
+ * the surrounding `import(...)`, so a replacement is a bare quoted string.
189
+ * Dynamic imports whose argument is not a string literal are skipped, since
190
+ * their target is only known at runtime. That includes an argument the literal
191
+ * merely starts: rewriting the `"./foo"` in `import("./foo" + suffix)` would
192
+ * build a path out of a resolved prefix and an unresolved tail.
193
+ */
194
+ export function findDynamicImportSpans(source, matcher) {
195
+ const spans = [];
196
+ let cursor = 0;
197
+ while (cursor < source.length) {
198
+ const skipped = skipIgnored(source, cursor);
199
+ if (skipped !== cursor) {
200
+ cursor = skipped;
201
+ continue;
202
+ }
203
+ // `import` used as an expression: not preceded by an identifier char or a
204
+ // dot (which would make it `foo.import` or part of a longer word).
205
+ if (!source.startsWith("import", cursor) ||
206
+ isIdentifierChar(source[cursor - 1]) ||
207
+ source[cursor - 1] === "." ||
208
+ isIdentifierChar(source[cursor + "import".length])) {
209
+ cursor++;
210
+ continue;
211
+ }
212
+ const parenIndex = skipWhitespaceAndComments(source, cursor + "import".length);
213
+ if (source[parenIndex] !== "(") {
214
+ cursor++;
215
+ continue;
216
+ }
217
+ const quoteIndex = skipWhitespaceAndComments(source, parenIndex + 1);
218
+ const quoted = readQuotedSpecifier(source, quoteIndex);
219
+ if (!quoted) {
220
+ cursor = parenIndex + 1;
221
+ continue;
222
+ }
223
+ // The literal must be the whole first argument. `)` closes the call and `,`
224
+ // starts the import-attributes argument; anything else (`+`, a template
225
+ // continuation, a ternary) means the runtime specifier is not this string.
226
+ const afterSpecifier = skipWhitespaceAndComments(source, quoted.end);
227
+ const isWholeArgument = source[afterSpecifier] === ")" || source[afterSpecifier] === ",";
228
+ const matchedPath = isWholeArgument ? matcher(quoted.specifier) : null;
229
+ if (matchedPath) {
230
+ spans.push({
231
+ original: source.slice(quoteIndex, quoted.end),
232
+ path: matchedPath,
233
+ start: quoteIndex,
234
+ end: quoted.end,
235
+ });
236
+ }
237
+ cursor = quoted.end;
238
+ }
239
+ return spans;
240
+ }
167
241
  export function findStaticSideEffectImportSpans(source, matcher) {
168
242
  const spans = [];
169
243
  let cursor = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AA0HpB,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAyI1B;AAqBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CASjB;AAmCD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,SAAS,EACT,KAAK,EACL,KAAK,EACL,YAAY,GACb,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AA8HpB,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAyI1B;AAqBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CASjB;AAmCD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,SAAS,EACT,KAAK,EACL,KAAK,EACL,YAAY,GACb,MAAM,cAAc,CAAC"}
@@ -9,7 +9,7 @@ import { createTransformContext, formatTimingLog, recordStageTiming } from "./co
9
9
  import { withSpan } from "../../observability/tracing/otlp-setup.js";
10
10
  import { computeConfigHash } from "../../cache/config-hash.js";
11
11
  import { computeDepsHash } from "../../cache/dependency-graph.js";
12
- import { compilePlugin, cssStripPlugin, finalizePlugin, parsePlugin, resolveImportsPlugin, ssrHttpCachePlugin, ssrHttpStubPlugin, ssrVfModulesPlugin, } from "./stages/index.js";
12
+ import { browserNodeBuiltinImportsPlugin, browserServerExportsStripPlugin, compilePlugin, cssStripPlugin, finalizePlugin, parsePlugin, resolveImportsPlugin, ssrHttpCachePlugin, ssrHttpStubPlugin, ssrVfModulesPlugin, } from "./stages/index.js";
13
13
  import { createFileSystem, exists } from "../../platform/compat/fs.js";
14
14
  import { getHttpBundleCacheDir } from "../../utils/cache-dir.js";
15
15
  import { validateCachedBundlesByManifestOrCode } from "../esm/cached-bundle-validation.js";
@@ -28,6 +28,8 @@ const BROWSER_PIPELINE = [
28
28
  parsePlugin,
29
29
  compilePlugin,
30
30
  cssStripPlugin, // Strip CSS imports before they hit import resolution
31
+ browserServerExportsStripPlugin, // Drop server-only hooks + their now-unused imports
32
+ browserNodeBuiltinImportsPlugin, // node:* named imports -> namespace + destructure
31
33
  resolveImportsPlugin, // Unified import resolution
32
34
  finalizePlugin,
33
35
  ];
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Browser Node-Builtin Imports Stage — converts named imports of Node built-ins
3
+ * into namespace imports plus a destructure.
4
+ *
5
+ * Browser-bound imports of `node:*` are pointed at a noop polyfill whose whole
6
+ * job, per its own documentation, is that "the import succeeds, and any actual
7
+ * usage of the imported API fails at the call site, which surfaces the problem
8
+ * clearly instead of a cryptic module resolution error".
9
+ *
10
+ * That contract cannot hold for a *named* import. ESM resolves named imports at
11
+ * link time, so `import { createHash } from "node:crypto"` fails the whole
12
+ * module graph before a line of it runs:
13
+ *
14
+ * SyntaxError: The requested module '.../node-noop.js' does not provide an
15
+ * export named 'createHash'
16
+ *
17
+ * One leaked builtin therefore takes down hydration for the entire page, and the
18
+ * error names the polyfill rather than the offending import.
19
+ *
20
+ * Rewriting to a namespace import restores the intended behaviour: linking
21
+ * succeeds, the binding is `undefined`, and the failure happens where the API is
22
+ * actually called. It also makes the two node-noop variants (source and compiled
23
+ * binary, which export different names) behave identically.
24
+ */
25
+ import type { TransformPlugin } from "../types.js";
26
+ /**
27
+ * Rewrite `import { a, b as c } from "node:x"` to a namespace import plus a
28
+ * destructure. Default and namespace imports already link successfully and are
29
+ * left untouched.
30
+ */
31
+ export declare function rewriteNodeBuiltinNamedImports(code: string): Promise<string>;
32
+ export declare const browserNodeBuiltinImportsPlugin: TransformPlugin;
33
+ //# sourceMappingURL=browser-node-builtin-imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-node-builtin-imports.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/pipeline/stages/browser-node-builtin-imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAC;AA+CrE;;;;GAIG;AACH,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ClF;AAED,eAAO,MAAM,+BAA+B,EAAE,eAM7C,CAAC"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Browser Node-Builtin Imports Stage — converts named imports of Node built-ins
3
+ * into namespace imports plus a destructure.
4
+ *
5
+ * Browser-bound imports of `node:*` are pointed at a noop polyfill whose whole
6
+ * job, per its own documentation, is that "the import succeeds, and any actual
7
+ * usage of the imported API fails at the call site, which surfaces the problem
8
+ * clearly instead of a cryptic module resolution error".
9
+ *
10
+ * That contract cannot hold for a *named* import. ESM resolves named imports at
11
+ * link time, so `import { createHash } from "node:crypto"` fails the whole
12
+ * module graph before a line of it runs:
13
+ *
14
+ * SyntaxError: The requested module '.../node-noop.js' does not provide an
15
+ * export named 'createHash'
16
+ *
17
+ * One leaked builtin therefore takes down hydration for the entire page, and the
18
+ * error names the polyfill rather than the offending import.
19
+ *
20
+ * Rewriting to a namespace import restores the intended behaviour: linking
21
+ * succeeds, the binding is `undefined`, and the failure happens where the API is
22
+ * actually called. It also makes the two node-noop variants (source and compiled
23
+ * binary, which export different names) behave identically.
24
+ */
25
+ import { TransformStage } from "../types.js";
26
+ import { rewriteImports } from "../../esm/lexer.js";
27
+ const NAMESPACE_PREFIX = "__vf_node_builtin_";
28
+ /**
29
+ * Pick a namespace prefix the module has never used. A source file is free to
30
+ * declare or import `__vf_node_builtin_0` itself, and shadowing it would either
31
+ * duplicate the binding or silently redirect the user's own one.
32
+ *
33
+ * Substring containment is the right test even though it over-matches: every
34
+ * name we go on to generate starts with the prefix, so a module that never
35
+ * mentions the prefix cannot collide with any of them. That keeps this cheap on
36
+ * post-esbuild output, where parsing for real bindings is not an option.
37
+ */
38
+ function pickNamespacePrefix(code) {
39
+ let prefix = NAMESPACE_PREFIX;
40
+ while (code.includes(prefix))
41
+ prefix += "_";
42
+ return prefix;
43
+ }
44
+ /** Split a named-import clause into `local: imported` destructure pairs. */
45
+ function toDestructurePairs(namedClause) {
46
+ const pairs = [];
47
+ for (const rawPart of namedClause.split(",")) {
48
+ const part = rawPart.trim();
49
+ if (!part)
50
+ continue;
51
+ const alias = part.match(/^([_$a-zA-Z][\w$]*)\s+as\s+([_$a-zA-Z][\w$]*)$/);
52
+ if (alias?.[1] && alias[2]) {
53
+ pairs.push(`${alias[1]}: ${alias[2]}`);
54
+ continue;
55
+ }
56
+ if (/^[_$a-zA-Z][\w$]*$/.test(part)) {
57
+ pairs.push(part);
58
+ continue;
59
+ }
60
+ return null; // Unrecognised clause — leave the statement alone.
61
+ }
62
+ return pairs.length > 0 ? pairs : null;
63
+ }
64
+ /**
65
+ * Rewrite `import { a, b as c } from "node:x"` to a namespace import plus a
66
+ * destructure. Default and namespace imports already link successfully and are
67
+ * left untouched.
68
+ */
69
+ export async function rewriteNodeBuiltinNamedImports(code) {
70
+ if (!code.includes("node:"))
71
+ return code;
72
+ let counter = 0;
73
+ const prefix = pickNamespacePrefix(code);
74
+ return await rewriteImports(code, (imp, statement) => {
75
+ if (!imp.n?.startsWith("node:"))
76
+ return null;
77
+ if (imp.d > -1)
78
+ return null; // dynamic import resolves lazily already
79
+ if (!statement.startsWith("import"))
80
+ return null;
81
+ // The clause is everything between the `import` keyword and the specifier.
82
+ // Take it from the lexer's own offsets rather than by searching for
83
+ // " from ": esbuild emits `import{createHash as h}from"node:crypto";` when
84
+ // the build is minified, and there is no such substring in it.
85
+ const specifierStart = imp.s - imp.ss;
86
+ if (specifierStart <= "import".length || specifierStart > statement.length)
87
+ return null;
88
+ const clause = statement
89
+ .slice("import".length, specifierStart - 1) // -1 for the opening quote
90
+ .replace(/\bfrom\s*$/, "")
91
+ .trim();
92
+ if (clause === "")
93
+ return null; // side-effect-only import
94
+ const namedMatch = clause.match(/\{([^}]*)\}/);
95
+ if (!namedMatch?.[1])
96
+ return null; // no named bindings
97
+ const pairs = toDestructurePairs(namedMatch[1]);
98
+ if (!pairs)
99
+ return null;
100
+ const namespace = `${prefix}${counter++}`;
101
+ const source = JSON.stringify(imp.n);
102
+ // Anything left of the named clause (a default binding) keeps its own import.
103
+ const leading = clause.replace(/\{[^}]*\}/, "").replace(/,\s*$/, "").replace(/^\s*,/, "")
104
+ .trim();
105
+ const defaultImport = leading ? `import ${leading} from ${source};` : "";
106
+ return `${defaultImport}import * as ${namespace} from ${source};` +
107
+ `const { ${pairs.join(", ")} } = ${namespace};`;
108
+ });
109
+ }
110
+ export const browserNodeBuiltinImportsPlugin = {
111
+ name: "browser-node-builtin-imports",
112
+ // Before import resolution, while the specifier is still `node:*`.
113
+ stage: TransformStage.COMPILE + 0.7,
114
+ condition: (ctx) => ctx.target === "browser",
115
+ transform: (ctx) => rewriteNodeBuiltinNamedImports(ctx.code),
116
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Browser Server-Exports Strip Stage: empties server-only data hooks in the
3
+ * client artifact, then drops the import bindings that only they used.
4
+ *
5
+ * `getServerData`, `getStaticData` and `getStaticPaths` run exclusively on the
6
+ * server, but the browser artifact is compiled from the same source file. Their
7
+ * bodies therefore ship to the client along with everything they import, so a
8
+ * page whose loader reaches `node:crypto` links against the node-builtin noop
9
+ * polyfill and hydration dies with:
10
+ *
11
+ * The requested module '.../node-noop.js' does not provide an export
12
+ * named 'createHash'
13
+ *
14
+ * esbuild cannot solve this for us: in transform mode (as opposed to bundle
15
+ * mode) it never drops an import, because it cannot prove the module is free of
16
+ * side effects.
17
+ *
18
+ * The pass runs on the AST from the `CodeParser` contract, for the same reason
19
+ * `rendering/rsc/export-extractor.ts` does: a module is not text. Matching
20
+ * declarations by hand means a private function that shares a hook's name gets
21
+ * emptied, a `}` inside a regular expression literal ends a body early, and a
22
+ * minified statement parses differently from the one a developer wrote.
23
+ *
24
+ * Two rules keep it conservative:
25
+ *
26
+ * - Only an exported declaration is emptied. A private helper called
27
+ * `getServerData` is ordinary client code.
28
+ * - An import whose bindings all fall out of use is reduced to a side-effect
29
+ * import rather than deleted, because this pass knows nothing about the
30
+ * top-level code of the module it points at. Node built-ins are the
31
+ * exception: in the browser they resolve to a noop polyfill, so there is no
32
+ * side effect to keep. This matches what esbuild does with an external
33
+ * import whose bindings go unused.
34
+ *
35
+ * Anything that cannot be parsed leaves the module exactly as it was.
36
+ */
37
+ import type { TransformPlugin } from "../types.js";
38
+ /**
39
+ * Empty the server-only hooks in `code` and drop the import bindings they were
40
+ * the last user of. Returns `code` unchanged when there is nothing to do, when
41
+ * no parser is registered, or when the module does not parse.
42
+ */
43
+ export declare function stripServerOnlyExports(code: string, filePath?: string): Promise<string>;
44
+ export declare const browserServerExportsStripPlugin: TransformPlugin;
45
+ //# sourceMappingURL=browser-server-exports-strip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-server-exports-strip.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/pipeline/stages/browser-server-exports-strip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAC;AAoPrE;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B7F;AAED,eAAO,MAAM,+BAA+B,EAAE,eAO7C,CAAC"}
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Browser Server-Exports Strip Stage: empties server-only data hooks in the
3
+ * client artifact, then drops the import bindings that only they used.
4
+ *
5
+ * `getServerData`, `getStaticData` and `getStaticPaths` run exclusively on the
6
+ * server, but the browser artifact is compiled from the same source file. Their
7
+ * bodies therefore ship to the client along with everything they import, so a
8
+ * page whose loader reaches `node:crypto` links against the node-builtin noop
9
+ * polyfill and hydration dies with:
10
+ *
11
+ * The requested module '.../node-noop.js' does not provide an export
12
+ * named 'createHash'
13
+ *
14
+ * esbuild cannot solve this for us: in transform mode (as opposed to bundle
15
+ * mode) it never drops an import, because it cannot prove the module is free of
16
+ * side effects.
17
+ *
18
+ * The pass runs on the AST from the `CodeParser` contract, for the same reason
19
+ * `rendering/rsc/export-extractor.ts` does: a module is not text. Matching
20
+ * declarations by hand means a private function that shares a hook's name gets
21
+ * emptied, a `}` inside a regular expression literal ends a body early, and a
22
+ * minified statement parses differently from the one a developer wrote.
23
+ *
24
+ * Two rules keep it conservative:
25
+ *
26
+ * - Only an exported declaration is emptied. A private helper called
27
+ * `getServerData` is ordinary client code.
28
+ * - An import whose bindings all fall out of use is reduced to a side-effect
29
+ * import rather than deleted, because this pass knows nothing about the
30
+ * top-level code of the module it points at. Node built-ins are the
31
+ * exception: in the browser they resolve to a noop polyfill, so there is no
32
+ * side effect to keep. This matches what esbuild does with an external
33
+ * import whose bindings go unused.
34
+ *
35
+ * Anything that cannot be parsed leaves the module exactly as it was.
36
+ */
37
+ import { tryResolve } from "../../../extensions/contracts.js";
38
+ import { rendererLogger as logger } from "../../../utils/index.js";
39
+ import { TransformStage } from "../types.js";
40
+ /** Exports that only ever execute on the server. */
41
+ const SERVER_ONLY_EXPORTS = ["getServerData", "getStaticData", "getStaticPaths"];
42
+ /** Source the stub nodes are lifted from, so no node shape is hand-built. */
43
+ const STUB_SOURCE = `function __vfStub() { throw new Error("server-only"); }
44
+ const __vfStubInit = function () { throw new Error("server-only"); };`;
45
+ function isNode(value) {
46
+ return typeof value === "object" && value !== null &&
47
+ typeof value.type === "string";
48
+ }
49
+ function children(node) {
50
+ const found = [];
51
+ for (const [key, value] of Object.entries(node)) {
52
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments")
53
+ continue;
54
+ if (Array.isArray(value)) {
55
+ for (const entry of value)
56
+ if (isNode(entry))
57
+ found.push(entry);
58
+ continue;
59
+ }
60
+ if (isNode(value))
61
+ found.push(value);
62
+ }
63
+ return found;
64
+ }
65
+ /**
66
+ * Walk every node in the tree. Returning `false` from `visit` skips the
67
+ * subtree, which is how import statements stay out of the reference count.
68
+ */
69
+ function walk(node, visit) {
70
+ if (visit(node) === false)
71
+ return;
72
+ for (const child of children(node))
73
+ walk(child, visit);
74
+ }
75
+ function nodeName(value) {
76
+ if (!isNode(value))
77
+ return null;
78
+ const name = value.name;
79
+ return typeof name === "string" ? name : null;
80
+ }
81
+ function bodyOf(ast) {
82
+ const program = ast.program;
83
+ const source = isNode(program) ? program : ast;
84
+ const body = source.body;
85
+ return Array.isArray(body) ? body.filter(isNode) : [];
86
+ }
87
+ /** The stub body and stub initialiser, parsed rather than constructed. */
88
+ async function parseStubs(parser) {
89
+ const ast = await parser.parse({ code: STUB_SOURCE, filePath: "vf-stub.ts" });
90
+ const [fn, variable] = bodyOf(ast);
91
+ const body = fn?.body;
92
+ const declarations = variable?.declarations;
93
+ const init = Array.isArray(declarations) && isNode(declarations[0])
94
+ ? declarations[0].init
95
+ : undefined;
96
+ if (!isNode(body) || !isNode(init))
97
+ return null;
98
+ return { body, init };
99
+ }
100
+ /** Names this module exports from its own local declarations. */
101
+ function exportedLocalNames(body) {
102
+ const names = new Set();
103
+ for (const statement of body) {
104
+ if (statement.type !== "ExportNamedDeclaration")
105
+ continue;
106
+ if (statement.exportKind === "type")
107
+ continue;
108
+ // `export { getServerData }` and `export { getServerData as data }`: the
109
+ // local name is what a declaration in this module is called. The reverse,
110
+ // `export { other as getServerData }`, exports `other` and must not touch
111
+ // a same-named local.
112
+ for (const specifier of Array.isArray(statement.specifiers) ? statement.specifiers : []) {
113
+ if (!isNode(specifier))
114
+ continue;
115
+ if (specifier.exportKind === "type")
116
+ continue;
117
+ // A re-export (`export { x } from "./y"`) has no local declaration to
118
+ // empty, so recording the name is harmless.
119
+ const local = nodeName(specifier.local);
120
+ if (local)
121
+ names.add(local);
122
+ }
123
+ const declaration = statement.declaration;
124
+ if (!isNode(declaration))
125
+ continue;
126
+ const direct = nodeName(declaration.id);
127
+ if (direct)
128
+ names.add(direct);
129
+ for (const declarator of Array.isArray(declaration.declarations) ? declaration.declarations : []) {
130
+ if (!isNode(declarator))
131
+ continue;
132
+ const name = nodeName(declarator.id);
133
+ if (name)
134
+ names.add(name);
135
+ }
136
+ }
137
+ return names;
138
+ }
139
+ /**
140
+ * Empty the body of every exported server-only hook. Emptying rather than
141
+ * deleting keeps the binding, so an export clause or re-export stays valid.
142
+ */
143
+ function emptyServerOnlyHooks(body, exported, stubs) {
144
+ const targets = SERVER_ONLY_EXPORTS.filter((name) => exported.has(name));
145
+ if (targets.length === 0)
146
+ return false;
147
+ let changed = false;
148
+ const declarationsIn = (statement) => {
149
+ const declaration = statement.type === "ExportNamedDeclaration"
150
+ ? statement.declaration
151
+ : statement;
152
+ return isNode(declaration) ? [declaration] : [];
153
+ };
154
+ for (const statement of body) {
155
+ for (const declaration of declarationsIn(statement)) {
156
+ if (declaration.type === "FunctionDeclaration") {
157
+ const name = nodeName(declaration.id);
158
+ if (!name || !targets.includes(name))
159
+ continue;
160
+ declaration.body = structuredClone(stubs.body);
161
+ changed = true;
162
+ continue;
163
+ }
164
+ if (declaration.type !== "VariableDeclaration")
165
+ continue;
166
+ for (const declarator of Array.isArray(declaration.declarations) ? declaration.declarations : []) {
167
+ if (!isNode(declarator))
168
+ continue;
169
+ const name = nodeName(declarator.id);
170
+ if (!name || !targets.includes(name))
171
+ continue;
172
+ declarator.init = structuredClone(stubs.init);
173
+ changed = true;
174
+ }
175
+ }
176
+ }
177
+ return changed;
178
+ }
179
+ /**
180
+ * Identifiers the module reads, ignoring import statements and the positions
181
+ * where an identifier is a fixed name rather than a reference (`a.hashOf`,
182
+ * `{ hashOf: 1 }`). Over-counting only ever keeps an import.
183
+ */
184
+ function referencedIdentifiers(body) {
185
+ const referenced = new Set();
186
+ // Filled in as each parent is visited, which always happens before its
187
+ // children.
188
+ const fixedNames = new WeakSet();
189
+ const markFixedName = (node) => {
190
+ const property = node.type === "MemberExpression" || node.type === "OptionalMemberExpression"
191
+ ? node.property
192
+ : node.type === "ObjectProperty" || node.type === "ObjectMethod" ||
193
+ node.type === "ClassMethod" || node.type === "ClassProperty"
194
+ ? node.key
195
+ : undefined;
196
+ if (node.computed === true)
197
+ return;
198
+ if (isNode(property))
199
+ fixedNames.add(property);
200
+ };
201
+ for (const statement of body) {
202
+ if (statement.type === "ImportDeclaration")
203
+ continue;
204
+ walk(statement, (node) => {
205
+ if (node.type === "ImportDeclaration")
206
+ return false;
207
+ markFixedName(node);
208
+ if (node.type === "Identifier" || node.type === "JSXIdentifier") {
209
+ if (fixedNames.has(node))
210
+ return true;
211
+ const name = nodeName(node);
212
+ if (name)
213
+ referenced.add(name);
214
+ }
215
+ return true;
216
+ });
217
+ }
218
+ return referenced;
219
+ }
220
+ /** Local binding names an import statement introduces. */
221
+ function importedBindings(statement) {
222
+ const bindings = [];
223
+ for (const specifier of Array.isArray(statement.specifiers) ? statement.specifiers : []) {
224
+ if (!isNode(specifier))
225
+ continue;
226
+ const name = nodeName(specifier.local);
227
+ if (name)
228
+ bindings.push(name);
229
+ }
230
+ return bindings;
231
+ }
232
+ /**
233
+ * Reduce imports nothing references any more to side-effect imports, and drop
234
+ * them outright when they point at a Node built-in.
235
+ */
236
+ function dropUnusedImportBindings(body) {
237
+ const referenced = referencedIdentifiers(body);
238
+ return body.filter((statement) => {
239
+ if (statement.type !== "ImportDeclaration")
240
+ return true;
241
+ if (statement.importKind === "type")
242
+ return true;
243
+ const bindings = importedBindings(statement);
244
+ // Already a side-effect import: nothing to drop.
245
+ if (bindings.length === 0)
246
+ return true;
247
+ if (bindings.some((binding) => referenced.has(binding)))
248
+ return true;
249
+ const source = isNode(statement.source) ? statement.source.value : undefined;
250
+ if (typeof source === "string" && source.startsWith("node:"))
251
+ return false;
252
+ statement.specifiers = [];
253
+ return true;
254
+ });
255
+ }
256
+ function setBody(ast, body) {
257
+ const program = ast.program;
258
+ const target = isNode(program) ? program : ast;
259
+ target.body = body;
260
+ }
261
+ /**
262
+ * Empty the server-only hooks in `code` and drop the import bindings they were
263
+ * the last user of. Returns `code` unchanged when there is nothing to do, when
264
+ * no parser is registered, or when the module does not parse.
265
+ */
266
+ export async function stripServerOnlyExports(code, filePath) {
267
+ // Cheap pre-check: no mention of a hook means no parse.
268
+ if (!SERVER_ONLY_EXPORTS.some((name) => code.includes(name)))
269
+ return code;
270
+ const parser = tryResolve("CodeParser");
271
+ if (!parser)
272
+ return code;
273
+ try {
274
+ const stubs = await parseStubs(parser);
275
+ if (!stubs)
276
+ return code;
277
+ const ast = await parser.parse({ code, filePath: filePath ?? "module.tsx" });
278
+ const body = bodyOf(ast);
279
+ if (!emptyServerOnlyHooks(body, exportedLocalNames(body), stubs))
280
+ return code;
281
+ setBody(ast, dropUnusedImportBindings(body));
282
+ const generated = await parser.generate(ast);
283
+ return generated.code;
284
+ }
285
+ catch (error) {
286
+ logger.debug("Left the module unchanged", {
287
+ filePath,
288
+ reason: error instanceof Error ? error.message : String(error),
289
+ });
290
+ return code;
291
+ }
292
+ }
293
+ export const browserServerExportsStripPlugin = {
294
+ name: "browser-server-exports-strip",
295
+ // After esbuild compile and CSS strip, before any import resolution, so the
296
+ // dropped bindings are never rewritten or pre-fetched.
297
+ stage: TransformStage.COMPILE + 0.6,
298
+ condition: (ctx) => ctx.target === "browser",
299
+ transform: (ctx) => stripServerOnlyExports(ctx.code, ctx.filePath),
300
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/pipeline/stages/compile.ts"],"names":[],"mappings":"AAKA,OAAO,EAAyB,KAAK,eAAe,EAAkB,MAAM,aAAa,CAAC;AAI1F,eAAO,MAAM,aAAa,EAAE,eA4D3B,CAAC"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/pipeline/stages/compile.ts"],"names":[],"mappings":"AAKA,OAAO,EAAyB,KAAK,eAAe,EAAkB,MAAM,aAAa,CAAC;AAI1F,eAAO,MAAM,aAAa,EAAE,eA6D3B,CAAC"}
@@ -2,7 +2,7 @@ import { getEsbuild } from "../../../platform/compat/esbuild.js";
2
2
  import { rendererLogger } from "../../../utils/index.js";
3
3
  import { COMPILATION_ERROR } from "../../../errors/index.js";
4
4
  import { getErrorCollector } from "../../../observability/index.js";
5
- import { getLoaderFromPath } from "../../esm/transform-utils.js";
5
+ import { ESBUILD_SUPPORTED_FEATURES, getLoaderFromPath } from "../../esm/transform-utils.js";
6
6
  import { TransformStage } from "../types.js";
7
7
  const logger = rendererLogger.component("esm-transform");
8
8
  export const compilePlugin = {
@@ -16,6 +16,7 @@ export const compilePlugin = {
16
16
  loader,
17
17
  format: "esm",
18
18
  target: "es2020",
19
+ supported: ESBUILD_SUPPORTED_FEATURES,
19
20
  jsx: "automatic",
20
21
  jsxImportSource: ctx.jsxImportSource,
21
22
  minify: !ctx.dev,
@@ -6,6 +6,8 @@
6
6
  export { parsePlugin } from "./parse.js";
7
7
  export { compilePlugin } from "./compile.js";
8
8
  export { cssStripPlugin } from "./ssr-css-strip.js";
9
+ export { browserServerExportsStripPlugin } from "./browser-server-exports-strip.js";
10
+ export { browserNodeBuiltinImportsPlugin } from "./browser-node-builtin-imports.js";
9
11
  export { resolveImportsPlugin } from "./resolve-imports.js";
10
12
  export { ssrVfModulesPlugin } from "./ssr-vf-modules.js";
11
13
  export { ssrHttpStubPlugin } from "./ssr-http-stub.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/pipeline/stages/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/pipeline/stages/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AACpF,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
@@ -6,6 +6,8 @@
6
6
  export { parsePlugin } from "./parse.js";
7
7
  export { compilePlugin } from "./compile.js";
8
8
  export { cssStripPlugin } from "./ssr-css-strip.js";
9
+ export { browserServerExportsStripPlugin } from "./browser-server-exports-strip.js";
10
+ export { browserNodeBuiltinImportsPlugin } from "./browser-node-builtin-imports.js";
9
11
  export { resolveImportsPlugin } from "./resolve-imports.js";
10
12
  export { ssrVfModulesPlugin } from "./ssr-vf-modules.js";
11
13
  export { ssrHttpStubPlugin } from "./ssr-http-stub.js";
@@ -42,5 +42,16 @@ export declare function resolveAndTransformVeryfrontImport(specifier: string, ct
42
42
  * Transform framework source code with React import rewriting.
43
43
  * Entry point for top-level framework modules (e.g., Head.tsx, Router.tsx).
44
44
  */
45
+ /**
46
+ * Drop `with { type: "json" }` from imports that now point at a JavaScript
47
+ * module.
48
+ *
49
+ * A framework import of a `.json` file (`#veryfront/server/dev-ui/manifest.json`)
50
+ * is resolved by transforming the JSON into a cached `.mjs` that default-exports
51
+ * the data. The attribute on the importer describes the *original* target, so
52
+ * leaving it in place makes the runtime reject the rewritten import with
53
+ * "Expected a Json module, but identified a Mjs module".
54
+ */
55
+ export declare function stripJsonAttributesFromModuleImports(code: string): string;
45
56
  export declare function transformFrameworkSource(content: string, sourcePath: string, reactVersion: string, projectDir: string, fs: ReturnType<typeof createFileSystem>): Promise<string>;
46
57
  //# sourceMappingURL=transform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAmBrE,OAAO,EASL,KAAK,gBAAgB,EAGtB,MAAM,gBAAgB,CAAC;AAoBxB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAgBD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AA6MhE;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,gBAAgB,EACrB,oBAAoB,UAAQ,EAC5B,KAAK,SAAI,GACR,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAsPD;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgDxB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAEjB"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAmBrE,OAAO,EASL,KAAK,gBAAgB,EAGtB,MAAM,gBAAgB,CAAC;AAoBxB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAgBD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AA8MhE;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,gBAAgB,EACrB,oBAAoB,UAAQ,EAC5B,KAAK,SAAI,GACR,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAyPD;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgDxB;AAED;;;GAGG;AACH;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzE;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAEjB"}
@@ -4,6 +4,7 @@
4
4
  * Compiles framework TypeScript/TSX files to JavaScript and recursively
5
5
  * resolves all imports (#veryfront/, relative, React).
6
6
  */
7
+ import { ESBUILD_SUPPORTED_FEATURES } from "../../../esm/transform-utils.js";
7
8
  import { join } from "../../../../platform/compat/path/index.js";
8
9
  import denoConfig from "../../../../../deno.js";
9
10
  import { rendererLogger as logger } from "../../../../utils/index.js";
@@ -122,6 +123,7 @@ async function compileFallbackSource(content, sourcePath) {
122
123
  jsxImportSource: "react",
123
124
  format: "esm",
124
125
  target: "es2022",
126
+ supported: ESBUILD_SUPPORTED_FEATURES,
125
127
  });
126
128
  return result.code;
127
129
  }
@@ -333,6 +335,7 @@ async function transformFrameworkCodeUncoalesced(content, sourcePath, ctx, throw
333
335
  jsxImportSource: "react",
334
336
  format: "esm",
335
337
  target: "es2022",
338
+ supported: ESBUILD_SUPPORTED_FEATURES,
336
339
  });
337
340
  let transformed = result.code;
338
341
  // Collect and recursively resolve all #veryfront/ imports
@@ -462,6 +465,7 @@ async function transformFrameworkCodeUncoalesced(content, sourcePath, ctx, throw
462
465
  reactVersion: ctx.reactVersion,
463
466
  reactImportMap,
464
467
  }));
468
+ transformed = stripJsonAttributesFromModuleImports(transformed);
465
469
  // Cache HTTP imports to local filesystem
466
470
  const importMap = await loadImportMap(ctx.projectDir);
467
471
  const cacheResult = await cacheHttpImportsToLocal(transformed, {
@@ -526,6 +530,19 @@ export async function resolveAndTransformVeryfrontImport(specifier, ctx) {
526
530
  * Transform framework source code with React import rewriting.
527
531
  * Entry point for top-level framework modules (e.g., Head.tsx, Router.tsx).
528
532
  */
533
+ /**
534
+ * Drop `with { type: "json" }` from imports that now point at a JavaScript
535
+ * module.
536
+ *
537
+ * A framework import of a `.json` file (`#veryfront/server/dev-ui/manifest.json`)
538
+ * is resolved by transforming the JSON into a cached `.mjs` that default-exports
539
+ * the data. The attribute on the importer describes the *original* target, so
540
+ * leaving it in place makes the runtime reject the rewritten import with
541
+ * "Expected a Json module, but identified a Mjs module".
542
+ */
543
+ export function stripJsonAttributesFromModuleImports(code) {
544
+ return code.replace(/(from\s*["'](?:file:\/\/)?[^"']+\.mjs["'])\s*with\s*\{[^}]*\}/g, "$1");
545
+ }
529
546
  export async function transformFrameworkSource(content, sourcePath, reactVersion, projectDir, fs) {
530
547
  return transformFrameworkCode(content, sourcePath, { reactVersion, projectDir, fs }, true);
531
548
  }
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.1099";
2
+ export declare const VERSION = "0.1.1100";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.1099";
4
+ export const VERSION = "0.1.1100";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.1099",
3
+ "version": "0.1.1100",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -328,10 +328,10 @@
328
328
  "@types/react": "19.2.14",
329
329
  "@types/react-dom": "19.2.3",
330
330
  "ws": "8.21.0",
331
- "@veryfront/ext-bundler-esbuild": "0.1.1099",
332
- "@veryfront/ext-content-mdx": "0.1.1099",
333
- "@veryfront/ext-css-tailwind": "0.1.1099",
334
- "@veryfront/ext-parser-babel": "0.1.1099"
331
+ "@veryfront/ext-bundler-esbuild": "0.1.1100",
332
+ "@veryfront/ext-content-mdx": "0.1.1100",
333
+ "@veryfront/ext-css-tailwind": "0.1.1100",
334
+ "@veryfront/ext-parser-babel": "0.1.1100"
335
335
  },
336
336
  "devDependencies": {
337
337
  "@types/node": "20.9.0"