veryfront 0.1.754 → 0.1.756

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 (108) hide show
  1. package/esm/cli/auth/callback-server.d.ts +4 -1
  2. package/esm/cli/auth/callback-server.d.ts.map +1 -1
  3. package/esm/cli/auth/callback-server.js +52 -13
  4. package/esm/cli/auth/index.d.ts +1 -1
  5. package/esm/cli/auth/index.d.ts.map +1 -1
  6. package/esm/cli/auth/index.js +1 -1
  7. package/esm/cli/auth/login.d.ts +2 -0
  8. package/esm/cli/auth/login.d.ts.map +1 -1
  9. package/esm/cli/auth/login.js +18 -6
  10. package/esm/cli/commands/demo/demo.d.ts.map +1 -1
  11. package/esm/cli/commands/demo/demo.js +6 -7
  12. package/esm/deno.js +1 -1
  13. package/esm/src/agent/runtime/index.d.ts +3 -96
  14. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  15. package/esm/src/agent/runtime/index.js +21 -341
  16. package/esm/src/agent/runtime/model-capabilities.d.ts +3 -0
  17. package/esm/src/agent/runtime/model-capabilities.d.ts.map +1 -0
  18. package/esm/src/agent/runtime/model-capabilities.js +18 -0
  19. package/esm/src/agent/runtime/runtime-tool-config.d.ts +14 -0
  20. package/esm/src/agent/runtime/runtime-tool-config.d.ts.map +1 -0
  21. package/esm/src/agent/runtime/runtime-tool-config.js +37 -0
  22. package/esm/src/agent/runtime/skill-policy-enforcement.d.ts +16 -0
  23. package/esm/src/agent/runtime/skill-policy-enforcement.d.ts.map +1 -0
  24. package/esm/src/agent/runtime/skill-policy-enforcement.js +55 -0
  25. package/esm/src/agent/runtime/tool-result-continuation.d.ts +34 -0
  26. package/esm/src/agent/runtime/tool-result-continuation.d.ts.map +1 -0
  27. package/esm/src/agent/runtime/tool-result-continuation.js +194 -0
  28. package/esm/src/agent/schemas/agent.schema.d.ts +7 -0
  29. package/esm/src/agent/schemas/agent.schema.d.ts.map +1 -1
  30. package/esm/src/agent/schemas/agent.schema.js +9 -3
  31. package/esm/src/agent/schemas/index.d.ts +1 -1
  32. package/esm/src/agent/schemas/index.d.ts.map +1 -1
  33. package/esm/src/agent/schemas/index.js +1 -1
  34. package/esm/src/cache/dependency-graph.d.ts +1 -0
  35. package/esm/src/cache/dependency-graph.d.ts.map +1 -1
  36. package/esm/src/cache/dependency-graph.js +7 -1
  37. package/esm/src/modules/server/module-batch-handler.d.ts.map +1 -1
  38. package/esm/src/modules/server/module-batch-handler.js +47 -35
  39. package/esm/src/modules/server/module-server.d.ts.map +1 -1
  40. package/esm/src/modules/server/module-server.js +31 -9
  41. package/esm/src/modules/server/rate-limiter.d.ts +3 -2
  42. package/esm/src/modules/server/rate-limiter.d.ts.map +1 -1
  43. package/esm/src/platform/adapters/base.d.ts +24 -3
  44. package/esm/src/platform/adapters/base.d.ts.map +1 -1
  45. package/esm/src/platform/adapters/base.js +15 -1
  46. package/esm/src/platform/adapters/runtime/bun/websocket-adapter.d.ts +2 -0
  47. package/esm/src/platform/adapters/runtime/bun/websocket-adapter.d.ts.map +1 -1
  48. package/esm/src/platform/adapters/runtime/bun/websocket-adapter.js +33 -1
  49. package/esm/src/platform/adapters/runtime/node/websocket-adapter.d.ts +1 -1
  50. package/esm/src/platform/adapters/runtime/node/websocket-adapter.d.ts.map +1 -1
  51. package/esm/src/platform/adapters/runtime/node/websocket-adapter.js +3 -10
  52. package/esm/src/proxy/handler.d.ts.map +1 -1
  53. package/esm/src/proxy/handler.js +25 -116
  54. package/esm/src/proxy/local-project-resolver.d.ts +18 -0
  55. package/esm/src/proxy/local-project-resolver.d.ts.map +1 -0
  56. package/esm/src/proxy/local-project-resolver.js +63 -0
  57. package/esm/src/proxy/proxy-token-resolution.d.ts +37 -0
  58. package/esm/src/proxy/proxy-token-resolution.d.ts.map +1 -0
  59. package/esm/src/proxy/proxy-token-resolution.js +51 -0
  60. package/esm/src/rendering/orchestrator/module-loader/index.d.ts +10 -0
  61. package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
  62. package/esm/src/rendering/orchestrator/module-loader/index.js +23 -158
  63. package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts +20 -0
  64. package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts.map +1 -0
  65. package/esm/src/rendering/orchestrator/module-loader/module-persistence.js +80 -0
  66. package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.d.ts +59 -0
  67. package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.d.ts.map +1 -0
  68. package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.js +97 -0
  69. package/esm/src/routing/api/handler.d.ts +2 -1
  70. package/esm/src/routing/api/handler.d.ts.map +1 -1
  71. package/esm/src/routing/api/handler.js +2 -1
  72. package/esm/src/routing/api/route-executor.d.ts +3 -0
  73. package/esm/src/routing/api/route-executor.d.ts.map +1 -1
  74. package/esm/src/routing/api/route-executor.js +28 -0
  75. package/esm/src/runtime/runtime-bridge.js +2 -2
  76. package/esm/src/security/http/base-handler.d.ts +3 -2
  77. package/esm/src/security/http/base-handler.d.ts.map +1 -1
  78. package/esm/src/security/http/base-handler.js +1 -1
  79. package/esm/src/security/sandbox/project-worker.d.ts +1 -0
  80. package/esm/src/security/sandbox/project-worker.d.ts.map +1 -1
  81. package/esm/src/security/sandbox/project-worker.js +17 -1
  82. package/esm/src/security/sandbox/worker-egress-guard.d.ts +15 -0
  83. package/esm/src/security/sandbox/worker-egress-guard.d.ts.map +1 -0
  84. package/esm/src/security/sandbox/worker-egress-guard.js +201 -0
  85. package/esm/src/security/sandbox/worker-permissions.d.ts +6 -2
  86. package/esm/src/security/sandbox/worker-permissions.d.ts.map +1 -1
  87. package/esm/src/security/sandbox/worker-permissions.js +34 -3
  88. package/esm/src/security/sandbox/worker-pool.d.ts +1 -1
  89. package/esm/src/security/sandbox/worker-pool.d.ts.map +1 -1
  90. package/esm/src/security/sandbox/worker-pool.js +35 -9
  91. package/esm/src/server/handlers/preview/hmr-client-manager.d.ts +3 -2
  92. package/esm/src/server/handlers/preview/hmr-client-manager.d.ts.map +1 -1
  93. package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
  94. package/esm/src/server/handlers/preview/hmr.handler.js +4 -1
  95. package/esm/src/server/handlers/request/api/api-handler-wrapper.js +1 -1
  96. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.d.ts +32 -0
  97. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.d.ts.map +1 -0
  98. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.js +27 -0
  99. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.d.ts.map +1 -1
  100. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.js +23 -3
  101. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
  102. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +32 -30
  103. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/persistence.d.ts +34 -0
  104. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/persistence.d.ts.map +1 -0
  105. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/persistence.js +30 -0
  106. package/esm/src/utils/version-constant.d.ts +1 -1
  107. package/esm/src/utils/version-constant.js +1 -1
  108. package/package.json +1 -1
