veryfront 0.1.1145 → 0.1.1147

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/esm/deno.d.ts +1 -0
  2. package/esm/deno.js +2 -1
  3. package/esm/src/discovery/import-rewriter.d.ts +1 -1
  4. package/esm/src/discovery/import-rewriter.d.ts.map +1 -1
  5. package/esm/src/discovery/import-rewriter.js +6 -0
  6. package/esm/src/discovery/runtime-modules-bootstrap.js +2 -0
  7. package/esm/src/modules/react-loader/ssr-module-loader/concurrency/semaphore.d.ts +3 -1
  8. package/esm/src/modules/react-loader/ssr-module-loader/concurrency/semaphore.d.ts.map +1 -1
  9. package/esm/src/modules/react-loader/ssr-module-loader/concurrency/semaphore.js +59 -20
  10. package/esm/src/rendering/renderer-concurrency.d.ts +16 -4
  11. package/esm/src/rendering/renderer-concurrency.d.ts.map +1 -1
  12. package/esm/src/rendering/renderer-concurrency.js +103 -11
  13. package/esm/src/rendering/renderer.d.ts +4 -0
  14. package/esm/src/rendering/renderer.d.ts.map +1 -1
  15. package/esm/src/rendering/renderer.js +123 -35
  16. package/esm/src/rendering/ssr-globals/dom-stubs.d.ts +53 -4
  17. package/esm/src/rendering/ssr-globals/dom-stubs.d.ts.map +1 -1
  18. package/esm/src/rendering/ssr-globals/dom-stubs.js +61 -2
  19. package/esm/src/rendering/ssr-globals/index.d.ts +1 -1
  20. package/esm/src/rendering/ssr-globals/index.d.ts.map +1 -1
  21. package/esm/src/rendering/ssr-globals/index.js +25 -8
  22. package/esm/src/routing/api/module-loader/loader.d.ts +4 -0
  23. package/esm/src/routing/api/module-loader/loader.d.ts.map +1 -1
  24. package/esm/src/routing/api/module-loader/loader.js +35 -10
  25. package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
  26. package/esm/src/server/runtime-handler/index.js +8 -2
  27. package/esm/src/server/runtime-handler/request-utils.d.ts +2 -0
  28. package/esm/src/server/runtime-handler/request-utils.d.ts.map +1 -1
  29. package/esm/src/server/runtime-handler/request-utils.js +5 -0
  30. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  31. package/esm/src/server/services/rendering/ssr.service.js +11 -0
  32. package/esm/src/utils/version-constant.d.ts +1 -1
  33. package/esm/src/utils/version-constant.js +1 -1
  34. package/package.json +5 -5
