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.
- package/esm/cli/auth/callback-server.d.ts +4 -1
- package/esm/cli/auth/callback-server.d.ts.map +1 -1
- package/esm/cli/auth/callback-server.js +52 -13
- package/esm/cli/auth/index.d.ts +1 -1
- package/esm/cli/auth/index.d.ts.map +1 -1
- package/esm/cli/auth/index.js +1 -1
- package/esm/cli/auth/login.d.ts +2 -0
- package/esm/cli/auth/login.d.ts.map +1 -1
- package/esm/cli/auth/login.js +18 -6
- package/esm/cli/commands/demo/demo.d.ts.map +1 -1
- package/esm/cli/commands/demo/demo.js +6 -7
- package/esm/deno.js +1 -1
- package/esm/src/agent/runtime/index.d.ts +3 -96
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +21 -341
- package/esm/src/agent/runtime/model-capabilities.d.ts +3 -0
- package/esm/src/agent/runtime/model-capabilities.d.ts.map +1 -0
- package/esm/src/agent/runtime/model-capabilities.js +18 -0
- package/esm/src/agent/runtime/runtime-tool-config.d.ts +14 -0
- package/esm/src/agent/runtime/runtime-tool-config.d.ts.map +1 -0
- package/esm/src/agent/runtime/runtime-tool-config.js +37 -0
- package/esm/src/agent/runtime/skill-policy-enforcement.d.ts +16 -0
- package/esm/src/agent/runtime/skill-policy-enforcement.d.ts.map +1 -0
- package/esm/src/agent/runtime/skill-policy-enforcement.js +55 -0
- package/esm/src/agent/runtime/tool-result-continuation.d.ts +34 -0
- package/esm/src/agent/runtime/tool-result-continuation.d.ts.map +1 -0
- package/esm/src/agent/runtime/tool-result-continuation.js +194 -0
- package/esm/src/agent/schemas/agent.schema.d.ts +7 -0
- package/esm/src/agent/schemas/agent.schema.d.ts.map +1 -1
- package/esm/src/agent/schemas/agent.schema.js +9 -3
- package/esm/src/agent/schemas/index.d.ts +1 -1
- package/esm/src/agent/schemas/index.d.ts.map +1 -1
- package/esm/src/agent/schemas/index.js +1 -1
- package/esm/src/cache/dependency-graph.d.ts +1 -0
- package/esm/src/cache/dependency-graph.d.ts.map +1 -1
- package/esm/src/cache/dependency-graph.js +7 -1
- package/esm/src/modules/server/module-batch-handler.d.ts.map +1 -1
- package/esm/src/modules/server/module-batch-handler.js +47 -35
- package/esm/src/modules/server/module-server.d.ts.map +1 -1
- package/esm/src/modules/server/module-server.js +31 -9
- package/esm/src/modules/server/rate-limiter.d.ts +3 -2
- package/esm/src/modules/server/rate-limiter.d.ts.map +1 -1
- package/esm/src/platform/adapters/base.d.ts +24 -3
- package/esm/src/platform/adapters/base.d.ts.map +1 -1
- package/esm/src/platform/adapters/base.js +15 -1
- package/esm/src/platform/adapters/runtime/bun/websocket-adapter.d.ts +2 -0
- package/esm/src/platform/adapters/runtime/bun/websocket-adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/bun/websocket-adapter.js +33 -1
- package/esm/src/platform/adapters/runtime/node/websocket-adapter.d.ts +1 -1
- package/esm/src/platform/adapters/runtime/node/websocket-adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/node/websocket-adapter.js +3 -10
- package/esm/src/proxy/handler.d.ts.map +1 -1
- package/esm/src/proxy/handler.js +25 -116
- package/esm/src/proxy/local-project-resolver.d.ts +18 -0
- package/esm/src/proxy/local-project-resolver.d.ts.map +1 -0
- package/esm/src/proxy/local-project-resolver.js +63 -0
- package/esm/src/proxy/proxy-token-resolution.d.ts +37 -0
- package/esm/src/proxy/proxy-token-resolution.d.ts.map +1 -0
- package/esm/src/proxy/proxy-token-resolution.js +51 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts +10 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +23 -158
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts +20 -0
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.js +80 -0
- package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.d.ts +59 -0
- package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/module-loader/module-transform-cache.js +97 -0
- package/esm/src/routing/api/handler.d.ts +2 -1
- package/esm/src/routing/api/handler.d.ts.map +1 -1
- package/esm/src/routing/api/handler.js +2 -1
- package/esm/src/routing/api/route-executor.d.ts +3 -0
- package/esm/src/routing/api/route-executor.d.ts.map +1 -1
- package/esm/src/routing/api/route-executor.js +28 -0
- package/esm/src/runtime/runtime-bridge.js +2 -2
- package/esm/src/security/http/base-handler.d.ts +3 -2
- package/esm/src/security/http/base-handler.d.ts.map +1 -1
- package/esm/src/security/http/base-handler.js +1 -1
- package/esm/src/security/sandbox/project-worker.d.ts +1 -0
- package/esm/src/security/sandbox/project-worker.d.ts.map +1 -1
- package/esm/src/security/sandbox/project-worker.js +17 -1
- package/esm/src/security/sandbox/worker-egress-guard.d.ts +15 -0
- package/esm/src/security/sandbox/worker-egress-guard.d.ts.map +1 -0
- package/esm/src/security/sandbox/worker-egress-guard.js +201 -0
- package/esm/src/security/sandbox/worker-permissions.d.ts +6 -2
- package/esm/src/security/sandbox/worker-permissions.d.ts.map +1 -1
- package/esm/src/security/sandbox/worker-permissions.js +34 -3
- package/esm/src/security/sandbox/worker-pool.d.ts +1 -1
- package/esm/src/security/sandbox/worker-pool.d.ts.map +1 -1
- package/esm/src/security/sandbox/worker-pool.js +35 -9
- package/esm/src/server/handlers/preview/hmr-client-manager.d.ts +3 -2
- package/esm/src/server/handlers/preview/hmr-client-manager.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.js +4 -1
- package/esm/src/server/handlers/request/api/api-handler-wrapper.js +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.d.ts +32 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.d.ts.map +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/http-fallback.js +27 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/import-rewriter.js +23 -3
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +32 -30
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/persistence.d.ts +34 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/persistence.d.ts.map +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/persistence.js +30 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- 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 {
|
|
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
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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;
|
|
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;
|
|
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>;
|