@@ -8,41 +8,18 @@
8
8
  */
9
9
  import { rendererLogger } from "../../../utils/index.js";
10
10
  import { getLocalAdapter } from "../../../platform/adapters/registry.js";
11
- import { transformToESM } from "../../../transforms/esm-transform.js";
12
11
  import { createFileSystem } from "../../../platform/compat/fs.js";
13
12
  import { getProjectTmpDir } from "../../../modules/react-loader/index.js";
14
- import { generateCacheKey as generateTransformCacheKey, getOrComputeTransform, initializeTransformCache, setCachedTransformAsync, } from "../../../transforms/esm/transform-cache.js";
15
- import { TRANSFORM_DISTRIBUTED_TTL_SEC } from "../../../utils/constants/cache.js";
16
- import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/cached-bundle-validation.js";
17
13
  import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
18
14
  import { join } from "../../../platform/compat/path/index.js";
19
- import { hashCodeHex } from "../../../utils/hash-utils.js";
20
- import { getModulePathCache, invalidateMdxEsmModule, lookupMdxEsmCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
21
- import { buildMdxEsmPathCacheKey } from "../../../transforms/mdx/esm-module-loader/cache-format.js";
15
+ import { invalidateMdxEsmModule, lookupMdxEsmCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
22
16
  import { resolveModuleDependencies, rewriteResolvedDependencyImports, } from "./dependency-resolver.js";
17
+ import { persistTransformedModule } from "./module-persistence.js";
18
+ import { transformModuleCodeWithCache, UNRESOLVED_VF_MODULES_RE, } from "./module-transform-cache.js";
23
19
  const logger = rendererLogger.component("module-loader");
24
20
  // Re-export utilities
25
21
  export { createEsmCache, createModuleCache, generateHash } from "./cache.js";
26
22
  export { fetchEsmModule, rewriteEsmPaths } from "./esm-rewriter.js";
27
- /** Maximum number of directories to track to prevent memory leaks */
28
- const MAX_CREATED_DIRS = 5_000;
29
- /** Cache for created directories to avoid repeated mkdir calls (LRU-style) */
30
- const createdDirs = new Set();
31
- /** TTL for cached transforms (uses centralized config) */
32
- const TRANSFORM_CACHE_TTL_SECONDS = TRANSFORM_DISTRIBUTED_TTL_SEC;
33
- /** Prune oldest entries when cache exceeds limit */
34
- function pruneCreatedDirs() {
35
- if (createdDirs.size <= MAX_CREATED_DIRS)
36
- return;
37
- const toDelete = createdDirs.size - MAX_CREATED_DIRS;
38
- let deleted = 0;
39
- for (const dir of createdDirs) {
40
- if (deleted >= toDelete)
41
- break;
42
- createdDirs.delete(dir);
43
- deleted++;
44
- }
45
- }
46
23
  function getModuleCacheKey(filePath, projectId, projectDir, contentSourceId) {
47
24
  const base = projectId ?? projectDir ?? "default";
48
25
  const source = contentSourceId ?? "default";
@@ -53,20 +30,6 @@ function decodeFileContent(fileContent) {
53
30
  return fileContent;
54
31
  return new TextDecoder().decode(fileContent);
55
32
  }
56
- async function ensureDir(adapter, dir) {
57
- if (createdDirs.has(dir))
58
- return;
59
- try {
60
- await adapter.fs.mkdir(dir, { recursive: true });
61
- }
62
- catch (_) {
63
- /* expected: directory might already exist */
64
- }
65
- finally {
66
- createdDirs.add(dir);
67
- pruneCreatedDirs();
68
- }
69
- }
70
33
  /**
71
34
  * Transform a module and all its local dependencies (@/ alias and relative imports).
72
35
  *
@@ -77,8 +40,6 @@ async function ensureDir(adapter, dir) {
77
40
  * @param useLocalAdapter - Whether to use local adapter for reading
78
41
  * @returns Path to the transformed module file
79
42
  */
80
- /** Pattern to detect unresolved /_vf_modules/ imports that will fail at runtime */
81
- const UNRESOLVED_VF_MODULES_RE = /from\s*["']((?:file:\/\/)?\/?\/?_vf_modules\/[^"']+)["']/;
82
43
  export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, config, useLocalAdapter = false) {
83
44
  const { moduleCache, projectDir, projectId, contentSourceId, adapter, mode } = config;
84
45
  const cacheKey = getModuleCacheKey(filePath, projectId, projectDir, contentSourceId);
@@ -158,123 +119,27 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
158
119
  projectDir,
159
120
  });
160
121
  }