package/esm/deno.d.ts CHANGED
@@ -285,6 +285,7 @@ declare namespace _default {
285
285
  "#std/testing.ts": string;
286
286
  "#std/testing/bdd": string;
287
287
  "#std/testing/bdd.ts": string;
288
+ "#std/testing/mock": string;
288
289
  "#std/testing/time": string;
289
290
  "#std/testing/time.ts": string;
290
291
  "#std/expect": string;
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.1145",
3
+ "version": "0.1.1147",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -345,6 +345,7 @@ export default {
345
345
  "#std/testing.ts": "jsr:@std/testing@1.0.17",
346
346
  "#std/testing/bdd": "jsr:@std/testing@1.0.17/bdd",
347
347
  "#std/testing/bdd.ts": "jsr:@std/testing@1.0.17/bdd",
348
+ "#std/testing/mock": "jsr:@std/testing@1.0.17/mock",
348
349
  "#std/testing/time": "jsr:@std/testing@1.0.17/time",
349
350
  "#std/testing/time.ts": "jsr:@std/testing@1.0.17/time",
350
351
  "#std/expect": "jsr:@std/expect@1.0.18",
@@ -1,5 +1,5 @@
1
1
  import { createFileSystem } from "../platform/compat/fs.js";
2
- export declare const DISCOVERY_GLOBAL_VERYFRONT_MODULES: readonly ["veryfront/agent", "veryfront/tool", "veryfront/platform", "veryfront/prompt", "veryfront/resource", "veryfront/embedding", "veryfront/knowledge", "veryfront/workflow", "veryfront/eval", "veryfront/metrics", "veryfront/schemas", "veryfront/integrations", "veryfront/chat/uploads"];
2
+ export declare const DISCOVERY_GLOBAL_VERYFRONT_MODULES: readonly ["veryfront/agent", "veryfront/tool", "veryfront/platform", "veryfront/prompt", "veryfront/resource", "veryfront/embedding", "veryfront/knowledge", "veryfront/workflow", "veryfront/eval", "veryfront/metrics", "veryfront/schemas", "veryfront/integrations", "veryfront/middleware", "veryfront/chat/uploads"];
3
3
  interface DenoRewriteOptions {
4
4
  compiled?: boolean;
5
5
  resolveSpecifier?: (specifier: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/import-rewriter.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAS5D,eAAO,MAAM,kCAAkC,oSAerC,CAAC;AAEX,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;CAClD;AAwHD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CA2BR;AAeD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAyQjB"}
1
+ {"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/import-rewriter.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAS5D,eAAO,MAAM,kCAAkC,4TAqBrC,CAAC;AAEX,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;CAClD;AAwHD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CA2BR;AAeD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAyQjB"}
@@ -22,6 +22,12 @@ export const DISCOVERY_GLOBAL_VERYFRONT_MODULES = [
22
22
  "veryfront/metrics",
23
23
  "veryfront/schemas",
24
24
  "veryfront/integrations",
25
+ // API-route middleware helpers (`import { MiddlewarePipeline, cors, … } from
26
+ // "veryfront/middleware"`). Without this, a compiled binary cannot register the
27
+ // module, so its per-subpath shim (`_vf_middleware.mjs`) is empty and any API
28
+ // route using the pipeline 500s with "does not provide an export named
29
+ // 'MiddlewarePipeline'". See veryfront-issue-inbox#217.
30
+ "veryfront/middleware",
25
31
  // Server-side chat upload route handler (app/api/uploads/route.ts).
26
32
  "veryfront/chat/uploads",
27
33
  ];
@@ -10,6 +10,7 @@ import * as evalMod from "../eval/index.js";
10
10
  import * as metricsMod from "../metrics/index.js";
11
11
  import * as schemasMod from "../schemas/index.js";
12
12
  import * as integrationsMod from "../integrations/index.js";
13
+ import * as middlewareMod from "../middleware/index.js";
13
14
  import * as chatUploadsMod from "../chat/upload-handler.js";
14
15
  import { registerDiscoveryRuntimeModules } from "./runtime-modules.js";
15
16
  registerDiscoveryRuntimeModules({
@@ -25,5 +26,6 @@ registerDiscoveryRuntimeModules({
25
26
  "veryfront/metrics": metricsMod,
26
27
  "veryfront/schemas": schemasMod,
27
28
  "veryfront/integrations": integrationsMod,
29
+ "veryfront/middleware": middlewareMod,
28
30
  "veryfront/chat/uploads": chatUploadsMod,
29
31
  });
@@ -5,7 +5,9 @@ export declare class Semaphore {
5
5
  constructor(permits: number, options?: {
6
6
  maxQueueSize?: number;
7
7
  });
8
- tryAcquire(timeoutMs?: number): Promise<boolean>;
8
+ tryAcquire(timeoutMs?: number, options?: {
9
+ signal?: AbortSignal;
10
+ }): Promise<boolean>;
9
11
  release(): void;
10
12
  get available(): number;
11
13
  get waiting(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"semaphore.d.ts","sourceRoot":"","sources":["../../../../../../src/src/modules/react-loader/ssr-module-loader/concurrency/semaphore.ts"],"names":[],"mappings":"AAGA,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,SAAS,CAAoE;gBAEzE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;IAKhE,UAAU,CAAC,SAAS,SAA6B,GAAG,OAAO,CAAC,OAAO,CAAC;IAkCpE,OAAO,IAAI,IAAI;IAUf,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
1
+ {"version":3,"file":"semaphore.d.ts","sourceRoot":"","sources":["../../../../../../src/src/modules/react-loader/ssr-module-loader/concurrency/semaphore.ts"],"names":[],"mappings":"AAYA,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,SAAS,CAAyB;gBAE9B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;IAKhE,UAAU,CACR,SAAS,SAA6B,EACtC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GACrC,OAAO,CAAC,OAAO,CAAC;IAqEnB,OAAO,IAAI,IAAI;IAgBf,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
@@ -8,39 +8,78 @@ export class Semaphore {
8
8
  this.permits = permits;
9
9
  this.maxQueueSize = options?.maxQueueSize ?? Infinity;
10
10
  }
11
- tryAcquire(timeoutMs = DEFAULT_ACQUIRE_TIMEOUT_MS) {
11
+ tryAcquire(timeoutMs = DEFAULT_ACQUIRE_TIMEOUT_MS, options = {}) {
12
+ const { signal } = options;
13
+ if (signal?.aborted) {
14
+ return Promise.reject(signal.reason ?? new DOMException("The operation was aborted", "AbortError"));
15
+ }
12
16
  if (this.permits > 0) {
13
17
  this.permits--;
14
18
  return Promise.resolve(true);
15
19
  }
20
+ if (timeoutMs <= 0) {
21
+ return Promise.resolve(false);
22
+ }
16
23
  if (this.waitQueue.length >= this.maxQueueSize) {
17
24
  return Promise.resolve(false);
18
25
  }
19
- return new Promise((resolve) => {
20
- let settled = false;
21
- const onAcquire = () => {
22
- if (settled)
23
- return;
24
- settled = true;
25
- clearTimeout(timeoutId);
26
- resolve(true);
26
+ return new Promise((resolve, reject) => {
27
+ const waiter = {
28
+ resolve,
29
+ reject,
30
+ settled: false,
31
+ signal,
27
32
  };
28
- const timeoutId = setTimeout(() => {
29
- if (settled)
30
- return;
31
- settled = true;
32
- const index = this.waitQueue.findIndex((w) => w.resolve === onAcquire);
33
+ const removeWaiter = () => {
34
+ const index = this.waitQueue.indexOf(waiter);
33
35
  if (index !== -1)
34
36
  this.waitQueue.splice(index, 1);
35
- resolve(false);
36
- }, timeoutMs);
37
- this.waitQueue.push({ resolve: onAcquire, reject: onAcquire });
37
+ };
38
+ const cleanup = () => {
39
+ if (waiter.timeoutId !== undefined)
40
+ clearTimeout(waiter.timeoutId);
41
+ if (waiter.signal && waiter.onAbort) {
42
+ waiter.signal.removeEventListener("abort", waiter.onAbort);
43
+ }
44
+ };
45
+ waiter.onAbort = () => {
46
+ if (waiter.settled)
47
+ return;
48
+ waiter.settled = true;
49
+ removeWaiter();
50
+ cleanup();
51
+ reject(signal?.reason ?? new DOMException("The operation was aborted", "AbortError"));
52
+ };
53
+ signal?.addEventListener("abort", waiter.onAbort, { once: true });
54
+ if (signal?.aborted) {
55
+ waiter.onAbort();
56
+ return;
57
+ }
58
+ if (Number.isFinite(timeoutMs)) {
59
+ waiter.timeoutId = setTimeout(() => {
60
+ if (waiter.settled)
61
+ return;
62
+ waiter.settled = true;
63
+ removeWaiter();
64
+ cleanup();
65
+ resolve(false);
66
+ }, timeoutMs);
67
+ }
68
+ this.waitQueue.push(waiter);
38
69
  });
39
70
  }
40
71
  release() {
41
- const next = this.waitQueue.shift();
42
- if (next) {
43
- next.resolve();
72
+ let next;
73
+ while ((next = this.waitQueue.shift())) {
74
+ if (next.settled)
75
+ continue;
76
+ next.settled = true;
77
+ if (next.timeoutId !== undefined)
78
+ clearTimeout(next.timeoutId);
79
+ if (next.signal && next.onAbort) {
80
+ next.signal.removeEventListener("abort", next.onAbort);
81
+ }
82
+ next.resolve(true);
44
83
  return;
45
84
  }
46
85
  this.permits++;
@@ -22,9 +22,16 @@ export declare const RENDER_MAX_CONCURRENT: number;
22
22
  * Configurable via RENDER_PER_PROJECT_LIMIT env var.
23
23
  */
24
24
  export declare const RENDER_PER_PROJECT_LIMIT: number;
25
+ /**
26
+ * Maximum queued foreground renders per project.
27
+ * Defaults to one additional per-project concurrency window. Background work
28
+ * never enters this queue.
29
+ */
30
+ export declare const RENDER_PER_PROJECT_QUEUE_SIZE: number;
25
31
  /**
26
32
  * Timeout for acquiring render permit (ms).
27
- * If semaphore cannot be acquired within this time, request fails fast with 503.
33
+ * This is the total foreground admission budget across project and global
34
+ * capacity gates. Background work does not wait.
28
35
  */
29
36
  export declare const RENDER_ACQUIRE_TIMEOUT_MS = 5000;
30
37
  /**
@@ -47,10 +54,15 @@ export declare const renderSemaphore: Semaphore;
47
54
  */
48
55
  export declare const projectRenderCounts: Map<string, number>;
49
56
  /**
50
- * Attempt to acquire a project render slot with proper locking.
51
- * Returns true if acquired, false if limit reached.
57
+ * Attempt to acquire a project render slot with proper locking. Foreground
58
+ * callers may opt into a bounded FIFO wait; background callers use the
59
+ * fail-fast default.
52
60
  */
53
- export declare function acquireProjectSlot(projectId: string): Promise<boolean>;
61
+ export declare function acquireProjectSlot(projectId: string, options?: {
62
+ wait?: boolean;
63
+ timeoutMs?: number;
64
+ signal?: AbortSignal;
65
+ }): Promise<boolean>;
54
66
  /**
55
67
  * Release a project render slot with proper locking.
56
68
  */
@@ -1 +1 @@
1
- {"version":3,"file":"renderer-concurrency.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer-concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oEAAoE,CAAC;AAQ/F;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAA8C,CAAC;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QACC,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAS/C;;;;GAIG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IA+BhD,OAAO,CAAC,OAAO;IASf,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF;AAYD,eAAO,MAAM,eAAe,WAE1B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC;AA8B7D;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAwBf"}
1
+ {"version":3,"file":"renderer-concurrency.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer-concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oEAAoE,CAAC;AAQ/F;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAA4C,CAAC;AAE/E;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QAGpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,QAMzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAS/C;;;;GAIG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IA+BhD,OAAO,CAAC,OAAO;IASf,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF;AAYD,eAAO,MAAM,eAAe,WAE1B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC;AAyD7D;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACjB,GACL,OAAO,CAAC,OAAO,CAAC,CA0ElB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAqCf"}
@@ -19,18 +19,24 @@ import { RENDER_ERROR } from "../errors/index.js";
19
19
  * Configurable via RENDER_MAX_CONCURRENT env var.
20
20
  * Prevents one pod from being overwhelmed when multiple projects have issues.
21
21
  */
22
- export const RENDER_MAX_CONCURRENT = getEnvNumber("RENDER_MAX_CONCURRENT") ?? 30;
22
+ export const RENDER_MAX_CONCURRENT = getEnvNumber("RENDER_MAX_CONCURRENT", 30);
23
23
  /**
24
24
  * Maximum concurrent renders per project (noisy-neighbor protection).
25
25
  * Defaults to ceil(RENDER_MAX_CONCURRENT / 3) so no single project can consume
26
26
  * more than ~1/3 of pod capacity. Set to 0 to disable per-project limits.
27
27
  * Configurable via RENDER_PER_PROJECT_LIMIT env var.
28
28
  */
29
- export const RENDER_PER_PROJECT_LIMIT = getEnvNumber("RENDER_PER_PROJECT_LIMIT") ??
30
- Math.ceil(RENDER_MAX_CONCURRENT / 3);
29
+ export const RENDER_PER_PROJECT_LIMIT = getEnvNumber("RENDER_PER_PROJECT_LIMIT", Math.ceil(RENDER_MAX_CONCURRENT / 3));
30
+ /**
31
+ * Maximum queued foreground renders per project.
32
+ * Defaults to one additional per-project concurrency window. Background work
33
+ * never enters this queue.
34
+ */
35
+ export const RENDER_PER_PROJECT_QUEUE_SIZE = Math.max(0, getEnvNumber("RENDER_PER_PROJECT_QUEUE_SIZE", Math.max(0, RENDER_PER_PROJECT_LIMIT)));
31
36
  /**
32
37
  * Timeout for acquiring render permit (ms).
33
- * If semaphore cannot be acquired within this time, request fails fast with 503.
38
+ * This is the total foreground admission budget across project and global
39
+ * capacity gates. Background work does not wait.
34
40
  */
35
41
  export const RENDER_ACQUIRE_TIMEOUT_MS = 5_000;
36
42
  /** Maximum time to wait for a project lock before giving up (10 seconds) */
@@ -111,6 +117,7 @@ export const projectRenderCounts = new Map();
111
117
  * Each project gets its own mutex so different projects don't block each other.
112
118
  */
113
119
  const projectMutexes = new Map();
120
+ const projectSlotWaitQueues = new Map();
114
121
  function getProjectMutex(projectId) {
115
122
  let mutex = projectMutexes.get(projectId);
116
123
  if (!mutex) {
@@ -119,6 +126,21 @@ function getProjectMutex(projectId) {
119
126
  }
120
127
  return mutex;
121
128
  }
129
+ function getProjectSlotWaitQueue(projectId) {
130
+ let queue = projectSlotWaitQueues.get(projectId);
131
+ if (!queue) {
132
+ queue = [];
133
+ projectSlotWaitQueues.set(projectId, queue);
134
+ }
135
+ return queue;
136
+ }
137
+ function cleanupProjectSlotWaiter(waiter) {
138
+ if (waiter.timeoutId !== undefined)
139
+ clearTimeout(waiter.timeoutId);
140
+ if (waiter.signal && waiter.onAbort) {
141
+ waiter.signal.removeEventListener("abort", waiter.onAbort);
142
+ }
143
+ }
122
144
  // ---------------------------------------------------------------------------
123
145
  // Slot Functions
124
146
  // ---------------------------------------------------------------------------
@@ -129,19 +151,74 @@ function acquireProjectLock(projectId) {
129
151
  return getProjectMutex(projectId).acquire(LOCK_TIMEOUT_MS);
130
152
  }
131
153
  /**
132
- * Attempt to acquire a project render slot with proper locking.
133
- * Returns true if acquired, false if limit reached.
154
+ * Attempt to acquire a project render slot with proper locking. Foreground
155
+ * callers may opt into a bounded FIFO wait; background callers use the
156
+ * fail-fast default.
134
157
  */
135
- export async function acquireProjectSlot(projectId) {
158
+ export async function acquireProjectSlot(projectId, options = {}) {
159
+ const { signal } = options;
160
+ if (signal?.aborted) {
161
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
162
+ }
136
163
  if (RENDER_PER_PROJECT_LIMIT <= 0)
137
164
  return true;
138
165
  const release = await acquireProjectLock(projectId);
139
166
  try {
167
+ if (signal?.aborted) {
168
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
169
+ }
140
170
  const current = projectRenderCounts.get(projectId) ?? 0;
141
- if (current >= RENDER_PER_PROJECT_LIMIT)
171
+ if (current < RENDER_PER_PROJECT_LIMIT) {
172
+ projectRenderCounts.set(projectId, current + 1);
173
+ return true;
174
+ }
175
+ if (!options.wait || RENDER_PER_PROJECT_QUEUE_SIZE <= 0)
142
176
  return false;
143
- projectRenderCounts.set(projectId, current + 1);
144
- return true;
177
+ const timeoutMs = options.timeoutMs ?? RENDER_ACQUIRE_TIMEOUT_MS;
178
+ if (timeoutMs <= 0)
179
+ return false;
180
+ const queue = getProjectSlotWaitQueue(projectId);
181
+ if (queue.length >= RENDER_PER_PROJECT_QUEUE_SIZE)
182
+ return false;
183
+ return new Promise((resolve, reject) => {
184
+ const waiter = {
185
+ resolve,
186
+ reject,
187
+ settled: false,
188
+ signal,
189
+ };
190
+ const removeWaiter = () => {
191
+ const index = queue.indexOf(waiter);
192
+ if (index !== -1)
193
+ queue.splice(index, 1);
194
+ if (queue.length === 0 && projectSlotWaitQueues.get(projectId) === queue) {
195
+ projectSlotWaitQueues.delete(projectId);
196
+ }
197
+ };
198
+ const settleWithoutSlot = (reason) => {
199
+ if (waiter.settled)
200
+ return;
201
+ waiter.settled = true;
202
+ removeWaiter();
203
+ cleanupProjectSlotWaiter(waiter);
204
+ if (reason !== undefined) {
205
+ reject(reason);
206
+ }
207
+ else {
208
+ resolve(false);
209
+ }
210
+ };
211
+ waiter.onAbort = () => settleWithoutSlot(signal?.reason ?? new DOMException("The operation was aborted", "AbortError"));
212
+ signal?.addEventListener("abort", waiter.onAbort, { once: true });
213
+ if (signal?.aborted) {
214
+ waiter.onAbort();
215
+ return;
216
+ }
217
+ if (Number.isFinite(timeoutMs)) {
218
+ waiter.timeoutId = setTimeout(() => settleWithoutSlot(), timeoutMs);
219
+ }
220
+ queue.push(waiter);
221
+ });
145
222
  }
146
223
  finally {
147
224
  release();
@@ -158,9 +235,24 @@ export async function releaseProjectSlot(projectId) {
158
235
  let deleteIdleMutex = false;
159
236
  try {
160
237
  const current = projectRenderCounts.get(projectId) ?? 0;
238
+ const queue = projectSlotWaitQueues.get(projectId);
239
+ let next;
240
+ while ((next = queue?.shift())) {
241
+ if (next.settled)
242
+ continue;
243
+ next.settled = true;
244
+ cleanupProjectSlotWaiter(next);
245
+ if (queue?.length === 0)
246
+ projectSlotWaitQueues.delete(projectId);
247
+ projectRenderCounts.set(projectId, Math.max(1, current));
248
+ next.resolve(true);
249
+ return;
250
+ }
251
+ if (queue?.length === 0)
252
+ projectSlotWaitQueues.delete(projectId);
161
253
  if (current <= 1) {
162
254
  projectRenderCounts.delete(projectId);
163
- deleteIdleMutex = mutex.waiting === 0;
255
+ deleteIdleMutex = mutex.waiting === 0 && !projectSlotWaitQueues.has(projectId);
164
256
  return;
165
257
  }
166
258
  projectRenderCounts.set(projectId, current - 1);
@@ -41,10 +41,13 @@ export declare class Renderer {
41
41
  * Key format: {cachePrefix}:{slug}:{colorScheme}
42
42
  */
43
43
  private renderFlight;
44
+ /** Lets foreground followers recover when a background leader fails fast at capacity. */
45
+ private renderFlightAdmissions;
44
46
  private productionPrewarmContexts;
45
47
  constructor(options?: RendererOptions);
46
48
  initialize(options?: SharedServicesOptions): Promise<void>;
47
49
  renderPage(slug: string, ctx: RenderContext, options?: RenderOptions): Promise<RenderResult>;
50
+ private renderPageWithAdmission;
48
51
  private resolveReleaseAssetManifest;
49
52
  private withManifestCachePrefix;
50
53
  /**
@@ -69,6 +72,7 @@ export declare class Renderer {
69
72
  private getProductionPrewarmKey;
70
73
  private rememberProductionPrewarm;
71
74
  private buildCanonicalPrewarmOptions;
75
+ private buildRoutePrewarmOptions;
72
76
  private buildStaleRefreshOptions;
73
77
  private scheduleProductionRenderRefresh;
74
78
  private runProductionRenderPrewarm;
@@ -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;YA8D9E,2BAA2B;IAWzC,OAAO,CAAC,uBAAuB;IAiB/B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,+BAA+B;IAoCvC,OAAO,CAAC,+BAA+B;IASvC,OAAO,CAAC,oCAAoC;IAa5C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,yBAAyB;IASjC,OAAO,CAAC,4BAA4B;IAgBpC,OAAO,CAAC,wBAAwB;IAehC,OAAO,CAAC,+BAA+B;YAyCzB,0BAA0B;YAuD1B,YAAY;YA4DZ,qBAAqB;IAgGnC,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,aAAa,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,gBAAgB,CAAC;IA4B5B,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAU5C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;YAUtD,4BAA4B;IA4BpC,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5D,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,OAAO,CAAC,wBAAwB;CAmGjC;AAED,OAAO,EACL,mBAAmB,EACnB,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,aAAa,GACnB,CAAC;AAMF,wBAAgB,WAAW,IAAI,QAAQ,CAOtC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsBrF;AAED,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAQrD;AAED,wBAAsB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYnF;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,aAAa,EACvB,cAAc,CAAC,EAAE,0BAA0B,GAC1C,OAAO,CAAC,YAAY,CAAC,CAIvB"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/renderer.ts"],"names":[],"mappings":"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"}
@@ -32,7 +32,7 @@
32
32
  import * as dntShim from "../../_dnt.shims.js";
33
33
  import { rendererLogger } from "../utils/index.js";
34
34
  import { MDXCacheAdapter } from "../transforms/mdx/index.js";
35
- import { INITIALIZATION_ERROR, SERVICE_OVERLOADED } from "../errors/index.js";
35
+ import { INITIALIZATION_ERROR, SERVICE_OVERLOADED, VeryfrontError } from "../errors/index.js";
36
36
  import { withSpan } from "../observability/tracing/otlp-setup.js";
37
37
  import { buildQueryAwareCacheKey, buildRenderCachePrefix, } from "../cache/keys.js";
38
38
  import { requestHasCacheSensitiveState } from "../cache/request-cacheability.js";
@@ -159,6 +159,8 @@ export class Renderer {
159
159
  * Key format: {cachePrefix}:{slug}:{colorScheme}
160
160
  */
161
161
  renderFlight = new Singleflight();
162
+ /** Lets foreground followers recover when a background leader fails fast at capacity. */
163
+ renderFlightAdmissions = new Map();
162
164
  productionPrewarmContexts = new Map();
163
165
  constructor(options = {}) {
164
166
  this.cache = new ContextAwareCacheCoordinator(options.cache);
@@ -181,6 +183,9 @@ export class Renderer {
181
183
  this.initializationPromise = null;
182
184
  }
183
185
  renderPage(slug, ctx, options) {
186
+ return this.renderPageWithAdmission(slug, ctx, options, "foreground");
187
+ }
188
+ renderPageWithAdmission(slug, ctx, options, admission) {
184
189
  return withSpan("renderer.renderPage", async () => {
185
190
  if (!this.initialized) {
186
191
  throw INITIALIZATION_ERROR.create({
@@ -219,7 +224,7 @@ export class Renderer {
219
224
  }
220
225
  return cacheResult.cachedResult;
221
226
  }
222
- const result = await this.doRenderPage(slug, effectiveCtx, effectiveOptions, startTime, cacheKey, effectiveOptions.abortSignal ?? effectiveOptions.request?.signal);
227
+ const result = await this.doRenderPage(slug, effectiveCtx, effectiveOptions, startTime, cacheKey, effectiveOptions.abortSignal ?? effectiveOptions.request?.signal, admission);
223
228
  this.scheduleProductionRenderPrewarm(slug, effectiveCtx, effectiveOptions, cacheKey);
224
229
  return result;
225
230
  }, {
@@ -332,6 +337,9 @@ export class Renderer {
332
337
  this.productionPrewarmContexts.set(key, promise);
333
338
  }
334
339
  buildCanonicalPrewarmOptions(ctx, options) {
340
+ const sourceUrl = options?.url ??
341
+ (options?.request ? new URL(options.request.url) : undefined);
342
+ const canonicalUrl = sourceUrl ? new URL("/", sourceUrl) : undefined;
335
343
  return {
336
344
  environment: ctx.environment,
337
345
  projectId: ctx.projectId,
@@ -341,6 +349,20 @@ export class Renderer {
341
349
  releaseAssetManifest: options?.releaseAssetManifest ?? null,
342
350
  noHmr: options?.noHmr,
343
351
  forceProductionScripts: options?.forceProductionScripts,
352
+ url: canonicalUrl,
353
+ };
354
+ }
355
+ buildRoutePrewarmOptions(slug, options) {
356
+ if (!options.url)
357
+ return options;
358
+ const url = new URL(normalizeComparableSlug(slug), options.url);
359
+ return {
360
+ ...options,
361
+ url,
362
+ request: new Request(url, {
363
+ method: "GET",
364
+ headers: { accept: "text/html" },
365
+ }),
344
366
  };
345
367
  }
346
368
  buildStaleRefreshOptions(ctx, options) {
@@ -369,7 +391,7 @@ export class Renderer {
369
391
  });
370
392
  this.rememberProductionPrewarm(refreshKey, promise);
371
393
  setTimeout(() => {
372
- void this.doRenderPage(slug, ctx, refreshOptions, performance.now(), cacheKey, undefined)
394
+ void this.doRenderPage(slug, ctx, refreshOptions, performance.now(), cacheKey, undefined, "background")
373
395
  .then(() => {
374
396
  this.scheduleProductionRenderPrewarm(slug, ctx, refreshOptions, cacheKey);
375
397
  resolvePromise();
@@ -378,6 +400,14 @@ export class Renderer {
378
400
  promise.finally(() => {
379
401
  this.productionPrewarmContexts.delete(refreshKey);
380
402
  }).catch((error) => {
403
+ if (error instanceof VeryfrontError && error.slug === "service-overloaded") {
404
+ logger.debug("Production stale render refresh skipped at capacity", {
405
+ slug,
406
+ projectId: ctx.projectId,
407
+ releaseId: ctx.releaseId,
408
+ });
409
+ return;
410
+ }
381
411
  logger.warn("Production stale render refresh failed", {
382
412
  slug,
383
413
  projectId: ctx.projectId,
@@ -410,9 +440,17 @@ export class Renderer {
410
440
  return;
411
441
  const slug = slugs[index];
412
442
  try {
413
- await this.renderPage(slug, ctx, options);
443
+ await this.renderPageWithAdmission(slug, ctx, this.buildRoutePrewarmOptions(slug, options), "background");
414
444
  }
415
445
  catch (error) {
446
+ if (error instanceof VeryfrontError && error.slug === "service-overloaded") {
447
+ logger.debug("Production render prewarm route skipped at capacity", {
448
+ slug,
449
+ projectId: ctx.projectId,
450
+ releaseId: ctx.releaseId,
451
+ });
452
+ continue;
453
+ }
416
454
  logger.warn("Production render prewarm route failed", {
417
455
  slug,
418
456
  projectId: ctx.projectId,
@@ -429,13 +467,17 @@ export class Renderer {
429
467
  routeCount: slugs.length,
430
468
  });
431
469
  }
432
- async doRenderPage(slug, ctx, options, startTime, cacheKey, callerSignal) {
470
+ async doRenderPage(slug, ctx, options, startTime, cacheKey, callerSignal, admission, retryBackgroundOverload = true) {
433
471
  const effectiveKey = cacheKey ?? dntShim.crypto.randomUUID();
434
472
  const flightKey = this.getSingleflightKey(effectiveKey, ctx, options?.colorScheme);
435
473
  const isFollower = cacheKey !== null ? this.renderFlight.has(flightKey) : false;
474
+ const leaderAdmission = isFollower ? this.renderFlightAdmissions.get(flightKey) : admission;
436
475
  const runRender = async () => {
476
+ if (cacheKey !== null) {
477
+ this.renderFlightAdmissions.set(flightKey, admission);
478
+ }
437
479
  try {
438
- return await this.runRenderWithCapacity(slug, ctx, options, startTime, cacheKey, callerSignal);
480
+ return await this.runRenderWithCapacity(slug, ctx, options, startTime, cacheKey, callerSignal, admission);
439
481
  }
440
482
  catch (error) {
441
483
  if (error instanceof TimeoutError) {
@@ -447,10 +489,32 @@ export class Renderer {
447
489
  }
448
490
  throw error;
449
491
  }
492
+ finally {
493
+ if (cacheKey !== null &&
494
+ this.renderFlightAdmissions.get(flightKey) === admission) {
495
+ this.renderFlightAdmissions.delete(flightKey);
496
+ }
497
+ }
450
498
  };
451
- const cachedData = cacheKey !== null
452
- ? await waitForSharedPromise(this.renderFlight.do(flightKey, runRender), callerSignal)
453
- : await runRender();
499
+ let cachedData;
500
+ try {
501
+ cachedData = cacheKey !== null
502
+ ? await waitForSharedPromise(this.renderFlight.do(flightKey, runRender), callerSignal)
503
+ : await runRender();
504
+ }
505
+ catch (error) {
506
+ if (retryBackgroundOverload &&
507
+ admission === "foreground" &&
508
+ isFollower &&
509
+ leaderAdmission === "background" &&
510
+ error instanceof VeryfrontError &&
511
+ error.slug === "service-overloaded") {
512
+ // Background leaders never wait for capacity. Give a foreground follower
513
+ // its own bounded admission attempt instead of inheriting that fail-fast result.
514
+ return await this.doRenderPage(slug, ctx, options, startTime, cacheKey, callerSignal, admission, false);
515
+ }
516
+ throw error;
517
+ }
454
518
  if (isFollower) {
455
519
  logger.debug("Render deduplicated (follower)", {
456
520
  slug,
@@ -468,40 +532,63 @@ export class Renderer {
468
532
  stream: null,
469
533
  };
470
534
  }
471
- async runRenderWithCapacity(slug, ctx, options, startTime, cacheKey, callerSignal) {
472
- if (!(await acquireProjectSlot(ctx.projectId))) {
535
+ async runRenderWithCapacity(slug, ctx, options, startTime, cacheKey, callerSignal, admission) {
536
+ const admissionStartedAt = performance.now();
537
+ const admissionSignal = cacheKey === null ? callerSignal : undefined;
538
+ const waitForCapacity = admission === "foreground";
539
+ const projectAcquired = await acquireProjectSlot(ctx.projectId, {
540
+ wait: waitForCapacity,
541
+ timeoutMs: waitForCapacity ? RENDER_ACQUIRE_TIMEOUT_MS : 0,
542
+ ...(admissionSignal ? { signal: admissionSignal } : {}),
543
+ });
544
+ if (!projectAcquired) {
473
545
  const activeCount = projectRenderCounts.get(ctx.projectId) ?? 0;
474
- logger.error("Per-project render limit reached", {
546
+ const context = {
475
547
  slug,
476
548
  projectId: ctx.projectId,
477
549
  activeRenders: activeCount,
478
550
  limit: RENDER_PER_PROJECT_LIMIT,
479
- });
480
- throw SERVICE_OVERLOADED.create({
481
- detail: `Per-project render limit reached (${activeCount}/${RENDER_PER_PROJECT_LIMIT} active). Try again shortly.`,
482
- context: {
483
- slug,
484
- projectId: ctx.projectId,
485
- activeRenders: activeCount,
486
- limit: RENDER_PER_PROJECT_LIMIT,
487
- },
488
- });
489
- }
490
- const acquired = await renderSemaphore.tryAcquire(RENDER_ACQUIRE_TIMEOUT_MS);
491
- if (!acquired) {
492
- await releaseProjectSlot(ctx.projectId);
493
- logger.error("Render capacity exceeded - service overloaded", {
494
- slug,
495
- projectId: ctx.projectId,
496
- waiting: renderSemaphore.waiting,
497
- available: renderSemaphore.available,
498
- });
551
+ admission,
552
+ };
553
+ if (admission === "background") {
554
+ logger.debug("Background render skipped at per-project capacity", context);
555
+ }
556
+ else {
557
+ logger.warn("Per-project render admission exhausted", context);
558
+ }
499
559
  throw SERVICE_OVERLOADED.create({
500
- detail: `Render capacity exceeded (${renderSemaphore.waiting} waiting). Service is overloaded.`,
501
- context: { slug, projectId: ctx.projectId, waiting: renderSemaphore.waiting },
560
+ detail: `Per-project render admission exhausted (${activeCount}/${RENDER_PER_PROJECT_LIMIT} active). Try again shortly.`,
561
+ context,
502
562
  });
503
563
  }
564
+ let globalAcquired = false;
504
565
  try {
566
+ const elapsedAdmissionMs = performance.now() - admissionStartedAt;
567
+ const globalWaitMs = waitForCapacity
568
+ ? Math.max(0, RENDER_ACQUIRE_TIMEOUT_MS - elapsedAdmissionMs)
569
+ : 0;
570
+ globalAcquired = await renderSemaphore.tryAcquire(globalWaitMs, {
571
+ ...(admissionSignal ? { signal: admissionSignal } : {}),
572
+ });
573
+ if (!globalAcquired) {
574
+ const context = {
575
+ slug,
576
+ projectId: ctx.projectId,
577
+ waiting: renderSemaphore.waiting,
578
+ available: renderSemaphore.available,
579
+ admission,
580
+ };
581
+ if (admission === "background") {
582
+ logger.debug("Background render skipped at global capacity", context);
583
+ }
584
+ else {
585
+ logger.warn("Global render admission exhausted", context);
586
+ }
587
+ throw SERVICE_OVERLOADED.create({
588
+ detail: `Render admission exhausted (${renderSemaphore.waiting} waiting). Service is overloaded.`,
589
+ context,
590
+ });
591
+ }
505
592
  const services = this.createServicesForContext(ctx, options?.colorScheme);
506
593
  const renderAbortController = new AbortController();
507
594
  const request = cacheKey !== null && options?.request
@@ -541,7 +628,8 @@ export class Renderer {
541
628
  };
542
629
  }
543
630
  finally {
544
- renderSemaphore.release();
631
+ if (globalAcquired)
632
+ renderSemaphore.release();
545
633
  await releaseProjectSlot(ctx.projectId);
546
634
  }
547
635
  }
@@ -5,14 +5,41 @@ declare function createClassListStub(): {
5
5
  contains: () => false;
6
6
  toggle: () => false;
7
7
  };
8
+ /**
9
+ * `style` stub — a plain bag (so `el.style.color = "red"` works) that also
10
+ * carries the CSSOM methods libraries call during render (`setProperty`,
11
+ * `getPropertyValue`, `removeProperty`). Without these, any lib that sets a CSS
12
+ * custom property while rendering (Floating UI, Radix Presence, vaul) throws
13
+ * "el.style.setProperty is not a function" on the server.
14
+ */
15
+ declare function createStyleStub(): {
16
+ setProperty: (propertyName?: string, value?: string, priority?: string) => void;
17
+ getPropertyValue: (propertyName?: string) => string;
18
+ removeProperty: (propertyName?: string) => string;
19
+ item: (index?: number) => string;
20
+ cssText: string;
21
+ length: number;
22
+ [key: string]: unknown;
23
+ };
8
24
  export declare function createElementStub(): {
9
- style: Record<string, unknown>;
25
+ style: ReturnType<typeof createStyleStub>;
10
26
  classList: ReturnType<typeof createClassListStub>;
11
27
  dataset: Record<string, unknown>;
12
28
  setAttribute: () => void;
13
29
  getAttribute: () => null;
30
+ setAttributeNS: () => void;
31
+ getAttributeNS: () => null;
14
32
  removeAttribute: () => void;
15
33
  hasAttribute: () => false;
34
+ closest: () => null;
35
+ matches: () => false;
36
+ contains: () => false;
37
+ focus: () => void;
38
+ blur: () => void;
39
+ click: () => void;
40
+ scrollIntoView: () => void;
41
+ getClientRects: () => [];
42
+ remove: () => void;
16
43
  appendChild: () => void;
17
44
  removeChild: () => void;
18
45
  insertBefore: () => void;
@@ -72,9 +99,13 @@ export declare function createDocumentStub(): {
72
99
  getElementsByName: () => [];
73
100
  documentElement: ReturnType<typeof createElementStub>;
74
101
  body: ReturnType<typeof createElementStub>;
75
- head: {
76
- appendChild: () => void;
77
- removeChild: () => void;
102
+ head: ReturnType<typeof createElementStub>;
103
+ activeElement: null;
104
+ hidden: false;
105
+ visibilityState: "visible";
106
+ createDocumentFragment: () => ReturnType<typeof createElementStub>;
107
+ createComment: () => {
108
+ textContent: string;
78
109
  };
79
110
  readyState: "complete";
80
111
  cookie: string;
@@ -204,9 +235,27 @@ export declare function createWindowStub(): {
204
235
  URLSearchParams: typeof globalThis.URLSearchParams;
205
236
  TextEncoder: typeof globalThis.TextEncoder;
206
237
  TextDecoder: typeof globalThis.TextDecoder;
238
+ ResizeObserver: ReturnType<typeof createObserverClass>;
239
+ IntersectionObserver: ReturnType<typeof createObserverClass>;
240
+ MutationObserver: ReturnType<typeof createObserverClass>;
207
241
  };
208
242
  export declare function createElementClass(name: string): {
209
243
  new (): object;
210
244
  };
245
+ /**
246
+ * Observer stub class for `ResizeObserver` / `IntersectionObserver` /
247
+ * `MutationObserver`. Libraries that construct one eagerly (at module or render
248
+ * scope, not inside an effect) otherwise throw "ResizeObserver is not defined"
249
+ * during SSR. The instance carries the no-op observe/disconnect surface so a
250
+ * lib that also *calls* those during render doesn't crash either.
251
+ */
252
+ export declare function createObserverClass(name: string): {
253
+ new (callback?: unknown): {
254
+ observe: () => void;
255
+ unobserve: () => void;
256
+ disconnect: () => void;
257
+ takeRecords: () => [];
258
+ };
259
+ };
211
260
  export {};
212
261
  //# sourceMappingURL=dom-stubs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom-stubs.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/ssr-globals/dom-stubs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dom-stubs.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/ssr-globals/dom-stubs.ts"],"names":[],"mappings":"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"}
@@ -17,15 +17,43 @@ function createClassListStub() {
17
17
  toggle: noopFalse,
18
18
  };
19
19
  }
20
+ /**
21
+ * `style` stub — a plain bag (so `el.style.color = "red"` works) that also
22
+ * carries the CSSOM methods libraries call during render (`setProperty`,
23
+ * `getPropertyValue`, `removeProperty`). Without these, any lib that sets a CSS
24
+ * custom property while rendering (Floating UI, Radix Presence, vaul) throws
25
+ * "el.style.setProperty is not a function" on the server.
26
+ */
27
+ function createStyleStub() {
28
+ return {
29
+ setProperty: noop,
30
+ getPropertyValue: () => emptyString,
31
+ removeProperty: () => emptyString,
32
+ item: () => emptyString,
33
+ cssText: emptyString,
34
+ length: 0,
35
+ };
36
+ }
20
37
  export function createElementStub() {
21
38
  return {
22
- style: {},
39
+ style: createStyleStub(),
23
40
  classList: createClassListStub(),
24
41
  dataset: {},
25
42
  setAttribute: noop,
26
43
  getAttribute: noopNull,
44
+ setAttributeNS: noop,
45
+ getAttributeNS: noopNull,
27
46
  removeAttribute: noop,
28
47
  hasAttribute: noopFalse,
48
+ closest: noopNull,
49
+ matches: noopFalse,
50
+ contains: noopFalse,
51
+ focus: noop,
52
+ blur: noop,
53
+ click: noop,
54
+ scrollIntoView: noop,
55
+ getClientRects: noopEmptyArray,
56
+ remove: noop,
29
57
  appendChild: noop,
30
58
  removeChild: noop,
31
59
  insertBefore: noop,
@@ -88,7 +116,16 @@ export function createDocumentStub() {
88
116
  // helpers) don't crash on a missing `getAttribute`/`setAttribute`.
89
117
  documentElement: createElementStub(),
90
118
  body: createElementStub(),
91
- head: { appendChild: noop, removeChild: noop },
119
+ // head gets the full element stub too, so CSS-in-JS libraries (emotion,
120
+ // styled-components, etc.) that insert <style> tags via
121
+ // `document.head.insertBefore(...)` during SSR don't crash on a missing
122
+ // `insertBefore`.
123
+ head: createElementStub(),
124
+ activeElement: null,
125
+ hidden: false,
126
+ visibilityState: "visible",
127
+ createDocumentFragment: createElementStub,
128
+ createComment: () => ({ textContent: emptyString }),
92
129
  readyState: "complete",
93
130
  cookie: emptyString,
94
131
  domain: emptyString,
@@ -211,6 +248,9 @@ export function createWindowStub() {
211
248
  URLSearchParams: globalThis.URLSearchParams,
212
249
  TextEncoder: globalThis.TextEncoder,
213
250
  TextDecoder: globalThis.TextDecoder,
251
+ ResizeObserver: createObserverClass("ResizeObserver"),
252
+ IntersectionObserver: createObserverClass("IntersectionObserver"),
253
+ MutationObserver: createObserverClass("MutationObserver"),
214
254
  };
215
255
  }
216
256
  export function createElementClass(name) {
@@ -219,3 +259,22 @@ export function createElementClass(name) {
219
259
  Object.defineProperty(ElementClass, "name", { value: name });
220
260
  return ElementClass;
221
261
  }
262
+ /**
263
+ * Observer stub class for `ResizeObserver` / `IntersectionObserver` /
264
+ * `MutationObserver`. Libraries that construct one eagerly (at module or render
265
+ * scope, not inside an effect) otherwise throw "ResizeObserver is not defined"
266
+ * during SSR. The instance carries the no-op observe/disconnect surface so a
267
+ * lib that also *calls* those during render doesn't crash either.
268
+ */
269
+ export function createObserverClass(name) {
270
+ const ObserverClass = class {
271
+ observe() { }
272
+ unobserve() { }
273
+ disconnect() { }
274
+ takeRecords() {
275
+ return [];
276
+ }
277
+ };
278
+ Object.defineProperty(ObserverClass, "name", { value: name });
279
+ return ObserverClass;
280
+ }
@@ -1,5 +1,5 @@
1
1
  export { disableSSRClientOnlyFetching, enableSSRClientOnlyFetching, isSSRGlobalsActive, setSSRServerPort, } from "./context.js";
2
2
  export { disableSSRFetchInterception, enableSSRFetchInterception } from "./fetch-interceptor.js";
3
- export { createDocumentStub, createElementClass, createElementStub, createWindowStub, } from "./dom-stubs.js";
3
+ export { createDocumentStub, createElementClass, createElementStub, createObserverClass, createWindowStub, } from "./dom-stubs.js";
4
4
  export declare function setupSSRGlobals(): void;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/ssr-globals/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEjG,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,eAAe,IAAI,IAAI,CA8BtC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/ssr-globals/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEjG,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,eAAe,IAAI,IAAI,CAiDtC"}
@@ -9,7 +9,7 @@
9
9
  import * as dntShim from "../../../_dnt.shims.js";
10
10
  export { disableSSRClientOnlyFetching, enableSSRClientOnlyFetching, isSSRGlobalsActive, setSSRServerPort, } from "./context.js";
11
11
  export { disableSSRFetchInterception, enableSSRFetchInterception } from "./fetch-interceptor.js";
12
- export { createDocumentStub, createElementClass, createElementStub, createWindowStub, } from "./dom-stubs.js";
12
+ export { createDocumentStub, createElementClass, createElementStub, createObserverClass, createWindowStub, } from "./dom-stubs.js";
13
13
  import { isSSRGlobalsActive, markSSRGlobalsInitialized } from "./context.js";
14
14
  import { createElementClass, createWindowStub } from "./dom-stubs.js";
15
15
  function setGlobal(name, value) {
@@ -36,6 +36,24 @@ export function setupSSRGlobals() {
36
36
  if (globalThis.window !== undefined && globalThis.document !== undefined)
37
37
  return;
38
38
  const windowStub = createWindowStub();
39
+ // DOM constructor stubs. Libraries reach these both as bare globals and as
40
+ // properties of `window` / `ownerDocument.defaultView` (e.g. Headless UI's
41
+ // focus manager reads `window.HTMLElement.prototype`). Create them once and
42
+ // expose them in every place a library might look, and wire document.defaultView
43
+ // back to the window stub so `element.ownerDocument.defaultView` resolves.
44
+ const domConstructors = {
45
+ Element: createElementClass("Element"),
46
+ HTMLElement: createElementClass("HTMLElement"),
47
+ SVGElement: createElementClass("SVGElement"),
48
+ Node: createElementClass("Node"),
49
+ Text: createElementClass("Text"),
50
+ Comment: createElementClass("Comment"),
51
+ DocumentFragment: createElementClass("DocumentFragment"),
52
+ };
53
+ for (const [name, ctor] of Object.entries(domConstructors)) {
54
+ windowStub[name] = ctor;
55
+ }
56
+ windowStub.document.defaultView = windowStub;
39
57
  setGlobal("window", windowStub);
40
58
  setGlobal("document", windowStub.document);
41
59
  setGlobal("navigator", windowStub.navigator);
@@ -49,12 +67,11 @@ export function setupSSRGlobals() {
49
67
  setGlobal("cancelAnimationFrame", windowStub.cancelAnimationFrame);
50
68
  setGlobal("self", windowStub);
51
69
  setGlobal("__VERYFRONT_SSR__", true);
52
- setGlobalIfMissing("Element", createElementClass("Element"));
53
- setGlobalIfMissing("HTMLElement", createElementClass("HTMLElement"));
54
- setGlobalIfMissing("SVGElement", createElementClass("SVGElement"));
55
- setGlobalIfMissing("Node", createElementClass("Node"));
56
- setGlobalIfMissing("Text", createElementClass("Text"));
57
- setGlobalIfMissing("Comment", createElementClass("Comment"));
58
- setGlobalIfMissing("DocumentFragment", createElementClass("DocumentFragment"));
70
+ for (const [name, ctor] of Object.entries(domConstructors)) {
71
+ setGlobalIfMissing(name, ctor);
72
+ }
73
+ setGlobalIfMissing("ResizeObserver", windowStub.ResizeObserver);
74
+ setGlobalIfMissing("IntersectionObserver", windowStub.IntersectionObserver);
75
+ setGlobalIfMissing("MutationObserver", windowStub.MutationObserver);
59
76
  markSSRGlobalsInitialized();
60
77
  }
@@ -7,4 +7,8 @@ export declare function loadHandlerModule(options: LoadModuleOptions): Promise<A
7
7
  * import specifiers, rather than because the module itself is broken.
8
8
  */
9
9
  export declare function isSpecifierResolutionError(error: unknown): boolean;
10
+ export declare function getUserDependencies(allDeps: ReadonlyMap<string, string>, runtime: {
11
+ isDeno: boolean;
12
+ isCompiledBinary: boolean;
13
+ }): Map<string, string>;
10
14
  //# sourceMappingURL=loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/routing/api/module-loader/loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkB9D,OAAO,EACL,iCAAiC,EACjC,gCAAgC,EAChC,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,0CAA0C,EAC1C,qCAAqC,EACrC,6BAA6B,EAC7B,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyBtF;AA0DD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIlE"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/routing/api/module-loader/loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkB9D,OAAO,EACL,iCAAiC,EACjC,gCAAgC,EAChC,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,0CAA0C,EAC1C,qCAAqC,EACrC,6BAA6B,EAC7B,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyBtF;AA0DD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIlE;AA4bD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAA;CAAE,GACtD,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrB"}
@@ -304,16 +304,26 @@ function loadAndTranspileModule(modulePath, projectDir, adapter, fs, config) {
304
304
  // Filter out framework-managed packages from user deps. These are already
305
305
  // handled by the framework's own external/rewrite logic and should not be
306
306
  // treated as user npm packages.
307
- const frameworkPackages = new Set(["zod", "veryfront", "react", "react-dom", "path"]);
308
- const frameworkPrefixes = ["@opentelemetry/", "node:", "veryfront/"];
309
- const userDeps = new Map();
310
- for (const [name, version] of allDeps) {
311
- if (frameworkPackages.has(name))
312
- continue;
313
- if (frameworkPrefixes.some((p) => name.startsWith(p)))
314
- continue;
315
- userDeps.set(name, version);
316
- }
307
+ //
308
+ // `zod` is kept as a user dep on Node and the Deno source-run so a
309
+ // handler's own `import { z } from "zod"` is rewritten to a resolvable
310
+ // specifier. Excluding it left a bare `import "zod"` in the temp handler
311
+ // that Deno cannot resolve → "not a dependency and not in import map" → 500.
312
+ // (The Node path already always-resolves zod via
313
+ // getNodeExternalPackagesToResolve, so only the Deno source-run was broken
314
+ // by the exclusion.) zod is still force-externalized below, never bundled.
315
+ //
316
+ // The compiled binary keeps zod excluded — this change is scoped to the
317
+ // runtimes where it is verified. The binary loads framework helpers
318
+ // (createValidatedHandler, MiddlewarePipeline, …) through per-subpath
319
+ // veryfront runtime shims written next to the temp handler, a separate and
320
+ // more constrained resolution path; wiring a user `zod` through it belongs
321
+ // in a dedicated change with its own binary coverage. Leaving the binary
322
+ // branch byte-identical to before keeps that path untouched here.
323
+ const userDeps = getUserDependencies(allDeps, {
324
+ isDeno,
325
+ isCompiledBinary: isDeno && isCompiledBinary(),
326
+ });
317
327
  // Always externalize user npm dependencies. The bundled handler is loaded
318
328
  // from a temp file and user deps are resolved at runtime:
319
329
  // - Node.js: via file:// URLs pointing to node_modules
@@ -409,6 +419,21 @@ async function readFileWithExtensions(adapter, basePath, extensions, projectDir)
409
419
  message: `File not found: ${basePath}`,
410
420
  }));
411
421
  }
422
+ export function getUserDependencies(allDeps, runtime) {
423
+ const frameworkPackages = new Set(["veryfront", "react", "react-dom", "path"]);
424
+ if (runtime.isDeno && runtime.isCompiledBinary)
425
+ frameworkPackages.add("zod");
426
+ const frameworkPrefixes = ["@opentelemetry/", "node:", "veryfront/"];
427
+ const userDeps = new Map();
428
+ for (const [name, version] of allDeps) {
429
+ if (frameworkPackages.has(name))
430
+ continue;
431
+ if (frameworkPrefixes.some((prefix) => name.startsWith(prefix)))
432
+ continue;
433
+ userDeps.set(name, version);
434
+ }
435
+ return userDeps;
436
+ }
412
437
  async function loadModuleFromCode(code, projectDir, fs, userDeps = new Map()) {
413
438
  const tempDir = await fs.makeTempDir({ prefix: "vf-api-" });
414
439
  const tempFile = pathHelper.join(tempDir, "handler.mjs");
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAkCpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAkErE,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMtF,2CAA2C;AAC3C,eAAO,MAAM,aAAa,4vBAqChB,CAAC;AAEX,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA6CD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,mBAAwB,GAC7B;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAA;CAAE,CAuB5D;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;CAC/C;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,qBAAsC,GAC3C,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAsYnE;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAkCpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAuErE,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMtF,2CAA2C;AAC3C,eAAO,MAAM,aAAa,4vBAqChB,CAAC;AAEX,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA6CD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,mBAAwB,GAC7B;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAA;CAAE,CAuB5D;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;CAC/C;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,qBAAsC,GAC3C,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CA4YnE;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC"}
@@ -58,7 +58,7 @@ import { checkRequestIsolation, completeIsolatedRequest, completeIsolatedRequest
58
58
  import { defaultDiscoveryCache } from "./local-project-discovery.js";
59
59
  import { buildMinimalContext } from "./handler-context-builder.js";
60
60
  import { handleProjectsRequest, shouldHandleProjectsUI } from "./projects-handler.js";
61
- import { HTTP_GATEWAY_TIMEOUT, isLightweightPath, isMonitoringPath } from "./request-utils.js";
61
+ import { HTTP_GATEWAY_TIMEOUT, isHMRWebSocketUpgrade, isLightweightPath, isMonitoringPath, } from "./request-utils.js";
62
62
  import { withRequestTimeout } from "./timeout-manager.js";
63
63
  import { EnvironmentVariableCache, fetchProjectEnvVars, filterRuntimeProjectEnv, runWithProjectEnv, } from "../project-env/index.js";
64
64
  import { SCANNER_PATH_PATTERN } from "../../utils/constants/security.js";
@@ -418,7 +418,13 @@ export function createVeryfrontHandler(projectDir, adapter, opts = { projectDir
418
418
  return errorToRFC9457Response(noHandlerError, ctx, request);
419
419
  };
420
420
  const { response, error, settled } = await withRequestTimeout((signal) => {
421
- const timeoutRequest = new Request(req, { signal });
421
+ // Deno.upgradeWebSocket requires the exact Request received by
422
+ // Deno.serve. Cloning it to attach the timeout signal lets the
423
+ // handshake return 101, but the upgraded connection immediately
424
+ // closes with an unexpected EOF.
425
+ const timeoutRequest = isHMRWebSocketUpgrade(req, url.pathname)
426
+ ? req
427
+ : new Request(req, { signal });
422
428
  return runWithRequestProfiling({
423
429
  category: profileCategory,
424
430
  method: req.method,
@@ -24,6 +24,8 @@ export declare const LIGHTWEIGHT_PATH_PREFIXES: string[];
24
24
  export declare function isLightweightPath(pathname: string): boolean;
25
25
  /** Check if path is the WebSocket endpoint (long-lived, handled by HMR handler) */
26
26
  export declare function isWebSocketPath(pathname: string): boolean;
27
+ /** Check whether a request is the exact HMR WebSocket upgrade that must retain native identity. */
28
+ export declare function isHMRWebSocketUpgrade(request: Request, pathname: string): boolean;
27
29
  /**
28
30
  * Requests that do not need render-specific enriched context.
29
31
  *
@@ -1 +1 @@
1
- {"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/request-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBpD;AAED,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,aAA+C,CAAC;AAQ7E,yFAAyF;AACzF,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAEhC,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,eAA4B,CAAC;AAE1D,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,UASrC,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE"}
1
+ {"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/request-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBpD;AAED,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,aAA+C,CAAC;AAQ7E,yFAAyF;AACzF,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAEhC,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,eAA4B,CAAC;AAE1D,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,UASrC,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,mGAAmG;AACnG,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEjF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE"}
@@ -7,6 +7,7 @@
7
7
  * @module server/runtime-handler/request-utils
8
8
  */
9
9
  import { getTimeoutFromEnv } from "../../middleware/builtin/timeout.js";
10
+ import { isWebSocketUpgrade } from "../../platform/compat/http/websocket.js";
10
11
  import { HTTP_GATEWAY_TIMEOUT } from "../../utils/constants/http.js";
11
12
  /** Check if host is a private/internal IP address */
12
13
  export function isInternalHost(host) {
@@ -67,6 +68,10 @@ export function isLightweightPath(pathname) {
67
68
  export function isWebSocketPath(pathname) {
68
69
  return pathname === "/_ws";
69
70
  }
71
+ /** Check whether a request is the exact HMR WebSocket upgrade that must retain native identity. */
72
+ export function isHMRWebSocketUpgrade(request, pathname) {
73
+ return isWebSocketPath(pathname) && isWebSocketUpgrade(request);
74
+ }
70
75
  /**
71
76
  * Requests that do not need render-specific enriched context.
72
77
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ssr.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/rendering/ssr.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,kCAAkC,CAAC;AAwB1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,mBAAmB,IAAI,YAAY,CAAC;IACpC,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrF,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC;CAC3D;AAUD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EACN,WAAW,GACX,YAAY,GACZ,UAAU,GACV,cAAc,GACd,SAAS,GACT,2BAA2B,CAAC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AA4FD,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACpC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KACrC;IAKD,mBAAmB,IAAI,YAAY;IAW7B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IA6H1F,OAAO,CAAC,iBAAiB;IA2IzB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;CAS1D"}
1
+ {"version":3,"file":"ssr.service.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/services/rendering/ssr.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,kCAAkC,CAAC;AAwB1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,mBAAmB,IAAI,YAAY,CAAC;IACpC,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrF,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC;CAC3D;AAUD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EACN,WAAW,GACX,YAAY,GACZ,UAAU,GACV,cAAc,GACd,SAAS,GACT,2BAA2B,CAAC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AA4FD,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACpC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KACrC;IAKD,mBAAmB,IAAI,YAAY;IAW7B,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAI1D,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IA6H1F,OAAO,CAAC,iBAAiB;IAyJzB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;CAS1D"}
@@ -285,6 +285,17 @@ export class SSRService {
285
285
  return buildRedirectResult(redirect, errorObj, slug);
286
286
  }
287
287
  }
288
+ if (error instanceof VeryfrontError && error.slug === "service-overloaded") {
289
+ return {
290
+ status: error.status ?? HTTP_UNAVAILABLE,
291
+ html: ErrorPages.memoryPressure(),
292
+ isStreaming: false,
293
+ cacheStrategy: "no-cache",
294
+ error: errorObj,
295
+ errorType: "server-error",
296
+ slug,
297
+ };
298
+ }
288
299
  logger.error("Render failed", {
289
300
  slug,
290
301
  error: errorObj.message,
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.1145";
2
+ export declare const VERSION = "0.1.1147";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.1145";
4
+ export const VERSION = "0.1.1147";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.1145",
3
+ "version": "0.1.1147",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -332,10 +332,10 @@
332
332
  "@types/react": "19.2.14",
333
333
  "@types/react-dom": "19.2.3",
334
334
  "ws": "8.21.0",
335
- "@veryfront/ext-bundler-esbuild": "0.1.1145",
336
- "@veryfront/ext-content-mdx": "0.1.1145",
337
- "@veryfront/ext-css-tailwind": "0.1.1145",
338
- "@veryfront/ext-parser-babel": "0.1.1145"
335
+ "@veryfront/ext-bundler-esbuild": "0.1.1147",
336
+ "@veryfront/ext-content-mdx": "0.1.1147",
337
+ "@veryfront/ext-css-tailwind": "0.1.1147",
338
+ "@veryfront/ext-parser-babel": "0.1.1147"
339
339
  },
340
340
  "devDependencies": {
341
341
  "@types/node": "20.9.0"