veryfront 0.1.1126 → 0.1.1128
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/templates/manifest.d.ts +1 -0
- package/esm/cli/templates/manifest.js +3 -2
- package/esm/deno.js +1 -1
- package/esm/src/config/environment-config.d.ts +5 -0
- package/esm/src/config/environment-config.d.ts.map +1 -1
- package/esm/src/config/environment-config.js +5 -2
- package/esm/src/html/hydration-script-builder/dev-client-renderer.js +1 -1
- package/esm/src/html/hydration-script-builder/prod-scripts.js +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.js +35 -11
- package/esm/src/html/utils.d.ts.map +1 -1
- package/esm/src/html/utils.js +19 -45
- package/esm/src/index.client.d.ts +6 -21
- package/esm/src/index.client.d.ts.map +1 -1
- package/esm/src/index.client.js +6 -21
- package/esm/src/middleware/builtin/timeout.d.ts +1 -1
- package/esm/src/middleware/builtin/timeout.d.ts.map +1 -1
- package/esm/src/middleware/builtin/timeout.js +3 -4
- package/esm/src/react/runtime/core.d.ts +22 -0
- package/esm/src/react/runtime/core.d.ts.map +1 -1
- package/esm/src/react/runtime/core.js +1 -1
- package/esm/src/rendering/orchestrator/module-collection.d.ts +10 -2
- package/esm/src/rendering/orchestrator/module-collection.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-collection.js +12 -2
- package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/pipeline.js +9 -3
- package/esm/src/rendering/orchestrator/types.d.ts +2 -0
- package/esm/src/rendering/orchestrator/types.d.ts.map +1 -1
- package/esm/src/rendering/renderer.d.ts.map +1 -1
- package/esm/src/rendering/renderer.js +18 -8
- package/esm/src/rendering/utils/stream-utils.d.ts +19 -7
- package/esm/src/rendering/utils/stream-utils.d.ts.map +1 -1
- package/esm/src/rendering/utils/stream-utils.js +77 -12
- package/esm/src/routing/api/context-builder.d.ts +7 -0
- package/esm/src/routing/api/context-builder.d.ts.map +1 -1
- package/esm/src/routing/api/context-builder.js +20 -2
- package/esm/src/routing/api/module-loader/loader.js +23 -0
- package/esm/src/server/handlers/dev/files/esbuild-plugins.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/files/esbuild-plugins.js +22 -0
- package/esm/src/server/handlers/request/module/page-data-endpoint-handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/module/page-data-endpoint-handler.js +40 -4
- package/esm/src/server/handlers/response/not-found.d.ts +0 -1
- package/esm/src/server/handlers/response/not-found.d.ts.map +1 -1
- package/esm/src/server/handlers/response/not-found.js +9 -110
- package/esm/src/server/services/rsc/orchestrators/handler.d.ts +3 -1
- package/esm/src/server/services/rsc/orchestrators/handler.d.ts.map +1 -1
- package/esm/src/server/services/rsc/orchestrators/handler.js +13 -8
- package/esm/src/server/services/rsc/orchestrators/render-handler.d.ts +1 -1
- package/esm/src/server/services/rsc/orchestrators/render-handler.d.ts.map +1 -1
- package/esm/src/server/services/rsc/orchestrators/render-handler.js +2 -2
- package/esm/src/transforms/esm/http-cache.d.ts.map +1 -1
- package/esm/src/transforms/esm/http-cache.js +132 -46
- package/esm/src/transforms/esm/in-flight-manager.d.ts +3 -2
- package/esm/src/transforms/esm/in-flight-manager.d.ts.map +1 -1
- package/esm/src/transforms/esm/in-flight-manager.js +6 -5
- package/esm/src/transforms/esm/transform-cache.d.ts.map +1 -1
- package/esm/src/transforms/esm/transform-cache.js +2 -16
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.js +16 -2
- package/esm/src/utils/singleflight.d.ts +5 -0
- package/esm/src/utils/singleflight.d.ts.map +1 -1
- package/esm/src/utils/singleflight.js +29 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -5
|
@@ -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;AA6DhF,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;AAqCD,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;IAiFnC;;;OAGG;YACW,mBAAmB;IAqHjC,OAAO,CAAC,uBAAuB;IAkCzB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAqU9E,+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;IA6FhC,OAAO,CAAC,kBAAkB;YAQZ,uBAAuB;IAmBrC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;CAStB"}
|
|
@@ -45,7 +45,7 @@ import { determineClientModuleStrategy } from "../rsc/client-module-strategy.js"
|
|
|
45
45
|
// Extracted modules
|
|
46
46
|
import { EMPTY_LAYOUT_RESULT, isDotPath } from "./path-helpers.js";
|
|
47
47
|
import { cachePageCss, CSS_SSR_TIMEOUT_MS, getCachedPageCss, getPageCssCacheKey, } from "./css-cache.js";
|
|
48
|
-
import { collectModulesToLoad, DATA_FETCH_TIMEOUT_MS, hasDataFetchingFunction, MODULE_LOAD_HARD_TIMEOUT_MS, MODULE_LOAD_TIMEOUT_MS, SSR_RENDER_TIMEOUT_MS, } from "./module-collection.js";
|
|
48
|
+
import { collectModulesToLoad, DATA_FETCH_TIMEOUT_MS, hasDataFetchingFunction, MODULE_LOAD_HARD_TIMEOUT_MS, MODULE_LOAD_TIMEOUT_MS, moduleLoadLabel, SSR_RENDER_TIMEOUT_MS, } from "./module-collection.js";
|
|
49
49
|
const renderPageLog = logger.component("render-page");
|
|
50
50
|
const renderPipelineLog = logger.component("render-pipeline");
|
|
51
51
|
const resolvePageDataLog = logger.component("resolve-page-data");
|
|
@@ -147,8 +147,13 @@ export class RenderPipeline {
|
|
|
147
147
|
async loadModulesInParallel(modules, options, timeoutControl) {
|
|
148
148
|
const moduleLoaderConfig = await this.resolveModuleLoaderConfig(options);
|
|
149
149
|
if (timeoutControl) {
|
|
150
|
+
const completedMilestones = new Set();
|
|
150
151
|
moduleLoaderConfig.signal = timeoutControl.signal;
|
|
151
152
|
moduleLoaderConfig.onProgress = ({ phase, filePath }) => {
|
|
153
|
+
const milestone = `${phase}:${filePath ?? ""}`;
|
|
154
|
+
if (completedMilestones.has(milestone))
|
|
155
|
+
return;
|
|
156
|
+
completedMilestones.add(milestone);
|
|
152
157
|
const fileName = filePath?.split("/").pop();
|
|
153
158
|
timeoutControl.mark(fileName ? `${phase}:${fileName}` : phase);
|
|
154
159
|
};
|
|
@@ -245,8 +250,9 @@ export class RenderPipeline {
|
|
|
245
250
|
}
|
|
246
251
|
const loadedModules = await profilePhase("render.load_modules", () => withSpan(SpanNames.RENDER_LOAD_MODULES, () => withProgressTimeoutThrow((control) => this.loadModulesInParallel(modulesToLoad, options, control), {
|
|
247
252
|
idleTimeoutMs: MODULE_LOAD_TIMEOUT_MS,
|
|
248
|
-
hardTimeoutMs: MODULE_LOAD_HARD_TIMEOUT_MS,
|
|
249
|
-
label:
|
|
253
|
+
hardTimeoutMs: options.abortSignal ? undefined : MODULE_LOAD_HARD_TIMEOUT_MS,
|
|
254
|
+
label: moduleLoadLabel(slug, options.url?.pathname ?? ""),
|
|
255
|
+
signal: options.abortSignal,
|
|
250
256
|
}), { "render.module_count": modulesToLoad.length }));
|
|
251
257
|
const dataJobs = loadedModules.filter((m) => options?.staticDataOnly
|
|
252
258
|
? typeof m.mod.getStaticData === "function"
|
|
@@ -30,6 +30,8 @@ export interface RenderOptions {
|
|
|
30
30
|
props?: Record<string, unknown>;
|
|
31
31
|
delivery?: "string" | "stream";
|
|
32
32
|
request?: Request;
|
|
33
|
+
/** Internal signal for the render owner's total deadline. */
|
|
34
|
+
abortSignal?: AbortSignal;
|
|
33
35
|
url?: URL;
|
|
34
36
|
/** Restrict data fetching to static hooks, even when a request context exists. */
|
|
35
37
|
staticDataOnly?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer.ts"],"names":[],"mappings":"AA8CA,OAAO,EACL,mBAAmB,EACnB,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,iCAAiC,CAAC;AAgBzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA4CxD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,oBAAoB;IACpB,KAAK,CAAC,EAAE,wBAAwB,CAAC;CAClC;AA4FD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,oBAAoB,CAAgC;IAC5D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,qBAAqB,CAA8B;IAE3D;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,yBAAyB,CAAoC;gBAEzD,OAAO,GAAE,eAAoB;IAInC,UAAU,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBhE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -49,7 +49,7 @@ import { SSROrchestrator } from "./orchestrator/ssr-orchestrator.js";
|
|
|
49
49
|
import { RenderPipeline } from "./orchestrator/pipeline.js";
|
|
50
50
|
import { createLayoutComponentCache } from "./layouts/utils/component-loader.js";
|
|
51
51
|
import { TimeoutError, withTimeoutThrow } from "./utils/stream-utils.js";
|
|
52
|
-
import { Singleflight } from "../utils/singleflight.js";
|
|
52
|
+
import { Singleflight, waitForSharedPromise } from "../utils/singleflight.js";
|
|
53
53
|
import { acquireProjectSlot, projectRenderCounts, releaseProjectSlot, RENDER_ACQUIRE_TIMEOUT_MS, RENDER_PER_PROJECT_LIMIT, renderSemaphore, } from "./renderer-concurrency.js";
|
|
54
54
|
const logger = rendererLogger.component("renderer");
|
|
55
55
|
/**
|
|
@@ -219,7 +219,7 @@ export class Renderer {
|
|
|
219
219
|
}
|
|
220
220
|
return cacheResult.cachedResult;
|
|
221
221
|
}
|
|
222
|
-
const result = await this.doRenderPage(slug, effectiveCtx, effectiveOptions, startTime, cacheKey);
|
|
222
|
+
const result = await this.doRenderPage(slug, effectiveCtx, effectiveOptions, startTime, cacheKey, effectiveOptions.abortSignal ?? effectiveOptions.request?.signal);
|
|
223
223
|
this.scheduleProductionRenderPrewarm(slug, effectiveCtx, effectiveOptions, cacheKey);
|
|
224
224
|
return result;
|
|
225
225
|
}, {
|
|
@@ -369,7 +369,7 @@ export class Renderer {
|
|
|
369
369
|
});
|
|
370
370
|
this.rememberProductionPrewarm(refreshKey, promise);
|
|
371
371
|
setTimeout(() => {
|
|
372
|
-
void this.doRenderPage(slug, ctx, refreshOptions, performance.now(), cacheKey)
|
|
372
|
+
void this.doRenderPage(slug, ctx, refreshOptions, performance.now(), cacheKey, undefined)
|
|
373
373
|
.then(() => {
|
|
374
374
|
this.scheduleProductionRenderPrewarm(slug, ctx, refreshOptions, cacheKey);
|
|
375
375
|
resolvePromise();
|
|
@@ -429,13 +429,13 @@ export class Renderer {
|
|
|
429
429
|
routeCount: slugs.length,
|
|
430
430
|
});
|
|
431
431
|
}
|
|
432
|
-
async doRenderPage(slug, ctx, options, startTime, cacheKey) {
|
|
432
|
+
async doRenderPage(slug, ctx, options, startTime, cacheKey, callerSignal) {
|
|
433
433
|
const effectiveKey = cacheKey ?? dntShim.crypto.randomUUID();
|
|
434
434
|
const flightKey = this.getSingleflightKey(effectiveKey, ctx, options?.colorScheme);
|
|
435
435
|
const isFollower = cacheKey !== null ? this.renderFlight.has(flightKey) : false;
|
|
436
436
|
const runRender = async () => {
|
|
437
437
|
try {
|
|
438
|
-
return await this.runRenderWithCapacity(slug, ctx, options, startTime, cacheKey);
|
|
438
|
+
return await this.runRenderWithCapacity(slug, ctx, options, startTime, cacheKey, callerSignal);
|
|
439
439
|
}
|
|
440
440
|
catch (error) {
|
|
441
441
|
if (error instanceof TimeoutError) {
|
|
@@ -449,7 +449,7 @@ export class Renderer {
|
|
|
449
449
|
}
|
|
450
450
|
};
|
|
451
451
|
const cachedData = cacheKey !== null
|
|
452
|
-
? await this.renderFlight.do(flightKey, runRender)
|
|
452
|
+
? await waitForSharedPromise(this.renderFlight.do(flightKey, runRender), callerSignal)
|
|
453
453
|
: await runRender();
|
|
454
454
|
if (isFollower) {
|
|
455
455
|
logger.debug("Render deduplicated (follower)", {
|
|
@@ -468,7 +468,7 @@ export class Renderer {
|
|
|
468
468
|
stream: null,
|
|
469
469
|
};
|
|
470
470
|
}
|
|
471
|
-
async runRenderWithCapacity(slug, ctx, options, startTime, cacheKey) {
|
|
471
|
+
async runRenderWithCapacity(slug, ctx, options, startTime, cacheKey, callerSignal) {
|
|
472
472
|
if (!(await acquireProjectSlot(ctx.projectId))) {
|
|
473
473
|
const activeCount = projectRenderCounts.get(ctx.projectId) ?? 0;
|
|
474
474
|
logger.error("Per-project render limit reached", {
|
|
@@ -503,8 +503,14 @@ export class Renderer {
|
|
|
503
503
|
}
|
|
504
504
|
try {
|
|
505
505
|
const services = this.createServicesForContext(ctx, options?.colorScheme);
|
|
506
|
+
const renderAbortController = new AbortController();
|
|
507
|
+
const request = cacheKey !== null && options?.request
|
|
508
|
+
? new Request(options.request, { signal: renderAbortController.signal })
|
|
509
|
+
: options?.request;
|
|
506
510
|
const result = await withTimeoutThrow(services.pipeline.renderPage(slug, {
|
|
507
511
|
...options,
|
|
512
|
+
request,
|
|
513
|
+
abortSignal: renderAbortController.signal,
|
|
508
514
|
delivery: "string",
|
|
509
515
|
projectId: ctx.projectId,
|
|
510
516
|
projectSlug: ctx.projectSlug,
|
|
@@ -512,7 +518,11 @@ export class Renderer {
|
|
|
512
518
|
contentSourceId: ctx.contentSourceId,
|
|
513
519
|
skipCacheCheck: true,
|
|
514
520
|
skipCachePersist: true,
|
|
515
|
-
}), RENDER_PIPELINE_TIMEOUT_MS, `Render pipeline for ${ctx.projectId}:${slug}
|
|
521
|
+
}), RENDER_PIPELINE_TIMEOUT_MS, `Render pipeline for ${ctx.projectId}:${slug}`, {
|
|
522
|
+
signal: cacheKey === null ? callerSignal : undefined,
|
|
523
|
+
onAbort: (reason) => renderAbortController.abort(reason),
|
|
524
|
+
onTimeout: (error) => renderAbortController.abort(error),
|
|
525
|
+
});
|
|
516
526
|
if (cacheKey !== null) {
|
|
517
527
|
await this.cache.persistResult(result, slug, ctx, options?.colorScheme, cacheKey);
|
|
518
528
|
}
|
|
@@ -7,7 +7,7 @@ export declare class TimeoutError extends Error {
|
|
|
7
7
|
});
|
|
8
8
|
}
|
|
9
9
|
export interface ProgressTimeoutControl {
|
|
10
|
-
/** Aborted when
|
|
10
|
+
/** Aborted when a local deadline or the caller-owned signal is reached. */
|
|
11
11
|
signal: AbortSignal;
|
|
12
12
|
/** Reset the idle deadline after a concrete unit of work completes. */
|
|
13
13
|
mark(label: string): void;
|
|
@@ -15,16 +15,28 @@ export interface ProgressTimeoutControl {
|
|
|
15
15
|
export interface ProgressTimeoutOptions {
|
|
16
16
|
label: string;
|
|
17
17
|
idleTimeoutMs: number;
|
|
18
|
-
|
|
18
|
+
/** Optional local hard cap. Omit when the caller already owns the total deadline. */
|
|
19
|
+
hardTimeoutMs?: number;
|
|
20
|
+
/** Optional deadline owned by the operation's caller. */
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export interface TimeoutOptions {
|
|
24
|
+
/** Optional caller-owned abort signal that should reject the waiter immediately. */
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
/** Called when the caller-owned signal aborts; failures do not replace the abort reason. */
|
|
27
|
+
onAbort?: (reason: unknown) => void;
|
|
28
|
+
/** Called when the local timeout fires; failures do not replace the timeout error. */
|
|
29
|
+
onTimeout?: (error: TimeoutError) => void;
|
|
19
30
|
}
|
|
20
31
|
export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T | undefined>;
|
|
21
|
-
export declare function withTimeoutThrow<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T>;
|
|
32
|
+
export declare function withTimeoutThrow<T>(promise: Promise<T>, timeoutMs: number, label: string, options?: TimeoutOptions): Promise<T>;
|
|
22
33
|
/**
|
|
23
|
-
* Run an operation with a resettable idle deadline and
|
|
34
|
+
* Run an operation with a resettable idle deadline and an optional hard cap.
|
|
24
35
|
*
|
|
25
|
-
* Callers must only call `mark` after meaningful progress.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
36
|
+
* Callers must only call `mark` after meaningful progress. Use `hardTimeoutMs`
|
|
37
|
+
* when this helper owns the total deadline. Omit it when an outer operation
|
|
38
|
+
* already enforces that deadline. The supplied signal lets cooperative work
|
|
39
|
+
* stop after either configured deadline.
|
|
28
40
|
*/
|
|
29
41
|
export declare function withProgressTimeoutThrow<T>(operation: (control: ProgressTimeoutControl) => Promise<T>, options: ProgressTimeoutOptions): Promise<T>;
|
|
30
42
|
export declare class StreamTimeoutError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/utils/stream-utils.ts"],"names":[],"mappings":"AAGA,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAG7B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAO9D;AAED,MAAM,WAAW,sBAAsB;IACrC,
|
|
1
|
+
{"version":3,"file":"stream-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/utils/stream-utils.ts"],"names":[],"mappings":"AAGA,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAG7B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;CAO9D;AAED,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,MAAM,EAAE,WAAW,CAAC;IACpB,uEAAuE;IACvE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,sFAAsF;IACtF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAsB,WAAW,CAAC,CAAC,EACjC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAkBxB;AAED,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,CAAC,CAAC,CAuDZ;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,SAAS,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1D,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,CAAC,CAAC,CAoFZ;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEpB,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;CAKtD;AAcD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,SAAS,GAAE,MAAuB,GACjC,OAAO,CAAC,MAAM,CAAC,CA+CjB"}
|
|
@@ -29,33 +29,77 @@ export async function withTimeout(promise, timeoutMs, label) {
|
|
|
29
29
|
clearTimeout(timeoutId);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
export async function withTimeoutThrow(promise, timeoutMs, label) {
|
|
32
|
+
export async function withTimeoutThrow(promise, timeoutMs, label, options) {
|
|
33
33
|
let timeoutId;
|
|
34
|
+
let removeAbortListener;
|
|
34
35
|
const timeoutPromise = new Promise((_, reject) => {
|
|
35
36
|
timeoutId = setTimeout(() => {
|
|
36
37
|
logger.error("TIMEOUT_HARD operation timed out (throwing)", { label, timeoutMs });
|
|
37
|
-
|
|
38
|
+
const error = new TimeoutError(label, timeoutMs);
|
|
39
|
+
try {
|
|
40
|
+
options?.onTimeout?.(error);
|
|
41
|
+
}
|
|
42
|
+
catch (callbackError) {
|
|
43
|
+
logger.error("TIMEOUT_HARD onTimeout callback failed", {
|
|
44
|
+
label,
|
|
45
|
+
error: callbackError instanceof Error ? callbackError.message : String(callbackError),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
reject(error);
|
|
50
|
+
}
|
|
38
51
|
}, timeoutMs);
|
|
39
52
|
});
|
|
53
|
+
const abortSignal = options?.signal;
|
|
54
|
+
const abortPromise = abortSignal
|
|
55
|
+
? new Promise((_, reject) => {
|
|
56
|
+
const abort = () => {
|
|
57
|
+
const reason = abortSignal.reason ??
|
|
58
|
+
new DOMException("The operation was aborted", "AbortError");
|
|
59
|
+
try {
|
|
60
|
+
options?.onAbort?.(reason);
|
|
61
|
+
}
|
|
62
|
+
catch (callbackError) {
|
|
63
|
+
logger.error("TIMEOUT_HARD onAbort callback failed", {
|
|
64
|
+
label,
|
|
65
|
+
error: callbackError instanceof Error ? callbackError.message : String(callbackError),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
reject(reason);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
if (abortSignal.aborted) {
|
|
73
|
+
abort();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
abortSignal.addEventListener("abort", abort, { once: true });
|
|
77
|
+
removeAbortListener = () => abortSignal.removeEventListener("abort", abort);
|
|
78
|
+
})
|
|
79
|
+
: undefined;
|
|
40
80
|
try {
|
|
41
|
-
return await Promise.race([promise, timeoutPromise]);
|
|
81
|
+
return await Promise.race(abortPromise ? [promise, timeoutPromise, abortPromise] : [promise, timeoutPromise]);
|
|
42
82
|
}
|
|
43
83
|
finally {
|
|
44
84
|
if (timeoutId)
|
|
45
85
|
clearTimeout(timeoutId);
|
|
86
|
+
removeAbortListener?.();
|
|
46
87
|
}
|
|
47
88
|
}
|
|
48
89
|
/**
|
|
49
|
-
* Run an operation with a resettable idle deadline and
|
|
90
|
+
* Run an operation with a resettable idle deadline and an optional hard cap.
|
|
50
91
|
*
|
|
51
|
-
* Callers must only call `mark` after meaningful progress.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
92
|
+
* Callers must only call `mark` after meaningful progress. Use `hardTimeoutMs`
|
|
93
|
+
* when this helper owns the total deadline. Omit it when an outer operation
|
|
94
|
+
* already enforces that deadline. The supplied signal lets cooperative work
|
|
95
|
+
* stop after either configured deadline.
|
|
54
96
|
*/
|
|
55
97
|
export async function withProgressTimeoutThrow(operation, options) {
|
|
56
|
-
const { label, idleTimeoutMs, hardTimeoutMs } = options;
|
|
57
|
-
if (idleTimeoutMs <= 0 ||
|
|
58
|
-
|
|
98
|
+
const { label, idleTimeoutMs, hardTimeoutMs, signal: parentSignal } = options;
|
|
99
|
+
if (idleTimeoutMs <= 0 ||
|
|
100
|
+
(hardTimeoutMs !== undefined &&
|
|
101
|
+
(hardTimeoutMs <= 0 || hardTimeoutMs < idleTimeoutMs))) {
|
|
102
|
+
throw new RangeError("Progress timeout requires idleTimeoutMs > 0 and, when set, hardTimeoutMs >= idleTimeoutMs");
|
|
59
103
|
}
|
|
60
104
|
const controller = new AbortController();
|
|
61
105
|
let idleTimeoutId;
|
|
@@ -95,9 +139,29 @@ export async function withProgressTimeoutThrow(operation, options) {
|
|
|
95
139
|
scheduleIdleTimeout();
|
|
96
140
|
},
|
|
97
141
|
};
|
|
98
|
-
|
|
99
|
-
|
|
142
|
+
const abortFromParent = () => {
|
|
143
|
+
if (!active || !parentSignal)
|
|
144
|
+
return;
|
|
145
|
+
active = false;
|
|
146
|
+
const reason = parentSignal.reason ??
|
|
147
|
+
new DOMException("The operation was aborted", "AbortError");
|
|
148
|
+
controller.abort(reason);
|
|
149
|
+
rejectTimeout(reason);
|
|
150
|
+
};
|
|
151
|
+
if (parentSignal?.aborted) {
|
|
152
|
+
abortFromParent();
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
156
|
+
}
|
|
157
|
+
if (active)
|
|
158
|
+
scheduleIdleTimeout();
|
|
159
|
+
const hardTimeoutId = !active || hardTimeoutMs === undefined
|
|
160
|
+
? undefined
|
|
161
|
+
: setTimeout(() => fail("hard", hardTimeoutMs), hardTimeoutMs);
|
|
100
162
|
try {
|
|
163
|
+
if (!active)
|
|
164
|
+
return await timeoutPromise;
|
|
101
165
|
return await Promise.race([
|
|
102
166
|
Promise.resolve().then(() => operation(control)),
|
|
103
167
|
timeoutPromise,
|
|
@@ -109,6 +173,7 @@ export async function withProgressTimeoutThrow(operation, options) {
|
|
|
109
173
|
clearTimeout(idleTimeoutId);
|
|
110
174
|
if (hardTimeoutId)
|
|
111
175
|
clearTimeout(hardTimeoutId);
|
|
176
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
112
177
|
}
|
|
113
178
|
}
|
|
114
179
|
export class StreamTimeoutError extends Error {
|
|
@@ -35,6 +35,13 @@ export interface APIContext {
|
|
|
35
35
|
* behave identically. Handlers must not care which one ran them.
|
|
36
36
|
*/
|
|
37
37
|
export declare function createJsonHelper(_request: Request): APIContext["json"];
|
|
38
|
+
/**
|
|
39
|
+
* Build the `ctx.text` response helper.
|
|
40
|
+
*
|
|
41
|
+
* Exported for the isolation Worker so both execution modes share Fetch's
|
|
42
|
+
* null-body status handling instead of maintaining separate implementations.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createTextHelper(): APIContext["text"];
|
|
38
45
|
/**
|
|
39
46
|
* Build the `ctx.body` request-body reader.
|
|
40
47
|
*
|
|
@@ -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;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;
|
|
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;AA0BD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAGtE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAAC,MAAM,CAAC,CAErD;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,CAmBZ;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"}
|
|
@@ -2,8 +2,17 @@ import { parseCookies } from "../../utils/cookie-utils.js";
|
|
|
2
2
|
import { INVALID_ARGUMENT } from "../../errors/index.js";
|
|
3
3
|
import { flattenRouteParams } from "../flatten-route-params.js";
|
|
4
4
|
export { parseCookies };
|
|
5
|
+
/**
|
|
6
|
+
* Statuses that the Fetch spec forbids from carrying a body. Constructing
|
|
7
|
+
* `new Response(body, { status })` with a non-null `body` (an empty string
|
|
8
|
+
* still counts) throws `Response with null body status cannot have body`, so
|
|
9
|
+
* the helpers below must send `null` for these.
|
|
10
|
+
*/
|
|
11
|
+
const NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);
|
|
5
12
|
function createResponse(body, contentType, init) {
|
|
6
|
-
|
|
13
|
+
const status = init?.status;
|
|
14
|
+
const hasNullBodyStatus = status !== undefined && NULL_BODY_STATUSES.has(status);
|
|
15
|
+
return new Response(hasNullBodyStatus ? null : body, {
|
|
7
16
|
...init,
|
|
8
17
|
headers: {
|
|
9
18
|
"Content-Type": contentType,
|
|
@@ -20,6 +29,15 @@ function createResponse(body, contentType, init) {
|
|
|
20
29
|
export function createJsonHelper(_request) {
|
|
21
30
|
return (data, init) => createResponse(JSON.stringify(data), "application/json", init);
|
|
22
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Build the `ctx.text` response helper.
|
|
34
|
+
*
|
|
35
|
+
* Exported for the isolation Worker so both execution modes share Fetch's
|
|
36
|
+
* null-body status handling instead of maintaining separate implementations.
|
|
37
|
+
*/
|
|
38
|
+
export function createTextHelper() {
|
|
39
|
+
return (data, init) => createResponse(data, "text/plain", init);
|
|
40
|
+
}
|
|
23
41
|
/**
|
|
24
42
|
* Build the `ctx.body` request-body reader.
|
|
25
43
|
*
|
|
@@ -52,7 +70,7 @@ export function createContext(request, match, fs) {
|
|
|
52
70
|
const url = new URL(request.url);
|
|
53
71
|
const json = createJsonHelper(request);
|
|
54
72
|
const body = createBodyReader(request);
|
|
55
|
-
const text = (
|
|
73
|
+
const text = createTextHelper();
|
|
56
74
|
return {
|
|
57
75
|
request,
|
|
58
76
|
req: request,
|
|
@@ -177,6 +177,28 @@ function createNamespaceOnLoadHandler(options) {
|
|
|
177
177
|
}
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
|
+
/** Resolves the framework's built-in @/ project alias through the runtime adapter. */
|
|
181
|
+
function createProjectAliasPlugin(adapter, projectDir) {
|
|
182
|
+
const projectRoot = pathHelper.resolve(projectDir);
|
|
183
|
+
return {
|
|
184
|
+
name: "vf-project-alias",
|
|
185
|
+
setup(build) {
|
|
186
|
+
build.onResolve({ filter: /^@\// }, (args) => {
|
|
187
|
+
const absolutePath = pathHelper.resolve(projectRoot, args.path.slice(2));
|
|
188
|
+
if (!isWithinDirectory(projectRoot, absolutePath)) {
|
|
189
|
+
logger.error(`[API] Project alias escapes project: ${args.path} -> ${absolutePath}`);
|
|
190
|
+
return { errors: [{ text: `Project alias escapes project: ${args.path}` }] };
|
|
191
|
+
}
|
|
192
|
+
return { path: absolutePath, namespace: "vf-project-alias" };
|
|
193
|
+
});
|
|
194
|
+
build.onLoad({ filter: /.*/, namespace: "vf-project-alias" }, createNamespaceOnLoadHandler({
|
|
195
|
+
adapter,
|
|
196
|
+
projectDir,
|
|
197
|
+
errorLabel: "via project alias",
|
|
198
|
+
}));
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
180
202
|
/** Resolves relative imports through the adapter's virtual FS for remote projects. */
|
|
181
203
|
function createAdapterResolvePlugin(adapter, projectDir) {
|
|
182
204
|
return {
|
|
@@ -342,6 +364,7 @@ function loadAndTranspileModule(modulePath, projectDir, adapter, fs, config) {
|
|
|
342
364
|
},
|
|
343
365
|
plugins: [
|
|
344
366
|
createImportMapPlugin(projectDir, adapter, config),
|
|
367
|
+
createProjectAliasPlugin(adapter, projectDir),
|
|
345
368
|
createAdapterResolvePlugin(adapter, projectDir),
|
|
346
369
|
createHTTPPlugin({ allowedHosts, projectDir }),
|
|
347
370
|
createProjectBoundaryPlugin(await resolveProjectRoots(projectDir)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esbuild-plugins.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/dev/files/esbuild-plugins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA6B,MAAM,EAAe,MAAM,yCAAyC,CAAC;AAG9G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAS5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,sCAAsC,CAAC;AAgC9C,MAAM,WAAW,uBAAuB;IACtC,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AASD,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE5E,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,uBAAuB,CAAC,CAmClC;AAoBD,gFAAgF;AAChF,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,uBAA4B,GACpC,MAAM,CA2KR;AAKD,UAAU,yBAAyB;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"esbuild-plugins.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/dev/files/esbuild-plugins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA6B,MAAM,EAAe,MAAM,yCAAyC,CAAC;AAG9G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAS5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,sCAAsC,CAAC;AAgC9C,MAAM,WAAW,uBAAuB;IACtC,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AASD,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE5E,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,uBAAuB,CAAC,CAmClC;AAoBD,gFAAgF;AAChF,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,uBAA4B,GACpC,MAAM,CA2KR;AAKD,UAAU,yBAAyB;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAuED,kFAAkF;AAClF,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,yBAAyB,GAAG,OAAe,GACnD,MAAM,CAqFR;AAED,wBAAgB,wBAAwB,IAAI,MAAM,CAUjD"}
|
|
@@ -236,6 +236,13 @@ function isBareImport(path) {
|
|
|
236
236
|
!path.startsWith("http://") &&
|
|
237
237
|
!path.startsWith("https://"));
|
|
238
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* A Node built-in module specifier (`node:crypto`, `node:fs`, …). These are
|
|
241
|
+
* server-only and must never be rewritten to an esm.sh URL for a browser bundle.
|
|
242
|
+
*/
|
|
243
|
+
function isNodeBuiltinSpecifier(path) {
|
|
244
|
+
return path === "node" || path.startsWith("node:");
|
|
245
|
+
}
|
|
239
246
|
function toEsmUrl(path) {
|
|
240
247
|
return ESM_PACKAGE_MAP[path] ?? `https://esm.sh/${path}`;
|
|
241
248
|
}
|
|
@@ -292,6 +299,21 @@ export function createBareExternalPlugin(options = false) {
|
|
|
292
299
|
return undefined;
|
|
293
300
|
if (args.kind !== "import-statement" && args.kind !== "dynamic-import")
|
|
294
301
|
return undefined;
|
|
302
|
+
// Fail closed on Node built-ins. This plugin only runs for browser
|
|
303
|
+
// bundles (platform: "browser"), where a server-only `node:*` import can
|
|
304
|
+
// never work: rewriting it to an esm.sh URL silently ships a module that
|
|
305
|
+
// 404s on esm.sh and throws (e.g. `createHash is not a function`) at
|
|
306
|
+
// hydration. Surface a clear build error instead of a broken rewrite.
|
|
307
|
+
if (isNodeBuiltinSpecifier(args.path)) {
|
|
308
|
+
return {
|
|
309
|
+
errors: [{
|
|
310
|
+
text: `Cannot bundle server-only import "${args.path}" for the browser. ` +
|
|
311
|
+
`Node built-in modules are not available on the client. Move it into a ` +
|
|
312
|
+
`server component, an API route, or middleware — or gate the code behind a ` +
|
|
313
|
+
`"use client" boundary that does not import it.`,
|
|
314
|
+
}],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
295
317
|
// Keep import-map-resolved specifiers as bare externals — the browser's
|
|
296
318
|
// <script type="importmap"> resolves them to the correct CDN URL.
|
|
297
319
|
if (importMapOwnsSpecifier(args.path, importMapImports)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-data-endpoint-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/module/page-data-endpoint-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"page-data-endpoint-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/module/page-data-endpoint-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAwGhE,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,cAAc,EACnB,qBAAqB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,eAAe,EAC/D,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,aAAa,EAC9C,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAC1C,OAAO,CAAC,aAAa,CAAC,CAkIxB"}
|
|
@@ -6,7 +6,7 @@ import { withSpan } from "../../../../observability/tracing/otlp-setup.js";
|
|
|
6
6
|
import { markRequestProfilePhase } from "../../../../observability/index.js";
|
|
7
7
|
import { HTTP_GATEWAY_TIMEOUT } from "../../../../utils/constants/http.js";
|
|
8
8
|
import { serverLogger } from "../../../../utils/index.js";
|
|
9
|
-
import { Singleflight } from "../../../../utils/singleflight.js";
|
|
9
|
+
import { Singleflight, waitForSharedPromise } from "../../../../utils/singleflight.js";
|
|
10
10
|
import { requestHasCacheSensitiveState } from "../../../../cache/request-cacheability.js";
|
|
11
11
|
import { sanitizeQueryParamsForCacheKey, } from "../../../../cache/keys.js";
|
|
12
12
|
import { getEnv } from "../../../../platform/compat/process.js";
|
|
@@ -47,6 +47,19 @@ function getPageDataCachePolicy(ctx) {
|
|
|
47
47
|
function isPageDataCacheEnabled() {
|
|
48
48
|
return PAGE_DATA_CACHE_MAX_ENTRIES > 0;
|
|
49
49
|
}
|
|
50
|
+
async function resolvePageDataWithinDeadline(renderer, slug, request, url, callerSignal) {
|
|
51
|
+
const controller = new AbortController();
|
|
52
|
+
const workRequest = callerSignal ? request : new Request(request, { signal: controller.signal });
|
|
53
|
+
return await withTimeoutThrow(renderer.resolvePageData(slug, {
|
|
54
|
+
request: workRequest,
|
|
55
|
+
url,
|
|
56
|
+
abortSignal: controller.signal,
|
|
57
|
+
}), PAGE_DATA_TIMEOUT_MS, `resolvePageData for ${slug}`, {
|
|
58
|
+
signal: callerSignal,
|
|
59
|
+
onAbort: (reason) => controller.abort(reason),
|
|
60
|
+
onTimeout: (error) => controller.abort(error),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
50
63
|
export function __clearPageDataEndpointCacheForTests() {
|
|
51
64
|
pageDataCache.clear();
|
|
52
65
|
}
|
|
@@ -66,8 +79,8 @@ export function handlePageDataEndpoint(req, pathname, ctx, createResponseBuilder
|
|
|
66
79
|
const cacheKey = canUsePageDataCache ? buildPageDataCacheKey(ctx, slug, url) : null;
|
|
67
80
|
const cachePolicy = cacheKey ? getPageDataCachePolicy(ctx) : null;
|
|
68
81
|
const payload = cacheKey
|
|
69
|
-
? await resolveCachedPageData(cacheKey, () =>
|
|
70
|
-
: await resolveUncachedPageData(() =>
|
|
82
|
+
? await waitForSharedPromise(resolveCachedPageData(cacheKey, () => resolvePageDataWithinDeadline(renderer, slug, req, url, undefined), cachePolicy), req.signal)
|
|
83
|
+
: await resolveUncachedPageData(() => resolvePageDataWithinDeadline(renderer, slug, req, url, req.signal));
|
|
71
84
|
const cacheStrategy = cacheKey
|
|
72
85
|
? {
|
|
73
86
|
maxAge: cachePolicy.maxAgeSeconds,
|
|
@@ -226,16 +239,39 @@ function refreshStalePageData(cacheKey, resolve, cachePolicy) {
|
|
|
226
239
|
}
|
|
227
240
|
});
|
|
228
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Only http(s) and root-relative destinations may be encoded for the client to
|
|
244
|
+
* follow. The client follows the destination with `window.location.href`, which
|
|
245
|
+
* would EXECUTE a `javascript:`/`data:` URL — unlike the full-page 302 path where
|
|
246
|
+
* the browser ignores such a Location. Protocol-relative `//host` is rejected too
|
|
247
|
+
* (it is easy to smuggle past a naive "starts with /" check). Blocked
|
|
248
|
+
* destinations fall through to normal error handling instead of being followed.
|
|
249
|
+
*/
|
|
250
|
+
function isFollowableRedirect(destination) {
|
|
251
|
+
if (destination.startsWith("/")) {
|
|
252
|
+
const baseOrigin = "https://veryfront.local";
|
|
253
|
+
try {
|
|
254
|
+
return new URL(destination, baseOrigin).origin === baseOrigin;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return /^https?:\/\//i.test(destination);
|
|
261
|
+
}
|
|
229
262
|
/**
|
|
230
263
|
* A redirect() from getServerData is thrown up the pipeline as a VeryfrontError
|
|
231
264
|
* whose `context.redirect` holds the destination (mirrors extractRedirectLocation
|
|
232
|
-
* in the SSR service). Returns null for any other error
|
|
265
|
+
* in the SSR service). Returns null for any other error, or for a redirect whose
|
|
266
|
+
* destination is not safe to hand to the client to follow.
|
|
233
267
|
*/
|
|
234
268
|
function extractRedirectFromError(error) {
|
|
235
269
|
const context = error?.context;
|
|
236
270
|
const redirect = context?.redirect;
|
|
237
271
|
if (!redirect || typeof redirect.destination !== "string")
|
|
238
272
|
return null;
|
|
273
|
+
if (!isFollowableRedirect(redirect.destination))
|
|
274
|
+
return null;
|
|
239
275
|
return { destination: redirect.destination, permanent: redirect.permanent === true };
|
|
240
276
|
}
|
|
241
277
|
function buildPageDataCacheKey(ctx, slug, url) {
|
|
@@ -3,6 +3,5 @@ import type { HandlerContext, HandlerMetadata, HandlerResult } from "../types.js
|
|
|
3
3
|
export declare class NotFoundHandler extends BaseHandler {
|
|
4
4
|
metadata: HandlerMetadata;
|
|
5
5
|
handle(req: Request, ctx: HandlerContext): Promise<HandlerResult>;
|
|
6
|
-
private generate404Html;
|
|
7
6
|
}
|
|
8
7
|
//# sourceMappingURL=not-found.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"not-found.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/response/not-found.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"not-found.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/response/not-found.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAUnG,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,EAAE,eAAe,CAIvB;IAEF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAmClE"}
|