161
- const contentHash = hashCodeHex(fileContent);
162
122
  const effectiveProjectId = projectId ?? projectDir;
163
- const scopedPath = `${effectiveProjectId}:${filePath}`;
164
- const transformCacheKey = generateTransformCacheKey(scopedPath, contentHash, true);
165
- await initializeTransformCache();
166
- const transformResult = await getOrComputeTransform(transformCacheKey, () => {
167
- logger.debug("Transform cache miss, transforming", { filePath });
168
- return transformToESM(fileContent, filePath, projectDir, adapter, {
169
- projectId: effectiveProjectId,
170
- dev: mode === "development",
171
- ssr: true,
172
- reactVersion: config.reactVersion,
173
- });
174
- }, TRANSFORM_CACHE_TTL_SECONDS);
175
- let transformedCode = transformResult.code;
176
- const cacheDir = getHttpBundleCacheDir();
177
- let bundlesValid = true;
178
- if (transformResult.cacheHit) {
179
- const validation = await validateCachedBundlesByManifestOrCode(transformedCode, transformResult.bundleManifestId, cacheDir);
180
- if (!validation.valid) {
181
- logger.warn("Cached HTTP bundle validation failed, re-transforming", {
182
- filePath,
183
- manifestId: transformResult.bundleManifestId?.slice(0, 12),
184
- failedHashes: validation.failedHashes,
185
- reason: validation.reason,
186
- source: validation.source,
187
- });
188
- bundlesValid = false;
189
- }
190
- }
191
- if (!bundlesValid) {
192
- transformedCode = await transformToESM(fileContent, filePath, projectDir, adapter, {
193
- projectId: effectiveProjectId,
194
- dev: mode === "development",
195
- ssr: true,
196
- reactVersion: config.reactVersion,
197
- });
198
- setCachedTransformAsync(transformCacheKey, transformedCode, contentHash, TRANSFORM_CACHE_TTL_SECONDS).catch((error) => {
199
- logger.debug("Failed to update transform cache after re-transform", {
200
- filePath,
201
- error,
202
- });
203
- });
204
- }
205
- // CRITICAL: Validate that no unresolved /_vf_modules/ imports remain after transform.
206
- // These imports should have been resolved to file:// paths by ssrVfModulesPlugin.
207
- // If they're still present, retry the transform bypassing all caches.
208
- if (UNRESOLVED_VF_MODULES_RE.test(transformedCode)) {
209
- const match = transformedCode.match(UNRESOLVED_VF_MODULES_RE);
210
- const unresolvedImport = match?.[1] || "unknown";
211
- logger.warn("[ModuleLoader] Transform has unresolved _vf_modules import, retrying without cache", {
212
- filePath: filePath.slice(-60),
213
- unresolvedImport: unresolvedImport.slice(0, 80),
214
- cacheHit: transformResult.cacheHit,
215
- });
216
- // Force a fresh transform bypassing all caches
217
- // Import runPipeline directly to bypass getOrComputeTransform cache
218
- const { runPipeline } = await import("../../../transforms/pipeline/index.js");
219
- const pipelineResult = await runPipeline(fileContent, filePath, projectDir, {
220
- projectId: effectiveProjectId,
221
- dev: mode === "development",
222
- ssr: true,
223
- reactVersion: config.reactVersion,
224
- });
225
- transformedCode = pipelineResult.code;
226
- // Check again after retry
227
- if (UNRESOLVED_VF_MODULES_RE.test(transformedCode)) {
228
- const retryMatch = transformedCode.match(UNRESOLVED_VF_MODULES_RE);
229
- logger.error("Transform still has unresolved _vf_modules after retry", {
230
- filePath: filePath.slice(-60),
231
- unresolvedImport: retryMatch?.[1]?.slice(0, 80) || "unknown",
232
- hint: "Check that framework sources exist in dist/framework-src/ and ssrVfModulesPlugin is running",
233
- });
234
- // Continue anyway - let it fail at import time for better error context
235
- }
236
- else {
237
- // Retry succeeded - update the cache
238
- setCachedTransformAsync(transformCacheKey, transformedCode, hashCodeHex(transformedCode).slice(0, 16), TRANSFORM_CACHE_TTL_SECONDS).catch((error) => {
239
- logger.debug("Failed to update cache after retry", { filePath, error });
240
- });
241
- }
242
- }
243
- const transformedHash = hashCodeHex(transformedCode).slice(0, 8);
244
- const relativePath = filePath.startsWith(projectDir)
245
- ? filePath.slice(projectDir.length).replace(/^\/+/, "")
246
- : filePath.replace(/^\/+/, "");
247
- const jsPath = relativePath.replace(/\.(tsx?|jsx|mdx)$/, `.${transformedHash}.js`);
248
- const tempFilePath = join(tmpDir, jsPath);
249
- const tempDir = tempFilePath.substring(0, tempFilePath.lastIndexOf("/"));
250
- await ensureDir(localAdapter, tempDir);
251
- try {
252
- await localAdapter.fs.writeFile(tempFilePath, transformedCode);
253
- }
254
- catch (error) {
255
- logger.error("Failed to write module:", {
256
- filePath,
257
- tempFilePath,
258
- error: error instanceof Error ? error.message : String(error),
259
- });
260
- throw error;
261
- }
262
- if (contentSourceId) {
263
- const normalizedPath = `_vf_modules/${relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js")}`;
264
- const mdxCacheKey = buildMdxEsmPathCacheKey(normalizedPath, config.reactVersion);
265
- const cache = await getModulePathCache(tmpDir);
266
- cache.set(mdxCacheKey, tempFilePath);
267
- saveModulePathCache(tmpDir).catch((err) => {
268
- logger.debug("Failed to save module cache", { error: String(err) });
269
- });
270
- logger.debug("Registered module in MDX-ESM cache", {
271
- file: filePath.slice(-40),
272
- mdxCacheKey,
273
- tempFilePath: tempFilePath.slice(-60),
274
- });
275
- }
276
- moduleCache.set(cacheKey, tempFilePath);
277
- return tempFilePath;
123
+ const { code: transformedCode } = await transformModuleCodeWithCache({
124
+ fileContent,
125
+ filePath,
126
+ projectDir,
127
+ effectiveProjectId,
128
+ mode,
129
+ adapter,
130
+ reactVersion: config.reactVersion,
131
+ });
132
+ return await persistTransformedModule({
133
+ filePath,
134
+ projectDir,
135
+ tmpDir,
136
+ transformedCode,
137
+ localAdapter,
138
+ moduleCache,
139
+ cacheKey,
140
+ contentSourceId,
141
+ reactVersion: config.reactVersion,
142
+ });
278
143
  }
