veryfront 0.1.1102 → 0.1.1104
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/deno.js +1 -1
- package/esm/src/agent/ag-ui/tool-shared.d.ts.map +1 -1
- package/esm/src/agent/ag-ui/tool-shared.js +0 -4
- package/esm/src/agent/factory.d.ts.map +1 -1
- package/esm/src/agent/factory.js +29 -31
- package/esm/src/agent/hosted/chat-preparation.d.ts +1 -0
- package/esm/src/agent/hosted/chat-preparation.d.ts.map +1 -1
- package/esm/src/agent/hosted/chat-preparation.js +20 -12
- package/esm/src/agent/hosted/default-project-steering-refresh.d.ts +1 -1
- package/esm/src/agent/hosted/default-project-steering-refresh.d.ts.map +1 -1
- package/esm/src/agent/hosted/default-project-steering-refresh.js +5 -9
- package/esm/src/agent/hosted/runtime-essential-tools.d.ts +1 -1
- package/esm/src/agent/hosted/runtime-essential-tools.d.ts.map +1 -1
- package/esm/src/agent/hosted/runtime-essential-tools.js +14 -5
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.d.ts.map +1 -1
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.js +4 -0
- package/esm/src/agent/index.d.ts +1 -1
- package/esm/src/agent/index.js +1 -1
- package/esm/src/agent/runtime/agent-definition.d.ts.map +1 -1
- package/esm/src/agent/runtime/agent-definition.js +3 -0
- package/esm/src/agent/runtime/agent-runtime-step.js +1 -1
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +0 -2
- package/esm/src/agent/runtime/skill-metadata.d.ts +11 -0
- package/esm/src/agent/runtime/skill-metadata.d.ts.map +1 -1
- package/esm/src/agent/runtime/skill-metadata.js +24 -0
- package/esm/src/agent/runtime/skill-prompt.d.ts.map +1 -1
- package/esm/src/agent/runtime/skill-prompt.js +5 -2
- package/esm/src/agent/types.d.ts +8 -6
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/channels/control-plane.d.ts.map +1 -1
- package/esm/src/channels/control-plane.js +1 -4
- package/esm/src/data/helpers.d.ts +20 -3
- package/esm/src/data/helpers.d.ts.map +1 -1
- package/esm/src/data/helpers.js +46 -12
- package/esm/src/data/static-data-fetcher.d.ts.map +1 -1
- package/esm/src/data/static-data-fetcher.js +15 -0
- package/esm/src/extensions/builtin-extensions.d.ts +1 -1
- package/esm/src/extensions/builtin-extensions.d.ts.map +1 -1
- package/esm/src/extensions/builtin-extensions.js +1 -6
- package/esm/src/extensions/builtin-schema-validator.d.ts +3 -0
- package/esm/src/extensions/builtin-schema-validator.d.ts.map +1 -0
- package/esm/src/extensions/builtin-schema-validator.js +8 -0
- package/esm/src/html/hydration-script-builder/templates/renderer.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/templates/renderer.js +52 -28
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
- package/esm/src/internal-agents/run-stream.js +6 -11
- package/esm/src/internal-agents/run-system-prompt.d.ts +1 -1
- package/esm/src/internal-agents/run-system-prompt.js +1 -1
- package/esm/src/modules/server/module-server.d.ts.map +1 -1
- package/esm/src/modules/server/module-server.js +15 -9
- package/esm/src/rendering/orchestrator/module-loader/build-failure.d.ts +20 -0
- package/esm/src/rendering/orchestrator/module-loader/build-failure.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/module-loader/build-failure.js +26 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts +2 -1
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +69 -7
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts +6 -0
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/module-persistence.js +49 -0
- package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/pipeline.js +10 -1
- package/esm/src/routing/api/context-builder.d.ts +26 -15
- package/esm/src/routing/api/context-builder.d.ts.map +1 -1
- package/esm/src/routing/api/context-builder.js +34 -15
- package/esm/src/routing/api/module-loader/loader.js +57 -1
- package/esm/src/server/dev-server/middleware.d.ts.map +1 -1
- package/esm/src/server/dev-server/middleware.js +29 -6
- package/esm/src/server/handlers/request/ssr/ssr.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/ssr/ssr.handler.js +6 -4
- package/esm/src/skill/prompt-augmentation.d.ts +4 -2
- package/esm/src/skill/prompt-augmentation.d.ts.map +1 -1
- package/esm/src/skill/prompt-augmentation.js +13 -2
- package/esm/src/transforms/esm/import-attributes.d.ts +32 -0
- package/esm/src/transforms/esm/import-attributes.d.ts.map +1 -0
- package/esm/src/transforms/esm/import-attributes.js +116 -0
- package/esm/src/transforms/esm/import-parser.d.ts.map +1 -1
- package/esm/src/transforms/esm/import-parser.js +68 -18
- package/esm/src/transforms/esm/lexer.d.ts +18 -0
- package/esm/src/transforms/esm/lexer.d.ts.map +1 -1
- package/esm/src/transforms/esm/lexer.js +21 -0
- package/esm/src/transforms/esm/specifier-resolver.d.ts.map +1 -1
- package/esm/src/transforms/esm/specifier-resolver.js +13 -0
- package/esm/src/transforms/esm/transform-utils.d.ts +8 -0
- package/esm/src/transforms/esm/transform-utils.d.ts.map +1 -1
- package/esm/src/transforms/esm/transform-utils.js +11 -1
- package/esm/src/transforms/import-rewriter/project-paths.d.ts +26 -0
- package/esm/src/transforms/import-rewriter/project-paths.d.ts.map +1 -0
- package/esm/src/transforms/import-rewriter/project-paths.js +49 -0
- package/esm/src/transforms/import-rewriter/strategies/alias-strategy.d.ts +0 -1
- package/esm/src/transforms/import-rewriter/strategies/alias-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/alias-strategy.js +5 -20
- package/esm/src/transforms/import-rewriter/strategies/asset-strategy.d.ts +1 -1
- package/esm/src/transforms/import-rewriter/strategies/asset-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/asset-strategy.js +62 -12
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.js +19 -3
- package/esm/src/transforms/import-rewriter/strategies/node-builtin-strategy.d.ts +11 -0
- package/esm/src/transforms/import-rewriter/strategies/node-builtin-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/node-builtin-strategy.js +13 -0
- package/esm/src/transforms/import-rewriter/strategies/relative-strategy.d.ts +0 -1
- package/esm/src/transforms/import-rewriter/strategies/relative-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/relative-strategy.js +2 -16
- package/esm/src/transforms/import-rewriter/strategies/veryfront-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/veryfront-strategy.js +4 -3
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.d.ts +4 -2
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/nested-imports.js +23 -7
- package/esm/src/transforms/pipeline/stages/browser-node-builtin-imports.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/browser-node-builtin-imports.js +5 -0
- package/esm/src/transforms/pipeline/stages/browser-server-exports-strip.d.ts +25 -3
- package/esm/src/transforms/pipeline/stages/browser-server-exports-strip.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/browser-server-exports-strip.js +285 -44
- package/esm/src/transforms/pipeline/stages/compile.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/compile.js +6 -1
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts +9 -5
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.js +23 -9
- package/esm/src/transforms/shared/server-only-packages.d.ts +30 -0
- package/esm/src/transforms/shared/server-only-packages.d.ts.map +1 -0
- package/esm/src/transforms/shared/server-only-packages.js +47 -0
- package/esm/src/types/entities/getEntityInfo.d.ts.map +1 -1
- package/esm/src/types/entities/getEntityInfo.js +10 -2
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -5
|
@@ -16,6 +16,8 @@ import { resolveModuleDependencies, rewriteResolvedDependencyImports, } from "./
|
|
|
16
16
|
import { persistTransformedModule } from "./module-persistence.js";
|
|
17
17
|
import { transformModuleCodeWithCache } from "./module-transform-cache.js";
|
|
18
18
|
import { getModuleCacheKey, resolveCachedModulePath } from "./module-cache-lookup.js";
|
|
19
|
+
import { markBuildFailure } from "./build-failure.js";
|
|
20
|
+
export { isBuildFailure } from "./build-failure.js";
|
|
19
21
|
const logger = rendererLogger.component("module-loader");
|
|
20
22
|
// Re-export utilities
|
|
21
23
|
export { createEsmCache, createModuleCache, generateHash } from "./cache.js";
|
|
@@ -35,7 +37,12 @@ function decodeFileContent(fileContent) {
|
|
|
35
37
|
* @param useLocalAdapter - Whether to use local adapter for reading
|
|
36
38
|
* @returns Path to the transformed module file
|
|
37
39
|
*/
|
|
38
|
-
export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, config, useLocalAdapter = false)
|
|
40
|
+
export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, config, useLocalAdapter = false, lineage = new Set(),
|
|
41
|
+
// Shared by reference across the whole transform tree (unlike `lineage`, which
|
|
42
|
+
// is copied per level): a descendant records a cycle target here, and the
|
|
43
|
+
// ancestor that eventually persists that target reads it to write a stable
|
|
44
|
+
// alias the left-as-authored cycle edge can resolve to.
|
|
45
|
+
cycleTargets = new Set()) {
|
|
39
46
|
const { moduleCache, projectDir, projectId, contentSourceId, adapter, mode } = config;
|
|
40
47
|
const cacheKey = getModuleCacheKey(filePath, projectId, projectDir, contentSourceId, config.reactVersion, mode);
|
|
41
48
|
const cachedPath = await resolveCachedModulePath({
|
|
@@ -58,15 +65,55 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
|
|
|
58
65
|
filePath,
|
|
59
66
|
projectDir,
|
|
60
67
|
});
|
|
61
|
-
|
|
68
|
+
// The module cache is only written once a transform completes, so it cannot
|
|
69
|
+
// break a cycle that is still in progress. Carry the chain instead.
|
|
70
|
+
const nextLineage = new Set(lineage).add(filePath);
|
|
71
|
+
const transformedDeps = (await Promise.all(resolvedDeps.filter((d) => d.depFilePath).map(async (dep) => {
|
|
72
|
+
// `await import()` is how a module graph legitimately breaks an import
|
|
73
|
+
// cycle, so following one eagerly can lead straight back to a module
|
|
74
|
+
// further up this chain and recurse until the worker dies. Leave the
|
|
75
|
+
// specifier as authored so the recursion terminates.
|
|
76
|
+
//
|
|
77
|
+
// The cycle target is persisted as a content-hashed artifact whose hash
|
|
78
|
+
// is derived from transformed output we do not produce here (producing it
|
|
79
|
+
// is the recursion we are breaking), so the edge cannot be rewritten to
|
|
80
|
+
// that hashed path. Instead we record the target: when its ancestor
|
|
81
|
+
// persists it, a stable non-hashed alias is written next to the hashed
|
|
82
|
+
// artifact so the relative `.js` specifier esbuild leaves behind resolves.
|
|
83
|
+
// NOTE: this alias path is not yet runtime-verified end to end; if it does
|
|
84
|
+
// not resolve in a real runtime the cycle branch stays broken, which is no
|
|
85
|
+
// worse than before (and still a strict improvement over hanging).
|
|
86
|
+
if (nextLineage.has(dep.depFilePath)) {
|
|
87
|
+
cycleTargets.add(dep.depFilePath);
|
|
88
|
+
logger.debug("Skipping dependency already in the transform chain:", {
|
|
89
|
+
path: dep.path,
|
|
90
|
+
depFilePath: dep.depFilePath,
|
|
91
|
+
});
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
62
94
|
logger.debug("Found dependency:", {
|
|
63
95
|
path: dep.path,
|
|
64
96
|
depFilePath: dep.depFilePath,
|
|
65
97
|
isLocalLib: dep.isLocalLib,
|
|
66
98
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
99
|
+
try {
|
|
100
|
+
const depTempPath = await transformModuleWithDeps(dep.depFilePath, tmpDir, localAdapter, config, dep.isLocalLib, nextLineage, cycleTargets);
|
|
101
|
+
return { ...dep, depTempPath };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
// A static import has to resolve for the importer to run at all. A
|
|
105
|
+
// dynamic one may never be evaluated, so a module behind an untaken
|
|
106
|
+
// branch must not fail the page that merely mentions it.
|
|
107
|
+
if (!dep.isDynamic)
|
|
108
|
+
throw error;
|
|
109
|
+
logger.warn("Leaving an unresolvable dynamic dependency as authored:", {
|
|
110
|
+
path: dep.path,
|
|
111
|
+
depFilePath: dep.depFilePath,
|
|
112
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
113
|
+
});
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}))).filter((dep) => dep !== null);
|
|
70
117
|
fileContent = rewriteResolvedDependencyImports(fileContent, transformedDeps);
|
|
71
118
|
for (const dep of transformedDeps) {
|
|
72
119
|
logger.debug("Replaced import:", {
|
|
@@ -103,6 +150,7 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
|
|
|
103
150
|
cacheKey,
|
|
104
151
|
contentSourceId,
|
|
105
152
|
reactVersion: config.reactVersion,
|
|
153
|
+
isCycleTarget: cycleTargets.has(filePath),
|
|
106
154
|
});
|
|
107
155
|
}
|
|
108
156
|
/**
|
|
@@ -146,7 +194,15 @@ export function isMissingModuleError(error) {
|
|
|
146
194
|
export async function loadModule(filePath, config) {
|
|
147
195
|
const tmpDir = await getModuleCacheDir(config);
|
|
148
196
|
const localAdapter = await getLocalAdapter();
|
|
149
|
-
|
|
197
|
+
// Everything up to here compiles and resolves source, so a failure is a build
|
|
198
|
+
// failure. Everything after it is the module running.
|
|
199
|
+
let tempFilePath;
|
|
200
|
+
try {
|
|
201
|
+
tempFilePath = await transformModuleWithDeps(filePath, tmpDir, localAdapter, config);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
throw markBuildFailure(error);
|
|
205
|
+
}
|
|
150
206
|
const moduleUrl = `file://${tempFilePath}`;
|
|
151
207
|
try {
|
|
152
208
|
return await import(moduleUrl);
|
|
@@ -189,7 +245,13 @@ export async function loadModule(filePath, config) {
|
|
|
189
245
|
// invalidation stays scoped to this tenant (the path-cache key is not
|
|
190
246
|
// project-scoped — see invalidateMdxEsmModule).
|
|
191
247
|
invalidateMdxEsmModule(tmpDir, filePath, config.projectDir, config.reactVersion);
|
|
192
|
-
|
|
248
|
+
let rebuiltPath;
|
|
249
|
+
try {
|
|
250
|
+
rebuiltPath = await transformModuleWithDeps(filePath, tmpDir, localAdapter, config);
|
|
251
|
+
}
|
|
252
|
+
catch (rebuildError) {
|
|
253
|
+
throw markBuildFailure(rebuildError);
|
|
254
|
+
}
|
|
193
255
|
return await import(`file://${rebuiltPath}?t=${Date.now()}&rebuilt=1`);
|
|
194
256
|
}
|
|
195
257
|
logger.error("Failed to import module:", {
|
|
@@ -14,6 +14,12 @@ export interface PersistTransformedModuleInput {
|
|
|
14
14
|
cacheKey: string;
|
|
15
15
|
contentSourceId?: string;
|
|
16
16
|
reactVersion?: string;
|
|
17
|
+
/**
|
|
18
|
+
* True when a dynamic import elsewhere closes a cycle back onto this module.
|
|
19
|
+
* Such an edge is left as authored (`import("../app/page.js")`), so it needs a
|
|
20
|
+
* stable, non-hashed alias next to the content-hashed artifact to resolve to.
|
|
21
|
+
*/
|
|
22
|
+
isCycleTarget?: boolean;
|
|
17
23
|
}
|
|
18
24
|
/** Write a transformed module artifact and register cache pointers. */
|
|
19
25
|
export declare function persistTransformedModule(input: PersistTransformedModuleInput): Promise<string>;
|
|
@@ -1 +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;AAuDzE,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;
|
|
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;AAuDzE,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;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAqDD,uEAAuE;AACvE,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,MAAM,CAAC,CAqEjB"}
|
|
@@ -44,6 +44,51 @@ async function ensureDir(adapter, dir, force = false) {
|
|
|
44
44
|
createdDirs.add(dir);
|
|
45
45
|
pruneCreatedDirs();
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Whether transformed output exposes a default export, so a cycle alias knows
|
|
49
|
+
* to re-export it. Covers esbuild's `export default …`, `… as default`, and
|
|
50
|
+
* `export { default } from …` forms.
|
|
51
|
+
*/
|
|
52
|
+
function hasDefaultExport(code) {
|
|
53
|
+
return /\bexport\s+default\b/.test(code) ||
|
|
54
|
+
/\bas\s+default\b/.test(code) ||
|
|
55
|
+
/\bexport\s*\{[^}]*\bdefault\b[^}]*\}/.test(code);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Write a stable, non-hashed alias next to a cycle target's hashed artifact.
|
|
59
|
+
*
|
|
60
|
+
* A dynamic import that closes an import cycle is left as the author wrote it
|
|
61
|
+
* (see the module loader), so esbuild normalises it to a relative `.js` path
|
|
62
|
+
* (`../app/page.js`) that does not match the content-hashed artifact
|
|
63
|
+
* (`../app/page.<hash>.js`). The alias sits at that relative path and re-exports
|
|
64
|
+
* the real artifact, so the edge resolves if the branch runs. Best-effort: a
|
|
65
|
+
* failed alias just leaves the pre-existing (unresolved) cycle edge in place.
|
|
66
|
+
*/
|
|
67
|
+
async function writeCycleTargetAlias(input, relativePath, hashedFileName) {
|
|
68
|
+
const aliasRelativePath = relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js");
|
|
69
|
+
// Same extension in and out means nothing was renamed (already `.js`): the
|
|
70
|
+
// authored edge already points at the real artifact, so no alias is needed.
|
|
71
|
+
if (aliasRelativePath === relativePath)
|
|
72
|
+
return;
|
|
73
|
+
const aliasPath = join(input.tmpDir, aliasRelativePath);
|
|
74
|
+
const lines = [`export * from "./${hashedFileName}";`];
|
|
75
|
+
if (hasDefaultExport(input.transformedCode)) {
|
|
76
|
+
lines.push(`export { default } from "./${hashedFileName}";`);
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await input.localAdapter.fs.writeFile(aliasPath, lines.join("\n"));
|
|
80
|
+
logger.debug("Wrote cycle-target alias", {
|
|
81
|
+
alias: aliasRelativePath,
|
|
82
|
+
target: hashedFileName,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger.warn("Failed to write cycle-target alias", {
|
|
87
|
+
filePath: input.filePath.slice(-40),
|
|
88
|
+
error: error instanceof Error ? error.message : String(error),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
47
92
|
/** Write a transformed module artifact and register cache pointers. */
|
|
48
93
|
export async function persistTransformedModule(input) {
|
|
49
94
|
const transformedHash = hashCodeHex(input.transformedCode).slice(0, 8);
|
|
@@ -100,5 +145,9 @@ export async function persistTransformedModule(input) {
|
|
|
100
145
|
});
|
|
101
146
|
}
|
|
102
147
|
input.moduleCache.set(input.cacheKey, tempFilePath);
|
|
148
|
+
if (input.isCycleTarget) {
|
|
149
|
+
const hashedFileName = jsPath.slice(jsPath.lastIndexOf("/") + 1);
|
|
150
|
+
await writeCycleTargetAlias(input, relativePath, hashedFileName);
|
|
151
|
+
}
|
|
103
152
|
return tempFilePath;
|
|
104
153
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAUH,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,iCAAiC,CAAC;AASzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAUH,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,iCAAiC,CAAC;AASzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAsDhF,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACxE,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrF;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,OAAO,qBAAqB,EAAE,sBAAsB,CAAC;CAC1E;AA0BD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,mBAAmB,CAAgC;gBAE/C,MAAM,EAAE,oBAAoB;IAcxC,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,oBAAoB;IA0B5B;;;;OAIG;YACW,yBAAyB;IAWvC;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAKxB,OAAO,CAAC,UAAU;YAOJ,0BAA0B;IAaxC;;;;;;;;;OASG;YACW,qBAAqB;IAqEnC;;;OAGG;YACW,mBAAmB;IA6GjC,OAAO,CAAC,uBAAuB;IAkCzB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAyT9E,+EAA+E;IACzE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAsHzE,kBAAkB;YA2ClB,cAAc;IAW5B,OAAO,CAAC,uBAAuB;YAYjB,kBAAkB;IAyFhC,OAAO,CAAC,kBAAkB;YAQZ,uBAAuB;IAmBrC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;CAStB"}
|
|
@@ -35,6 +35,7 @@ import { buildReleaseAssetModules } from "../../release-assets/client-module-map
|
|
|
35
35
|
import { getCSSByHashAsync, regenerateCSSByHash, } from "../../html/styles-builder/tailwind-compiler.js";
|
|
36
36
|
import { getReadyManifestForRender } from "../../release-assets/manifest-cache.js";
|
|
37
37
|
import { createEsmCache, createModuleCache, loadModule } from "./module-loader/index.js";
|
|
38
|
+
import { isBuildFailure } from "./module-loader/build-failure.js";
|
|
38
39
|
import { getCSSImports, runWithCSSCollector, } from "../../modules/react-loader/css-import-collector.js";
|
|
39
40
|
import { assembleRenderResult } from "./render-result-assembly.js";
|
|
40
41
|
import { isMdxEsmExportMismatchError, recoverStaleMdxEsmPreviewCaches } from "../page-rendering.js";
|
|
@@ -160,7 +161,11 @@ export class RenderPipeline {
|
|
|
160
161
|
continue;
|
|
161
162
|
const errorMessage = result.error.message;
|
|
162
163
|
if (result.type === "page") {
|
|
163
|
-
criticalFailures.push({
|
|
164
|
+
criticalFailures.push({
|
|
165
|
+
path: result.path,
|
|
166
|
+
error: errorMessage,
|
|
167
|
+
buildFailure: isBuildFailure(result.error),
|
|
168
|
+
});
|
|
164
169
|
renderPageLog.error("Critical page module failed to load", {
|
|
165
170
|
path: result.path,
|
|
166
171
|
error: errorMessage,
|
|
@@ -180,6 +185,10 @@ export class RenderPipeline {
|
|
|
180
185
|
detail: `Critical page module(s) failed to load:\n${failedDetails}`,
|
|
181
186
|
context: {
|
|
182
187
|
criticalFailures,
|
|
188
|
+
// A module that never compiled is a developer-facing build failure;
|
|
189
|
+
// one that compiled and threw at module scope is an application
|
|
190
|
+
// error the project's own error page should present.
|
|
191
|
+
buildFailure: criticalFailures.some((f) => f.buildFailure),
|
|
183
192
|
loadedCount: loaded.length,
|
|
184
193
|
totalModules: modules.length,
|
|
185
194
|
},
|
|
@@ -12,31 +12,42 @@ export interface APIContext {
|
|
|
12
12
|
headers: Headers;
|
|
13
13
|
url: URL;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Build a JSON `Response`. `ctx.json(data, init?)` mirrors `Response.json`.
|
|
16
16
|
*
|
|
17
|
-
* `ctx.
|
|
18
|
-
* `ctx.json(data, init?)` returns a JSON `Response`.
|
|
17
|
+
* To read the request body, use `ctx.body()` or the raw `ctx.request.json()`.
|
|
19
18
|
*/
|
|
20
|
-
json:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
json: (data: unknown, init?: ResponseInit) => Response;
|
|
20
|
+
/**
|
|
21
|
+
* Read and parse the request body as JSON.
|
|
22
|
+
*
|
|
23
|
+
* The result is cached, so calling it more than once (or alongside a manual
|
|
24
|
+
* `ctx.request.json()`) does not throw `Body already consumed`. A body that
|
|
25
|
+
* is not valid JSON becomes a 400, not an unhandled 500.
|
|
26
|
+
*/
|
|
27
|
+
body: <T = unknown>() => Promise<T>;
|
|
24
28
|
text: (data: string, init?: ResponseInit) => Response;
|
|
25
29
|
fs: FileSystemAdapter;
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
28
|
-
* Build the `ctx.json` helper
|
|
29
|
-
*
|
|
30
|
-
* Overloaded on arity. `ctx.json(data)` builds a response; `ctx.json()` reads
|
|
31
|
-
* the request body, which is what handlers reach for, and what the zero-arg
|
|
32
|
-
* form was previously misread as. It used to stringify `undefined` into a
|
|
33
|
-
* Response, so `await ctx.json()` yielded a Response object that serialised
|
|
34
|
-
* back out as `{}` and silently dropped every posted payload.
|
|
32
|
+
* Build the `ctx.json` response helper. Writes only; mirrors `Response.json`.
|
|
35
33
|
*
|
|
36
34
|
* Exported because the isolation Worker builds its own context and has to
|
|
37
35
|
* behave identically. Handlers must not care which one ran them.
|
|
38
36
|
*/
|
|
39
|
-
export declare function createJsonHelper(
|
|
37
|
+
export declare function createJsonHelper(_request: Request): APIContext["json"];
|
|
38
|
+
/**
|
|
39
|
+
* Build the `ctx.body` request-body reader.
|
|
40
|
+
*
|
|
41
|
+
* The parse is memoised on the first call, so a validation helper and a handler
|
|
42
|
+
* that both read the body do not fight over a single-use stream. The clone is
|
|
43
|
+
* taken up front, while the context is built, so `ctx.request` is left intact
|
|
44
|
+
* for a handler that still wants the raw stream — and, crucially, so a handler
|
|
45
|
+
* that reads `ctx.request` raw *before* calling `ctx.body()` cannot make the
|
|
46
|
+
* clone throw `Body already consumed` (`request.clone()` throws synchronously
|
|
47
|
+
* once the original stream is disturbed). A malformed body is turned into a
|
|
48
|
+
* catalogued 400 rather than escaping as a 500.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createBodyReader(request: Request): APIContext["body"];
|
|
40
51
|
export declare function createContext(request: Request, match: RouteMatch, fs: FileSystemAdapter): APIContext;
|
|
41
52
|
/**
|
|
42
53
|
* @deprecated Use {@link flattenRouteParams} directly. Kept as a thin alias so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAI3D,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC;IACvD;;;;;;OAMG;IACH,IAAI,EAAE,CAAC,CAAC,GAAG,OAAO,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC;IACtD,EAAE,EAAE,iBAAiB,CAAC;CACvB;AAgBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAGtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAiBrE;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,iBAAiB,GACpB,UAAU,CAqBZ;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACxC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseCookies } from "../../utils/cookie-utils.js";
|
|
2
|
+
import { INVALID_ARGUMENT } from "../../errors/index.js";
|
|
2
3
|
import { flattenRouteParams } from "../flatten-route-params.js";
|
|
3
4
|
export { parseCookies };
|
|
4
5
|
function createResponse(body, contentType, init) {
|
|
@@ -11,29 +12,46 @@ function createResponse(body, contentType, init) {
|
|
|
11
12
|
});
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
|
-
* Build the `ctx.json` helper
|
|
15
|
-
*
|
|
16
|
-
* Overloaded on arity. `ctx.json(data)` builds a response; `ctx.json()` reads
|
|
17
|
-
* the request body, which is what handlers reach for, and what the zero-arg
|
|
18
|
-
* form was previously misread as. It used to stringify `undefined` into a
|
|
19
|
-
* Response, so `await ctx.json()` yielded a Response object that serialised
|
|
20
|
-
* back out as `{}` and silently dropped every posted payload.
|
|
15
|
+
* Build the `ctx.json` response helper. Writes only; mirrors `Response.json`.
|
|
21
16
|
*
|
|
22
17
|
* Exported because the isolation Worker builds its own context and has to
|
|
23
18
|
* behave identically. Handlers must not care which one ran them.
|
|
24
19
|
*/
|
|
25
|
-
export function createJsonHelper(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
export function createJsonHelper(_request) {
|
|
21
|
+
return (data, init) => createResponse(JSON.stringify(data), "application/json", init);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build the `ctx.body` request-body reader.
|
|
25
|
+
*
|
|
26
|
+
* The parse is memoised on the first call, so a validation helper and a handler
|
|
27
|
+
* that both read the body do not fight over a single-use stream. The clone is
|
|
28
|
+
* taken up front, while the context is built, so `ctx.request` is left intact
|
|
29
|
+
* for a handler that still wants the raw stream — and, crucially, so a handler
|
|
30
|
+
* that reads `ctx.request` raw *before* calling `ctx.body()` cannot make the
|
|
31
|
+
* clone throw `Body already consumed` (`request.clone()` throws synchronously
|
|
32
|
+
* once the original stream is disturbed). A malformed body is turned into a
|
|
33
|
+
* catalogued 400 rather than escaping as a 500.
|
|
34
|
+
*/
|
|
35
|
+
export function createBodyReader(request) {
|
|
36
|
+
// Clone eagerly: at construction time the original body is guaranteed
|
|
37
|
+
// untouched, so the read is order-independent with any raw `ctx.request`
|
|
38
|
+
// access a handler performs later.
|
|
39
|
+
const source = request.clone();
|
|
40
|
+
let parsed;
|
|
41
|
+
const read = () => {
|
|
42
|
+
if (!parsed) {
|
|
43
|
+
parsed = source.json().catch(() => {
|
|
44
|
+
throw INVALID_ARGUMENT.create({ detail: "Request body is not valid JSON" });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return parsed;
|
|
48
|
+
};
|
|
49
|
+
return () => read();
|
|
33
50
|
}
|
|
34
51
|
export function createContext(request, match, fs) {
|
|
35
52
|
const url = new URL(request.url);
|
|
36
53
|
const json = createJsonHelper(request);
|
|
54
|
+
const body = createBodyReader(request);
|
|
37
55
|
const text = (data, init) => createResponse(data, "text/plain", init);
|
|
38
56
|
return {
|
|
39
57
|
request,
|
|
@@ -44,6 +62,7 @@ export function createContext(request, match, fs) {
|
|
|
44
62
|
headers: request.headers,
|
|
45
63
|
url,
|
|
46
64
|
json,
|
|
65
|
+
body,
|
|
47
66
|
text,
|
|
48
67
|
fs,
|
|
49
68
|
};
|
|
@@ -5,7 +5,7 @@ import { validateHTTPImports } from "./http-validator.js";
|
|
|
5
5
|
import { loadSecurityConfig } from "./security-config.js";
|
|
6
6
|
import { createError, toError } from "../../../errors/index.js";
|
|
7
7
|
import { getEsbuildLoader } from "../../../utils/path-utils.js";
|
|
8
|
-
import { createFileSystem } from "../../../platform/compat/fs.js";
|
|
8
|
+
import { createFileSystem, realPath } from "../../../platform/compat/fs.js";
|
|
9
9
|
import * as pathHelper from "../../../platform/compat/path/index.js";
|
|
10
10
|
import { FILE_EXTENSIONS, getLoaderForFile, validateModulePath } from "./loader-helpers.js";
|
|
11
11
|
import { isDeno } from "../../../platform/compat/runtime.js";
|
|
@@ -211,6 +211,61 @@ function createAdapterResolvePlugin(adapter, projectDir) {
|
|
|
211
211
|
},
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Refuse to load any file the bundle resolved outside the project.
|
|
216
|
+
*
|
|
217
|
+
* The resolver plugins above validate the specifiers they claim, but esbuild
|
|
218
|
+
* applies the project's own tsconfig `paths` itself, before any `onResolve`
|
|
219
|
+
* callback runs. A templated project maps `@/*` to `./*`, so `@/../secrets.ts`
|
|
220
|
+
* is resolved by esbuild straight to a path above the project root and loaded
|
|
221
|
+
* in the default namespace, where none of those guards ever see it.
|
|
222
|
+
*
|
|
223
|
+
* This runs at load time instead, which is the one point every resolution
|
|
224
|
+
* strategy converges on. Returning `undefined` defers to normal loading, so the
|
|
225
|
+
* plugin only ever subtracts. Package code is exempt: `node_modules` is
|
|
226
|
+
* resolved by esbuild's own node resolution rather than by a project alias, and
|
|
227
|
+
* is legitimately hoisted above the project root in a monorepo.
|
|
228
|
+
*
|
|
229
|
+
* `roots` carries both the project path as configured and its symlink-resolved
|
|
230
|
+
* form, because esbuild reports the real path of a file it loaded. A project
|
|
231
|
+
* reached through a symlink (`/var` -> `/private/var` on macOS, and any deploy
|
|
232
|
+
* layout that symlinks a release directory) would otherwise fail every import.
|
|
233
|
+
*/
|
|
234
|
+
/**
|
|
235
|
+
* The project path as configured, plus its symlink-resolved form when they
|
|
236
|
+
* differ. `realPath` throws if the directory is missing, in which case the
|
|
237
|
+
* configured path is all there is to compare against.
|
|
238
|
+
*/
|
|
239
|
+
async function resolveProjectRoots(projectDir) {
|
|
240
|
+
const configured = pathHelper.resolve(projectDir);
|
|
241
|
+
try {
|
|
242
|
+
const real = await realPath(configured);
|
|
243
|
+
return real === configured ? [configured] : [configured, real];
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return [configured];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function createProjectBoundaryPlugin(roots) {
|
|
250
|
+
return {
|
|
251
|
+
name: "vf-project-boundary",
|
|
252
|
+
setup(build) {
|
|
253
|
+
build.onLoad({ filter: /.*/ }, (args) => {
|
|
254
|
+
if (roots.some((root) => isWithinDirectory(root, args.path)))
|
|
255
|
+
return undefined;
|
|
256
|
+
if (args.path.split(/[\\/]/).includes("node_modules"))
|
|
257
|
+
return undefined;
|
|
258
|
+
logger.error(`[API] Resolved import escapes project: ${args.path}`);
|
|
259
|
+
return {
|
|
260
|
+
errors: [{
|
|
261
|
+
text: `Import escapes the project directory: ${args.path}. ` +
|
|
262
|
+
`API routes may only import files inside the project.`,
|
|
263
|
+
}],
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
214
269
|
function loadAndTranspileModule(modulePath, projectDir, adapter, fs, config) {
|
|
215
270
|
return withSpan("api.loadAndTranspileModule", async () => {
|
|
216
271
|
const { filePath: resolvedPath, contents: source } = await readFileWithExtensions(adapter, modulePath, FILE_EXTENSIONS, projectDir);
|
|
@@ -289,6 +344,7 @@ function loadAndTranspileModule(modulePath, projectDir, adapter, fs, config) {
|
|
|
289
344
|
createImportMapPlugin(projectDir, adapter, config),
|
|
290
345
|
createAdapterResolvePlugin(adapter, projectDir),
|
|
291
346
|
createHTTPPlugin({ allowedHosts, projectDir }),
|
|
347
|
+
createProjectBoundaryPlugin(await resolveProjectRoots(projectDir)),
|
|
292
348
|
],
|
|
293
349
|
});
|
|
294
350
|
if (result.errors?.length) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAM7D,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAkFD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAkC/B;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAM7D,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAkFD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAkC/B;AAgJD,wBAAsB,eAAe,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,eAAe,EACvB,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -136,25 +136,48 @@ async function loadMiddlewareFromVirtualFS(middlewarePath, adapter, strictExport
|
|
|
136
136
|
await fs.remove(tempDir, { recursive: true });
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
+
/** Describe the shape of the default export that was rejected. */
|
|
140
|
+
function describeDefaultExport(exported) {
|
|
141
|
+
if (Array.isArray(exported)) {
|
|
142
|
+
if (exported.length === 0)
|
|
143
|
+
return `Found an empty default export array.`;
|
|
144
|
+
const badIndex = exported.findIndex((value) => typeof value !== "function");
|
|
145
|
+
if (badIndex >= 0) {
|
|
146
|
+
return `Found a default export array with a non-function at index ${badIndex} ` +
|
|
147
|
+
`(${typeof exported[badIndex]}).`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (exported && typeof exported === "object") {
|
|
151
|
+
const keys = Object.keys(exported);
|
|
152
|
+
return keys.length > 0
|
|
153
|
+
? `Found a default export of type object with keys: ${keys.join(", ")}.`
|
|
154
|
+
: `Found a default export of type object with no keys.`;
|
|
155
|
+
}
|
|
156
|
+
return `Found a default export of type ${typeof exported}.`;
|
|
157
|
+
}
|
|
139
158
|
/**
|
|
140
159
|
* Explain what a root middleware file must export. When the module looks like it
|
|
141
160
|
* was written for Next.js, say so, because that is overwhelmingly why this
|
|
142
161
|
* fails. A bad root middleware takes down every route, so the message has
|
|
143
162
|
* to be enough to fix the file without reading the source.
|
|
144
163
|
*/
|
|
145
|
-
function invalidMiddlewareExport(middlewareModule, sourceFile) {
|
|
164
|
+
function invalidMiddlewareExport(middlewareModule, sourceFile, exported) {
|
|
146
165
|
const named = middlewareModule && typeof middlewareModule === "object"
|
|
147
166
|
? Object.keys(middlewareModule)
|
|
148
167
|
: [];
|
|
149
168
|
const looksLikeNext = named.includes("middleware") &&
|
|
150
169
|
typeof middlewareModule.middleware === "function";
|
|
170
|
+
const hasDefault = middlewareModule && typeof middlewareModule === "object" &&
|
|
171
|
+
"default" in middlewareModule;
|
|
151
172
|
const detail = looksLikeNext
|
|
152
173
|
? `Found a named "middleware" export, which is the Next.js convention. ` +
|
|
153
174
|
`Veryfront expects a default export, and its middleware receives ` +
|
|
154
175
|
`(c, next), where c is a context carrying c.req, not the Request itself.`
|
|
155
|
-
:
|
|
156
|
-
?
|
|
157
|
-
:
|
|
176
|
+
: hasDefault
|
|
177
|
+
? describeDefaultExport(exported)
|
|
178
|
+
: named.length > 0
|
|
179
|
+
? `Found export(s): ${named.join(", ")}.`
|
|
180
|
+
: `The module has no usable export.`;
|
|
158
181
|
return new TypeError(`Invalid middleware export in ${sourceFile}. ${detail}\n` +
|
|
159
182
|
`Expected a default export that is a middleware function, or a non-empty ` +
|
|
160
183
|
`array of them:\n\n` +
|
|
@@ -171,7 +194,7 @@ function normalizeMiddlewareExport(middlewareModule, strict = false, sourceFile
|
|
|
171
194
|
: middlewareModule;
|
|
172
195
|
if (Array.isArray(exported)) {
|
|
173
196
|
if (strict && (exported.length === 0 || exported.some((value) => typeof value !== "function"))) {
|
|
174
|
-
throw invalidMiddlewareExport(middlewareModule, sourceFile);
|
|
197
|
+
throw invalidMiddlewareExport(middlewareModule, sourceFile, exported);
|
|
175
198
|
}
|
|
176
199
|
return exported.filter((middleware) => typeof middleware === "function");
|
|
177
200
|
}
|
|
@@ -179,7 +202,7 @@ function normalizeMiddlewareExport(middlewareModule, strict = false, sourceFile
|
|
|
179
202
|
return [exported];
|
|
180
203
|
}
|
|
181
204
|
if (strict) {
|
|
182
|
-
throw invalidMiddlewareExport(middlewareModule, sourceFile);
|
|
205
|
+
throw invalidMiddlewareExport(middlewareModule, sourceFile, exported);
|
|
183
206
|
}
|
|
184
207
|
return [];
|
|
185
208
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr.handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/ssr/ssr.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,aAAa,EACd,MAAM,gBAAgB,CAAC;AAWxB,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,4CAA4C,CAAC;AAOpD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAKzE;
|
|
1
|
+
{"version":3,"file":"ssr.handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/ssr/ssr.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,aAAa,EACd,MAAM,gBAAgB,CAAC;AAWxB,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,4CAA4C,CAAC;AAOpD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAKzE;AAiCD,qBAAa,UAAW,SAAQ,WAAW;IACzC,QAAQ,EAAE,eAAe,CAIvB;IAEF,OAAO,CAAC,UAAU,CAAiB;gBAEvB,UAAU,CAAC,EAAE,cAAc;IAKvC,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA8BjE,OAAO,CAAC,qBAAqB;IAmF7B,OAAO,CAAC,iBAAiB;IAkEzB,OAAO,CAAC,cAAc;YAgBR,cAAc;YA6Bd,sBAAsB;YAgBtB,aAAa;CAU5B"}
|
|
@@ -49,9 +49,11 @@ export function isProductionMode(ctx, _url) {
|
|
|
49
49
|
* opposed to errors thrown by the running application.
|
|
50
50
|
*
|
|
51
51
|
* Module-load failures arrive wrapped in a RUNTIME-category `render-error`,
|
|
52
|
-
* which loses the original category, so they
|
|
53
|
-
*
|
|
54
|
-
*
|
|
52
|
+
* which loses the original category, so they carry a `buildFailure` flag that
|
|
53
|
+
* the module loader sets at the point of failure. Failing to load is not
|
|
54
|
+
* evidence on its own: a module that compiled fine and threw at module scope
|
|
55
|
+
* also fails to load, and that is an application error the project's own error
|
|
56
|
+
* page should present.
|
|
55
57
|
*/
|
|
56
58
|
function isBuildError(error) {
|
|
57
59
|
if (!(error instanceof VeryfrontError))
|
|
@@ -59,7 +61,7 @@ function isBuildError(error) {
|
|
|
59
61
|
if (error.category === "BUILD" || error.category === "MODULE")
|
|
60
62
|
return true;
|
|
61
63
|
const context = error.context;
|
|
62
|
-
return
|
|
64
|
+
return context?.buildFailure === true;
|
|
63
65
|
}
|
|
64
66
|
export class SSRHandler extends BaseHandler {
|
|
65
67
|
metadata = {
|
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
8
|
import type { Skill } from "./types.js";
|
|
9
|
+
/** Maximum number of skills rendered in an agent system prompt. */
|
|
10
|
+
export declare const MAX_SKILL_MANIFEST_PROMPT_ENTRIES = 30;
|
|
9
11
|
/**
|
|
10
12
|
* Build the skill manifest prompt section for an agent's system prompt.
|
|
11
13
|
*
|
|
12
|
-
* Lists
|
|
13
|
-
*
|
|
14
|
+
* Lists up to the prompt entry limit with descriptions and instructions on
|
|
15
|
+
* how to use the skill tools (load_skill, load_skill_reference, execute_skill_script).
|
|
14
16
|
*
|
|
15
17
|
* @param skills - Map of resolved skills for the agent
|
|
16
18
|
* @returns Prompt section string, or empty string if no skills
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-augmentation.d.ts","sourceRoot":"","sources":["../../../src/src/skill/prompt-augmentation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"prompt-augmentation.d.ts","sourceRoot":"","sources":["../../../src/src/skill/prompt-augmentation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,mEAAmE;AACnE,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,CA0C3E"}
|
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
|
+
/** Maximum number of skills rendered in an agent system prompt. */
|
|
9
|
+
export const MAX_SKILL_MANIFEST_PROMPT_ENTRIES = 30;
|
|
8
10
|
/**
|
|
9
11
|
* Build the skill manifest prompt section for an agent's system prompt.
|
|
10
12
|
*
|
|
11
|
-
* Lists
|
|
12
|
-
*
|
|
13
|
+
* Lists up to the prompt entry limit with descriptions and instructions on
|
|
14
|
+
* how to use the skill tools (load_skill, load_skill_reference, execute_skill_script).
|
|
13
15
|
*
|
|
14
16
|
* @param skills - Map of resolved skills for the agent
|
|
15
17
|
* @returns Prompt section string, or empty string if no skills
|
|
@@ -23,8 +25,17 @@ export function buildSkillManifestPrompt(skills) {
|
|
|
23
25
|
"You have access to skills via tool calling. IMPORTANT: You MUST call the load_skill tool (not write it as text) to activate a skill before performing skill-related tasks.",
|
|
24
26
|
"",
|
|
25
27
|
];
|
|
28
|
+
let displayedSkillCount = 0;
|
|
26
29
|
for (const [id, skill] of skills) {
|
|
27
30
|
lines.push(`- **${id}**: ${skill.metadata.description}`);
|
|
31
|
+
displayedSkillCount += 1;
|
|
32
|
+
if (displayedSkillCount === MAX_SKILL_MANIFEST_PROMPT_ENTRIES) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (skills.size > MAX_SKILL_MANIFEST_PROMPT_ENTRIES) {
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push(`${skills.size - MAX_SKILL_MANIFEST_PROMPT_ENTRIES} more skill summaries omitted from this prompt. Call load_skill only with a known skill ID.`);
|
|
28
39
|
}
|
|
29
40
|
lines.push("");
|
|
30
41
|
lines.push("### Skill Tools (call these as tools, never write them as text)");
|