279
144
  /**
280
145
  * Get the cache directory for module transforms.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Final module-loader persistence phase.
3
+ *
4
+ * @module rendering/orchestrator/module-loader/module-persistence
5
+ */
6
+ import type { RuntimeAdapter } from "../../../platform/adapters/base.js";
7
+ export interface PersistTransformedModuleInput {
8
+ filePath: string;
9
+ projectDir: string;
10
+ tmpDir: string;
11
+ transformedCode: string;
12
+ localAdapter: RuntimeAdapter;
13
+ moduleCache: Map<string, string>;
14
+ cacheKey: string;
15
+ contentSourceId?: string;
16
+ reactVersion?: string;
17
+ }
18
+ /** Write a transformed module artifact and register cache pointers. */
19
+ export declare function persistTransformedModule(input: PersistTransformedModuleInput): Promise<string>;
20
+ //# sourceMappingURL=module-persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-persistence.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/module-persistence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA6CzE,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,cAAc,CAAC;IAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,uEAAuE;AACvE,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,MAAM,CAAC,CA2CjB"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Final module-loader persistence phase.
3
+ *
4
+ * @module rendering/orchestrator/module-loader/module-persistence
5
+ */
6
+ import { join } from "../../../platform/compat/path/index.js";
7
+ import { rendererLogger } from "../../../utils/index.js";
8
+ import { hashCodeHex } from "../../../utils/hash-utils.js";
9
+ import { getModulePathCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
10
+ import { buildMdxEsmPathCacheKey } from "../../../transforms/mdx/esm-module-loader/cache-format.js";
11
+ const logger = rendererLogger.component("module-loader");
12
+ /** Maximum number of directories to track to prevent memory leaks. */
13
+ const MAX_CREATED_DIRS = 5_000;
14
+ /** Cache for created directories to avoid repeated mkdir calls (LRU-style). */
15
+ const createdDirs = new Set();
16
+ /** Prune oldest entries when cache exceeds limit. */
17
+ function pruneCreatedDirs() {
18
+ if (createdDirs.size <= MAX_CREATED_DIRS)
19
+ return;
20
+ const toDelete = createdDirs.size - MAX_CREATED_DIRS;
21
+ let deleted = 0;
22
+ for (const dir of createdDirs) {
23
+ if (deleted >= toDelete)
24
+ break;
25
+ createdDirs.delete(dir);
26
+ deleted++;
27
+ }
28
+ }
29
+ async function ensureDir(adapter, dir) {
30
+ if (createdDirs.has(dir))
31
+ return;
32
+ try {
33
+ await adapter.fs.mkdir(dir, { recursive: true });
34
+ }
35
+ catch (_) {
36
+ /* expected: directory might already exist */
37
+ }
38
+ finally {
39
+ createdDirs.add(dir);
40
+ pruneCreatedDirs();
41
+ }
42
+ }
43
+ /** Write a transformed module artifact and register cache pointers. */
44
+ export async function persistTransformedModule(input) {
45
+ const transformedHash = hashCodeHex(input.transformedCode).slice(0, 8);
46
+ const relativePath = input.filePath.startsWith(input.projectDir)
47
+ ? input.filePath.slice(input.projectDir.length).replace(/^\/+/, "")
48
+ : input.filePath.replace(/^\/+/, "");
49
+ const jsPath = relativePath.replace(/\.(tsx?|jsx|mdx)$/, `.${transformedHash}.js`);
50
+ const tempFilePath = join(input.tmpDir, jsPath);
51
+ const tempDir = tempFilePath.substring(0, tempFilePath.lastIndexOf("/"));
52
+ await ensureDir(input.localAdapter, tempDir);
53
+ try {
54
+ await input.localAdapter.fs.writeFile(tempFilePath, input.transformedCode);
55
+ }
56
+ catch (error) {
57
+ logger.error("Failed to write module:", {
58
+ filePath: input.filePath,
59
+ tempFilePath,
60
+ error: error instanceof Error ? error.message : String(error),
61
+ });
62
+ throw error;
63
+ }
64
+ if (input.contentSourceId) {
65
+ const normalizedPath = `_vf_modules/${relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js")}`;
66
+ const mdxCacheKey = buildMdxEsmPathCacheKey(normalizedPath, input.reactVersion);
67
+ const cache = await getModulePathCache(input.tmpDir);
68
+ cache.set(mdxCacheKey, tempFilePath);
69
+ saveModulePathCache(input.tmpDir).catch((err) => {
70
+ logger.debug("Failed to save module cache", { error: String(err) });
71
+ });
72
+ logger.debug("Registered module in MDX-ESM cache", {
73
+ file: input.filePath.slice(-40),
74
+ mdxCacheKey,
75
+ tempFilePath: tempFilePath.slice(-60),
76
+ });
77
+ }
78
+ input.moduleCache.set(input.cacheKey, tempFilePath);
79
+ return tempFilePath;
80
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Transform-cache and retry phase for the SSR module loader.
3
+ *
4
+ * @module rendering/orchestrator/module-loader/module-transform-cache
5
+ */
6
+ import type { RuntimeAdapter } from "../../../platform/adapters/base.js";
7
+ import { initializeTransformCache, setCachedTransformAsync } from "../../../transforms/esm/transform-cache.js";
8
+ import { getHttpBundleCacheDir } from "../../../utils/cache-dir.js";
9
+ /** Pattern to detect unresolved /_vf_modules/ imports that will fail at runtime. */
10
+ export declare const UNRESOLVED_VF_MODULES_RE: RegExp;
11
+ export interface ModuleTransformCacheResult {
12
+ code: string;
13
+ cacheKey: string;
14
+ contentHash: string;
15
+ }
16
+ interface TransformCacheResult {
17
+ code: string;
18
+ cacheHit: boolean;
19
+ bundleManifestId?: string;
20
+ }
21
+ interface BundleValidationResult {
22
+ valid: boolean;
23
+ failedHashes: string[];
24
+ reason?: string;
25
+ source: string;
26
+ }
27
+ interface TransformOptions {
28
+ projectId: string;
29
+ dev: boolean;
30
+ ssr: boolean;
31
+ reactVersion?: string;
32
+ }
33
+ interface PipelineResult {
34
+ code: string;
35
+ }
36
+ export interface ModuleTransformCacheDeps {
37
+ initializeTransformCache: typeof initializeTransformCache;
38
+ getOrComputeTransform: (key: string, compute: () => Promise<string>, ttlSeconds: number) => Promise<TransformCacheResult>;
39
+ transformToESM: (code: string, filePath: string, projectDir: string, adapter: RuntimeAdapter, options: TransformOptions) => Promise<string>;
40
+ validateCachedBundlesByManifestOrCode: (code: string, bundleManifestId: string | undefined, cacheDir: string) => Promise<BundleValidationResult>;
41
+ getHttpBundleCacheDir: typeof getHttpBundleCacheDir;
42
+ setCachedTransformAsync: typeof setCachedTransformAsync;
43
+ runPipeline: (code: string, filePath: string, projectDir: string, options: TransformOptions) => Promise<PipelineResult>;
44
+ }
45
+ export interface TransformModuleCodeWithCacheInput {
46
+ fileContent: string;
47
+ filePath: string;
48
+ projectDir: string;
49
+ effectiveProjectId: string;
50
+ mode: "development" | "production";
51
+ adapter: RuntimeAdapter;
52
+ reactVersion?: string;
53
+ ttlSeconds?: number;
54
+ deps?: ModuleTransformCacheDeps;
55
+ }
56
+ /** Transform module source through the shared cache and stale-cache retry checks. */
57
+ export declare function transformModuleCodeWithCache(input: TransformModuleCodeWithCacheInput): Promise<ModuleTransformCacheResult>;
58
+ export {};
59
+ //# sourceMappingURL=module-transform-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-transform-cache.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/module-transform-cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAIzE,OAAO,EAGL,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAKpE,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,QAA6D,CAAC;AAEnG,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,UAAU,sBAAsB;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,qBAAqB,EAAE,CACrB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAC9B,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,cAAc,EAAE,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,gBAAgB,KACtB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,qCAAqC,EAAE,CACrC,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACrC,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,WAAW,EAAE,CACX,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,gBAAgB,KACtB,OAAO,CAAC,cAAc,CAAC,CAAC;CAC9B;AAeD,MAAM,WAAW,iCAAiC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,wBAAwB,CAAC;CACjC;AAED,qFAAqF;AACrF,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,iCAAiC,GACvC,OAAO,CAAC,0BAA0B,CAAC,CAoHrC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Transform-cache and retry phase for the SSR module loader.
3
+ *
4
+ * @module rendering/orchestrator/module-loader/module-transform-cache
5
+ */
6
+ import { rendererLogger } from "../../../utils/index.js";
7
+ import { hashCodeHex } from "../../../utils/hash-utils.js";
8
+ import { transformToESM } from "../../../transforms/esm-transform.js";
9
+ import { generateCacheKey as generateTransformCacheKey, getOrComputeTransform, initializeTransformCache, setCachedTransformAsync, } from "../../../transforms/esm/transform-cache.js";
10
+ import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/cached-bundle-validation.js";
11
+ import { getHttpBundleCacheDir } from "../../../utils/cache-dir.js";
12
+ import { TRANSFORM_DISTRIBUTED_TTL_SEC } from "../../../utils/constants/cache.js";
13
+ const logger = rendererLogger.component("module-loader");
14
+ /** Pattern to detect unresolved /_vf_modules/ imports that will fail at runtime. */
15
+ export const UNRESOLVED_VF_MODULES_RE = /from\s*["']((?:file:\/\/)?\/?\/?_vf_modules\/[^"']+)["']/;
16
+ const defaultDeps = {
17
+ initializeTransformCache,
18
+ getOrComputeTransform,
19
+ transformToESM,
20
+ validateCachedBundlesByManifestOrCode,
21
+ getHttpBundleCacheDir,
22
+ setCachedTransformAsync,
23
+ runPipeline: async (code, filePath, projectDir, options) => {
24
+ const { runPipeline } = await import("../../../transforms/pipeline/index.js");
25
+ return await runPipeline(code, filePath, projectDir, options);
26
+ },
27
+ };
28
+ /** Transform module source through the shared cache and stale-cache retry checks. */
29
+ export async function transformModuleCodeWithCache(input) {
30
+ const deps = input.deps ?? defaultDeps;
31
+ const ttlSeconds = input.ttlSeconds ?? TRANSFORM_DISTRIBUTED_TTL_SEC;
32
+ const contentHash = hashCodeHex(input.fileContent);
33
+ const scopedPath = `${input.effectiveProjectId}:${input.filePath}`;
34
+ const cacheKey = generateTransformCacheKey(scopedPath, contentHash, true);
35
+ const transformOptions = {
36
+ projectId: input.effectiveProjectId,
37
+ dev: input.mode === "development",
38
+ ssr: true,
39
+ reactVersion: input.reactVersion,
40
+ };
41
+ await deps.initializeTransformCache();
42
+ const transformResult = await deps.getOrComputeTransform(cacheKey, () => {
43
+ logger.debug("Transform cache miss, transforming", { filePath: input.filePath });
44
+ return deps.transformToESM(input.fileContent, input.filePath, input.projectDir, input.adapter, transformOptions);
45
+ }, ttlSeconds);
46
+ let transformedCode = transformResult.code;
47
+ if (transformResult.cacheHit) {
48
+ const validation = await deps.validateCachedBundlesByManifestOrCode(transformedCode, transformResult.bundleManifestId, deps.getHttpBundleCacheDir());
49
+ if (!validation.valid) {
50
+ logger.warn("Cached HTTP bundle validation failed, re-transforming", {
51
+ filePath: input.filePath,
52
+ manifestId: transformResult.bundleManifestId?.slice(0, 12),
53
+ failedHashes: validation.failedHashes,
54
+ reason: validation.reason,
55
+ source: validation.source,
56
+ });
57
+ transformedCode = await deps.transformToESM(input.fileContent, input.filePath, input.projectDir, input.adapter, transformOptions);
58
+ deps.setCachedTransformAsync(cacheKey, transformedCode, contentHash, ttlSeconds).catch((error) => {
59
+ logger.debug("Failed to update transform cache after re-transform", {
60
+ filePath: input.filePath,
61
+ error,
62
+ });
63
+ });
64
+ }
65
+ }
66
+ // CRITICAL: Validate that no unresolved /_vf_modules/ imports remain after transform.
67
+ // These imports should have been resolved to file:// paths by ssrVfModulesPlugin.
68
+ // If they're still present, retry the transform bypassing all caches.
69
+ if (UNRESOLVED_VF_MODULES_RE.test(transformedCode)) {
70
+ const match = transformedCode.match(UNRESOLVED_VF_MODULES_RE);
71
+ const unresolvedImport = match?.[1] || "unknown";
72
+ logger.warn("[ModuleLoader] Transform has unresolved _vf_modules import, retrying without cache", {
73
+ filePath: input.filePath.slice(-60),
74
+ unresolvedImport: unresolvedImport.slice(0, 80),
75
+ cacheHit: transformResult.cacheHit,
76
+ });
77
+ const pipelineResult = await deps.runPipeline(input.fileContent, input.filePath, input.projectDir, transformOptions);
78
+ transformedCode = pipelineResult.code;
79
+ if (UNRESOLVED_VF_MODULES_RE.test(transformedCode)) {
80
+ const retryMatch = transformedCode.match(UNRESOLVED_VF_MODULES_RE);
81
+ logger.error("Transform still has unresolved _vf_modules after retry", {
82
+ filePath: input.filePath.slice(-60),
83
+ unresolvedImport: retryMatch?.[1]?.slice(0, 80) || "unknown",
84
+ hint: "Check that framework sources exist in dist/framework-src/ and ssrVfModulesPlugin is running",
85
+ });
86
+ }
87
+ else {
88
+ deps.setCachedTransformAsync(cacheKey, transformedCode, hashCodeHex(transformedCode).slice(0, 16), ttlSeconds).catch((error) => {
89
+ logger.debug("Failed to update cache after retry", {
90
+ filePath: input.filePath,
91
+ error,
92
+ });
93
+ });
94
+ }
95
+ }
96
+ return { code: transformedCode, cacheKey, contentHash };
97
+ }
@@ -4,6 +4,7 @@ import { type APIContext } from "./context-builder.js";
4
4
  import type { APIRoute } from "./module-loader/types.js";
5
5
  import { loadHandlerModule } from "./module-loader/loader.js";
6
6
  import { discoverAppRoutes, discoverPagesRoutes } from "./route-discovery.js";
7
+ import type { HandlerContext } from "../../types/index.js";
7
8
  export type { APIContext, APIRoute };
8
9
  /**
9
10
  * Injection interface for testing APIRouteHandler dependencies
@@ -40,7 +41,7 @@ export declare class APIRouteHandler {
40
41
  private configPromise;
41
42
  constructor(projectDir: string, adapter?: RuntimeAdapter);
42
43
  initialize(): Promise<void>;
43
- handle(request: Request): Promise<Response | null>;
44
+ handle(request: Request, ctx?: HandlerContext): Promise<Response | null>;
44
45
  private loadHandler;
45
46
  clearCache(): void;
46
47
  destroy(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMlD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAO9E,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAErC;;GAEG;AACH,UAAU,mBAAmB;IAC3B,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;CAC9B;AAID;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAE3E;AAWD,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAE3E,qBAAa,eAAe;IAgBxB,OAAO,CAAC,UAAU;IAfpB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,UAAU,CAA6E;IAC/F,OAAO,CAAC,gBAAgB,CAAuB;IAE/C,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,iBAAiB,CAA8B;IAEvD,OAAO,CAAC,MAAM,CAAsD;IACpE,OAAO,CAAC,aAAa,CAA8B;gBAGzC,UAAU,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE,cAAc;IAM1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgD3B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAyFlD,OAAO,CAAC,WAAW;IAuCnB,UAAU,IAAI,IAAI;IAKlB,OAAO,IAAI,IAAI;YAKD,aAAa;YAsBb,gBAAgB;YAOhB,cAAc;YAcd,YAAY;YAOZ,cAAc;CAW7B;AAED,OAAO,EACL,UAAU,EACV,SAAS,EACT,mBAAmB,IAAI,WAAW,EAClC,YAAY,IAAI,IAAI,EACpB,QAAQ,EACR,gBAAgB,IAAI,QAAQ,EAC5B,YAAY,GACb,MAAM,yCAAyC,CAAC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMlD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAErC;;GAEG;AACH,UAAU,mBAAmB;IAC3B,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;CAC9B;AAID;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAE3E;AAWD,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAE3E,qBAAa,eAAe;IAgBxB,OAAO,CAAC,UAAU;IAfpB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,UAAU,CAA6E;IAC/F,OAAO,CAAC,gBAAgB,CAAuB;IAE/C,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,iBAAiB,CAA8B;IAEvD,OAAO,CAAC,MAAM,CAAsD;IACpE,OAAO,CAAC,aAAa,CAA8B;gBAGzC,UAAU,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE,cAAc;IAM1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgD3B,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IA0FxE,OAAO,CAAC,WAAW;IAuCnB,UAAU,IAAI,IAAI;IAKlB,OAAO,IAAI,IAAI;YAKD,aAAa;YAsBb,gBAAgB;YAOhB,cAAc;YAcd,YAAY;YAOZ,cAAc;CAW7B;AAED,OAAO,EACL,UAAU,EACV,SAAS,EACT,mBAAmB,IAAI,WAAW,EAClC,YAAY,IAAI,IAAI,EACpB,QAAQ,EACR,gBAAgB,IAAI,QAAQ,EAC5B,YAAY,GACb,MAAM,yCAAyC,CAAC"}
@@ -79,7 +79,7 @@ export class APIRouteHandler {
79
79
  logger.debug("Route handler initialized");
80
80
  }, { "api.projectDir": this.projectDir });
81
81
  }
82
- handle(request) {
82
+ handle(request, ctx) {
83
83
  const { pathname } = new URL(request.url);
84
84
  return withSpan("api.handle", async () => {
85
85
  const adapter = await this.ensureAdapter();
@@ -132,6 +132,7 @@ export class APIRouteHandler {
132
132
  const isolationOptions = {
133
133
  modulePath: match.route.page,
134
134
  projectDir: this.projectDir,
135
+ isLocalProject: ctx?.isLocalProject,
135
136
  };
136
137
  const response = isAppRoute
137
138
  ? await executeAppRoute(handler, request, match, pathname, adapter, isolationOptions)
@@ -1,11 +1,14 @@
1
1
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
2
2
  import type { RouteMatch } from "./api-route-matcher.js";
3
3
  import type { APIRoute } from "./module-loader/types.js";
4
+ export declare function __resetInProcessIsolationWarningForTests(): void;
4
5
  export interface ExecuteRouteOptions {
5
6
  /** Absolute path to the handler module on disk (for isolated execution) */
6
7
  modulePath?: string;
7
8
  /** Project directory (for isolated execution scope) */
8
9
  projectDir?: string;
10
+ /** Whether the handler module belongs to a trusted local development project. */
11
+ isLocalProject?: boolean;
9
12
  }
10
13
  export declare function executeAppRoute(handler: APIRoute, request: Request, match: RouteMatch, pathname: string, adapter: RuntimeAdapter, options?: ExecuteRouteOptions): Promise<Response>;
11
14
  export declare function executePagesRoute(handler: APIRoute, request: Request, match: RouteMatch, pathname: string, adapter: RuntimeAdapter, projectDir?: string, options?: ExecuteRouteOptions): Promise<Response>;
@@ -1 +1 @@
1
- {"version":3,"file":"route-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/route-executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,0BAA0B,CAAC;AA0UlC,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,QAAQ,CAAC,CA6CnB;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAuCnB"}
1
+ {"version":3,"file":"route-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/route-executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,0BAA0B,CAAC;AAoJlC,wBAAgB,wCAAwC,IAAI,IAAI,CAE/D;AAqND,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,QAAQ,CAAC,CA8CnB;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAwCnB"}
@@ -106,6 +106,32 @@ function checkContentLengthLimit(request) {
106
106
  });
107
107
  }
108
108
  }
109
+ let warnedUntrustedInProcessExecution = false;
110
+ export function __resetInProcessIsolationWarningForTests() {
111
+ warnedUntrustedInProcessExecution = false;
112
+ }
113
+ function warnIfUntrustedInProcessExecution(routeKind, pathname, options) {
114
+ if (options?.isLocalProject !== false)
115
+ return;
116
+ if (isWorkerIsolationEnabled())
117
+ return;
118
+ if (warnedUntrustedInProcessExecution)
119
+ return;
120
+ warnedUntrustedInProcessExecution = true;
121
+ try {
122
+ logger.warn("Untrusted project code is executing in-process with worker isolation disabled. Enable WORKER_ISOLATION_ENABLED=1 and WORKER_ISOLATION_API=1 to run project routes in a permission-restricted worker.", {
123
+ modulePath: options.modulePath,
124
+ pathname,
125
+ projectDir: options.projectDir,
126
+ requiredEnv: ["WORKER_ISOLATION_ENABLED", "WORKER_ISOLATION_API"],
127
+ routeKind,
128
+ workerIsolationEnabled: false,
129
+ });
130
+ }
131
+ catch {
132
+ // A diagnostic warning must not prevent the API route from running.
133
+ }
134
+ }
109
135
  async function readBodyWithSizeGuard(request) {
110
136
  if (!request.body)
111
137
  return null;
@@ -237,6 +263,7 @@ export function executeAppRoute(handler, request, match, pathname, adapter, opti
237
263
  return executeAppRouteIsolated(options.modulePath, request, match, pathname, adapter, options.projectDir);
238
264
  }
239
265
  // Default path: execute in main process (existing behavior)
266
+ warnIfUntrustedInProcessExecution("app", pathname, options);
240
267
  const method = request.method.toUpperCase();
241
268
  return withSpan("api.executeAppRoute", async () => {
242
269
  const handlerModule = handler;
@@ -266,6 +293,7 @@ export function executePagesRoute(handler, request, match, pathname, adapter, pr
266
293
  return executePagesRouteIsolated(options.modulePath, request, match, pathname, adapter, options.projectDir ?? projectDir);
267
294
  }
268
295
  // Default path: execute in main process (existing behavior)
296
+ warnIfUntrustedInProcessExecution("pages", pathname, options);
269
297
  const method = request.method;
270
298
  return withSpan("api.executePagesRoute", async () => {
271
299
  const methodHandler = handler[method] ?? handler.default;
@@ -271,7 +271,7 @@ export function generateText(options) {
271
271
  return resolveDirectTools(options.tools).then((tools) => options.model.doGenerate({
272
272
  prompt: toRuntimePrompt(normalizeSystemPrompt(options.system), options.messages),
273
273
  maxOutputTokens: options.maxOutputTokens,
274
- temperature: options.temperature,
274
+ ...(options.temperature === undefined ? {} : { temperature: options.temperature }),
275
275
  topP: options.topP,
276
276
  topK: options.topK,
277
277
  stopSequences: options.stopSequences,
@@ -293,7 +293,7 @@ export function streamText(options) {
293
293
  const directResultPromise = resolveDirectTools(options.tools).then((tools) => options.model.doStream({
294
294
  prompt: toRuntimePrompt(normalizeSystemPrompt(options.system), options.messages),
295
295
  maxOutputTokens: options.maxOutputTokens,
296
- temperature: options.temperature,
296
+ ...(options.temperature === undefined ? {} : { temperature: options.temperature }),
297
297
  topP: options.topP,
298
298
  topK: options.topK,
299
299
  stopSequences: options.stopSequences,
@@ -1,8 +1,9 @@
1
1
  import type { Handler, HandlerContext, HandlerMetadata, HandlerResult } from "../../types/index.js";
2
+ import type { WebSocketUpgradeResponse } from "../../platform/adapters/base.js";
2
3
  import { ResponseBuilder } from "./response/index.js";
3
4
  export interface HandlerHelpers {
4
5
  createResponseBuilder: (ctx: HandlerContext, nonce?: string) => ResponseBuilder;
5
- respond: (response: Response, metadata?: Record<string, unknown>) => HandlerResult;
6
+ respond: (response: Response | WebSocketUpgradeResponse, metadata?: Record<string, unknown>) => HandlerResult;
6
7
  logDebug: (message: string, extra?: Record<string, unknown>, ctx?: HandlerContext) => void;
7
8
  getErrorMessage: (error: unknown) => string;
8
9
  continue: () => HandlerResult;
@@ -19,7 +20,7 @@ export declare abstract class BaseHandler implements Handler {
19
20
  protected logInfo(message: string, extra?: Record<string, unknown>, _ctx?: HandlerContext): void;
20
21
  protected getErrorMessage(error: unknown): string;
21
22
  protected continue(): HandlerResult;
22
- protected respond(response: Response, metadata?: Record<string, unknown>): HandlerResult;
23
+ protected respond(response: Response | WebSocketUpgradeResponse, metadata?: Record<string, unknown>): HandlerResult;
23
24
  protected withProxyContext<T>(ctx: HandlerContext, fn: () => Promise<T>, options?: {
24
25
  requireToken?: boolean;
25
26
  }): Promise<T>;