@timber-js/app 0.2.0-alpha.85 → 0.2.0-alpha.87
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/dist/index.js +48 -1
- package/dist/index.js.map +1 -1
- package/dist/plugins/dev-error-overlay.d.ts +12 -0
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/server/dev-source-map.d.ts +22 -0
- package/dist/server/dev-source-map.d.ts.map +1 -0
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/internal.js +19 -2
- package/dist/server/internal.js.map +1 -1
- package/dist/server/pipeline.d.ts +10 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +11 -0
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +10 -0
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/package.json +7 -6
- package/src/cli.ts +0 -0
- package/src/plugins/dev-error-overlay.ts +67 -3
- package/src/plugins/dev-server.ts +13 -0
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/fallback-error.ts +5 -0
- package/src/server/pipeline.ts +34 -4
- package/src/server/rsc-entry/error-renderer.ts +5 -0
- package/src/server/rsc-entry/index.ts +54 -0
- package/src/server/rsc-entry/rsc-stream.ts +16 -0
- package/src/server/rsc-entry/ssr-renderer.ts +6 -3
- package/LICENSE +0 -8
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { type ProxyExport } from './proxy.js';
|
|
14
14
|
import { type MiddlewareFn } from './middleware-runner.js';
|
|
15
|
+
import { DenySignal } from './primitives.js';
|
|
15
16
|
import type { SegmentNode } from '../routing/types.js';
|
|
16
17
|
/**
|
|
17
18
|
* Shallow merge that skips prototype-polluting keys.
|
|
@@ -110,6 +111,15 @@ export interface PipelineConfig {
|
|
|
110
111
|
* `new Response(null, { status: 500 })`.
|
|
111
112
|
*/
|
|
112
113
|
renderFallbackError?: (error: unknown, req: Request, responseHeaders: Headers) => Response | Promise<Response>;
|
|
114
|
+
/**
|
|
115
|
+
* Fallback deny page renderer — called when a DenySignal escapes from
|
|
116
|
+
* middleware or the render phase. Renders the appropriate status-code
|
|
117
|
+
* page (403.tsx, 404.tsx, etc.) instead of returning a bare empty response.
|
|
118
|
+
*
|
|
119
|
+
* If this function throws, the pipeline falls back to a bare
|
|
120
|
+
* `new Response(null, { status: denyStatus })`.
|
|
121
|
+
*/
|
|
122
|
+
renderDenyFallback?: (deny: DenySignal, req: Request, responseHeaders: Headers) => Response | Promise<Response>;
|
|
113
123
|
}
|
|
114
124
|
/**
|
|
115
125
|
* Run segment param coercion on the matched route's segments.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/error-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"error-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/error-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAYvD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqHD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,WAAW,EAAE,EAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,qBAAqB,EACtC,WAAW,CAAC,EAAE,eAAe,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAwCnB;AAqID;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,qBAAqB,GACrC,OAAO,CAAC,QAAQ,CAAC,CA6BnB"}
|
|
@@ -10,6 +10,17 @@ import { type DebugComponentEntry } from './helpers.js';
|
|
|
10
10
|
* debug channel. This is only populated for render-phase errors.
|
|
11
11
|
*/
|
|
12
12
|
export declare function setDevPipelineErrorHandler(handler: (error: Error, phase: string, debugComponents?: DebugComponentEntry[]) => void): void;
|
|
13
|
+
/**
|
|
14
|
+
* Set the dev source-map handler.
|
|
15
|
+
*
|
|
16
|
+
* Called by the dev server after importing this module to wire Vite's
|
|
17
|
+
* module graph source-mapping into the error rendering pipeline. Errors
|
|
18
|
+
* rendered by renderErrorPage / renderFallbackError will have their
|
|
19
|
+
* stack traces rewritten to show original source positions.
|
|
20
|
+
*
|
|
21
|
+
* No-op in production.
|
|
22
|
+
*/
|
|
23
|
+
export declare function setDevSourceMapHandler(handler: (error: Error) => void): void;
|
|
13
24
|
export { runWithEarlyHintsSender } from '../early-hints-sender.js';
|
|
14
25
|
export { runWithWaitUntil } from '../waituntil-bridge.js';
|
|
15
26
|
declare const _default: (req: Request) => Promise<Response>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA4DA,OAAO,EAKL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAoCtB;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,mBAAmB,EAAE,KAAK,IAAI,GACtF,IAAI,CAEN;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;AAqiBD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;8BA3SrC,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA6ShD,wBAAiE"}
|
|
@@ -28,6 +28,16 @@ export interface RenderSignals {
|
|
|
28
28
|
error: unknown;
|
|
29
29
|
status: number;
|
|
30
30
|
} | null;
|
|
31
|
+
/**
|
|
32
|
+
* The last unhandled error seen by RSC onError that isn't a signal.
|
|
33
|
+
* Used as a fallback when SSR fails (SsrStreamError) but no structured
|
|
34
|
+
* signal was captured — provides the original error for the error page
|
|
35
|
+
* instead of relying on SsrStreamError.cause extraction.
|
|
36
|
+
*
|
|
37
|
+
* NOT used for page-level error detection (that would break Suspense
|
|
38
|
+
* error isolation). Only consumed when SSR actually fails.
|
|
39
|
+
*/
|
|
40
|
+
lastUnhandledError: unknown | null;
|
|
31
41
|
/** Callback fired when a redirect or deny signal is captured in onError. */
|
|
32
42
|
onSignal?: () => void;
|
|
33
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAItB;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvD,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;IACvB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,mBAAmB,EAAE,CAAC;CAClD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAItB;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvD;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;IACvB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,mBAAmB,EAAE,CAAC;CAClD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CA4J1F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAW/D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAarD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAiB,CAAC;AAEhF,UAAU,gBAAgB;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"ssr-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAW/D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAarD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAiB,CAAC;AAEhF,UAAU,gBAAgB;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiRjF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.87",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -110,6 +110,11 @@
|
|
|
110
110
|
"publishConfig": {
|
|
111
111
|
"access": "public"
|
|
112
112
|
},
|
|
113
|
+
"scripts": {
|
|
114
|
+
"build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
|
|
115
|
+
"typecheck": "tsgo --noEmit",
|
|
116
|
+
"prepublishOnly": "pnpm run build"
|
|
117
|
+
},
|
|
113
118
|
"dependencies": {
|
|
114
119
|
"@opentelemetry/api": "^1.9.1",
|
|
115
120
|
"@opentelemetry/context-async-hooks": "^2.6.1",
|
|
@@ -152,9 +157,5 @@
|
|
|
152
157
|
},
|
|
153
158
|
"engines": {
|
|
154
159
|
"node": ">=22.12.0"
|
|
155
|
-
},
|
|
156
|
-
"scripts": {
|
|
157
|
-
"build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
|
|
158
|
-
"typecheck": "tsgo --noEmit"
|
|
159
160
|
}
|
|
160
|
-
}
|
|
161
|
+
}
|
package/src/cli.ts
CHANGED
|
File without changes
|
|
@@ -234,6 +234,49 @@ export function formatRscDebugContext(components: RscDebugComponentInfo[]): stri
|
|
|
234
234
|
return lines.join('\n');
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
// ─── Module Runner Offset ───────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Dynamically compute the line offset that Vite's module runner adds
|
|
241
|
+
* when wrapping modules in an async function.
|
|
242
|
+
*
|
|
243
|
+
* Vite's `calculateOffsetOnce()` uses the same technique: create a new
|
|
244
|
+
* AsyncFunction, throw from line 1, and check where the engine reports
|
|
245
|
+
* the error. The difference between the reported line and 1 is the offset.
|
|
246
|
+
*
|
|
247
|
+
* This is engine-dependent (currently 2 on Node 18-22) and could change
|
|
248
|
+
* in future Node.js or V8 versions. Computing it at runtime ensures we
|
|
249
|
+
* always match the actual behavior.
|
|
250
|
+
*/
|
|
251
|
+
let _cachedOffset: number | null = null;
|
|
252
|
+
|
|
253
|
+
export function calculateModuleRunnerOffset(): number {
|
|
254
|
+
if (_cachedOffset !== null) return _cachedOffset;
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
// Parse the AsyncFunction source to count wrapper lines before the body.
|
|
258
|
+
// AsyncFunction.toString() returns something like:
|
|
259
|
+
// "async function anonymous(\n) {\nBODY\n}"
|
|
260
|
+
// The number of newlines before BODY is the offset Vite's module runner adds.
|
|
261
|
+
// eslint-disable-next-line no-new-func -- intentional: mirrors Vite's technique
|
|
262
|
+
const AsyncFunction = async function () {}.constructor as typeof Function;
|
|
263
|
+
const wrapper = new AsyncFunction('BODY');
|
|
264
|
+
const src = wrapper.toString();
|
|
265
|
+
const bodyIndex = src.indexOf('BODY');
|
|
266
|
+
if (bodyIndex === -1) {
|
|
267
|
+
_cachedOffset = 2; // fallback
|
|
268
|
+
return _cachedOffset;
|
|
269
|
+
}
|
|
270
|
+
const beforeBody = src.slice(0, bodyIndex);
|
|
271
|
+
const newlineCount = (beforeBody.match(/\n/g) || []).length;
|
|
272
|
+
_cachedOffset = newlineCount;
|
|
273
|
+
} catch {
|
|
274
|
+
_cachedOffset = 2; // fallback to known-good value
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return _cachedOffset;
|
|
278
|
+
}
|
|
279
|
+
|
|
237
280
|
// ─── Stack Trace Source-Mapping ──────────────────────────────────────────────
|
|
238
281
|
|
|
239
282
|
/**
|
|
@@ -310,9 +353,10 @@ function rewriteStacktrace(
|
|
|
310
353
|
const rawSourceMap = mod?.transformResult?.map;
|
|
311
354
|
if (!rawSourceMap) return input;
|
|
312
355
|
|
|
313
|
-
// Vite's module runner
|
|
314
|
-
//
|
|
315
|
-
|
|
356
|
+
// Vite's module runner wraps each module in an async function,
|
|
357
|
+
// adding N lines before the module body. The offset is computed
|
|
358
|
+
// dynamically to match the actual engine behavior (see TIM-783).
|
|
359
|
+
const OFFSET = calculateModuleRunnerOffset();
|
|
316
360
|
const origLine = Number(lineStr) - OFFSET;
|
|
317
361
|
const origCol = Number(colStr) - 1;
|
|
318
362
|
if (origLine <= 0 || origCol < 0) return input;
|
|
@@ -344,6 +388,26 @@ function rewriteStacktrace(
|
|
|
344
388
|
return { stack: result, changed };
|
|
345
389
|
}
|
|
346
390
|
|
|
391
|
+
// ─── Error Source-Mapping (exported for use by fallback-error.ts) ────────────
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Source-map an error's stack trace using the Vite dev server's module graph.
|
|
395
|
+
*
|
|
396
|
+
* Exported so that the fallback error renderer (fallback-error.ts) can
|
|
397
|
+
* source-map errors before rendering the dev error page. Without this,
|
|
398
|
+
* the dev error page shows transpiled positions (e.g. page.tsx:1:1 instead
|
|
399
|
+
* of page.tsx:4:9).
|
|
400
|
+
*
|
|
401
|
+
* See TIM-811.
|
|
402
|
+
*/
|
|
403
|
+
export function fixErrorStacktrace(server: ViteDevServer, error: Error, phase?: ErrorPhase): void {
|
|
404
|
+
fixStacktraceForEnvironment(
|
|
405
|
+
server,
|
|
406
|
+
error,
|
|
407
|
+
phase ?? classifyErrorPhase(error, server.config.root)
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
347
411
|
// ─── Overlay Integration ────────────────────────────────────────────────────
|
|
348
412
|
|
|
349
413
|
/**
|
|
@@ -20,6 +20,7 @@ import { setViteServer } from '../server/dev-warnings.js';
|
|
|
20
20
|
import {
|
|
21
21
|
sendErrorToOverlay,
|
|
22
22
|
classifyErrorPhase,
|
|
23
|
+
fixErrorStacktrace,
|
|
23
24
|
parseFirstAppFrame,
|
|
24
25
|
type ErrorPhase,
|
|
25
26
|
} from './dev-error-overlay.js';
|
|
@@ -213,6 +214,18 @@ function createTimberMiddleware(server: ViteDevServer, projectRoot: string) {
|
|
|
213
214
|
);
|
|
214
215
|
});
|
|
215
216
|
}
|
|
217
|
+
|
|
218
|
+
// Wire source-map handler so error pages show original positions.
|
|
219
|
+
// fixErrorStacktrace rewrites the error's stack trace in-place using
|
|
220
|
+
// the Vite dev server's module graph. See TIM-811.
|
|
221
|
+
const setSourceMap = rscModule.setDevSourceMapHandler as
|
|
222
|
+
| ((fn: (error: Error) => void) => void)
|
|
223
|
+
| undefined;
|
|
224
|
+
if (typeof setSourceMap === 'function') {
|
|
225
|
+
setSourceMap((error: Error) => {
|
|
226
|
+
fixErrorStacktrace(server, error);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
216
229
|
} catch (error) {
|
|
217
230
|
// Module transform error — syntax error, missing import, etc.
|
|
218
231
|
// Vite may already show its own overlay for these, but we still
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-only error source-mapping bridge.
|
|
3
|
+
*
|
|
4
|
+
* Stores a callback that rewrites an error's stack trace using the Vite
|
|
5
|
+
* dev server's module graph. Set by the RSC entry on startup (via
|
|
6
|
+
* setDevSourceMapHandler), consumed by error renderers before generating
|
|
7
|
+
* error pages.
|
|
8
|
+
*
|
|
9
|
+
* In production, the callback is never set — all calls are no-ops.
|
|
10
|
+
*
|
|
11
|
+
* See TIM-811.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
let _sourceMapError: ((error: Error) => void) | undefined;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Set the source-map callback. Called once during dev server initialization.
|
|
18
|
+
*/
|
|
19
|
+
export function setSourceMapCallback(fn: (error: Error) => void): void {
|
|
20
|
+
_sourceMapError = fn;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Source-map an error's stack trace in-place if the callback is available.
|
|
25
|
+
* No-op in production or before the dev server initializes.
|
|
26
|
+
*/
|
|
27
|
+
export function sourceMapError(error: unknown): void {
|
|
28
|
+
if (_sourceMapError && error instanceof Error) {
|
|
29
|
+
_sourceMapError(error);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -17,6 +17,7 @@ import type { LayoutEntry } from './deny-renderer.js';
|
|
|
17
17
|
import type { GlobalErrorFile } from './rsc-entry/error-renderer.js';
|
|
18
18
|
import { logRenderError } from './logger.js';
|
|
19
19
|
import { loadModule } from './safe-load.js';
|
|
20
|
+
import { sourceMapError } from './dev-source-map.js';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Render a fallback error page when the render pipeline throws.
|
|
@@ -34,6 +35,10 @@ export async function renderFallbackError(
|
|
|
34
35
|
globalError?: GlobalErrorFile,
|
|
35
36
|
projectRoot?: string
|
|
36
37
|
): Promise<Response> {
|
|
38
|
+
// Source-map the error's stack trace in dev mode so the error page
|
|
39
|
+
// shows original source positions. See TIM-811.
|
|
40
|
+
sourceMapError(error);
|
|
41
|
+
|
|
37
42
|
if (isDev) {
|
|
38
43
|
return renderDevErrorPage(error, projectRoot);
|
|
39
44
|
}
|
package/src/server/pipeline.ts
CHANGED
|
@@ -168,6 +168,7 @@ export interface PipelineConfig {
|
|
|
168
168
|
* Undefined in production — zero overhead.
|
|
169
169
|
*/
|
|
170
170
|
onPipelineError?: (error: Error, phase: string) => void;
|
|
171
|
+
|
|
171
172
|
/**
|
|
172
173
|
* Fallback error renderer — called when a catastrophic error escapes the
|
|
173
174
|
* render phase. Produces an HTML Response instead of a bare empty 500.
|
|
@@ -184,6 +185,19 @@ export interface PipelineConfig {
|
|
|
184
185
|
req: Request,
|
|
185
186
|
responseHeaders: Headers
|
|
186
187
|
) => Response | Promise<Response>;
|
|
188
|
+
/**
|
|
189
|
+
* Fallback deny page renderer — called when a DenySignal escapes from
|
|
190
|
+
* middleware or the render phase. Renders the appropriate status-code
|
|
191
|
+
* page (403.tsx, 404.tsx, etc.) instead of returning a bare empty response.
|
|
192
|
+
*
|
|
193
|
+
* If this function throws, the pipeline falls back to a bare
|
|
194
|
+
* `new Response(null, { status: denyStatus })`.
|
|
195
|
+
*/
|
|
196
|
+
renderDenyFallback?: (
|
|
197
|
+
deny: DenySignal,
|
|
198
|
+
req: Request,
|
|
199
|
+
responseHeaders: Headers
|
|
200
|
+
) => Response | Promise<Response>;
|
|
187
201
|
}
|
|
188
202
|
|
|
189
203
|
// ─── Param Coercion ────────────────────────────────────────────────────────
|
|
@@ -624,9 +638,18 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
624
638
|
applyCookieJar(responseHeaders);
|
|
625
639
|
return buildRedirectResponse(error, req, responseHeaders);
|
|
626
640
|
}
|
|
627
|
-
// DenySignal from middleware →
|
|
641
|
+
// DenySignal from middleware → render deny page with correct status code.
|
|
642
|
+
// Previously returned bare Response(null) — now renders 403.tsx etc.
|
|
628
643
|
if (error instanceof DenySignal) {
|
|
629
|
-
|
|
644
|
+
applyCookieJar(responseHeaders);
|
|
645
|
+
if (config.renderDenyFallback) {
|
|
646
|
+
try {
|
|
647
|
+
return await config.renderDenyFallback(error, req, responseHeaders);
|
|
648
|
+
} catch {
|
|
649
|
+
// Deny page rendering failed — fall through to bare response
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return new Response(null, { status: error.status, headers: responseHeaders });
|
|
630
653
|
}
|
|
631
654
|
// Middleware throw → HTTP 500 (middleware runs before rendering,
|
|
632
655
|
// no error boundary to catch it)
|
|
@@ -655,9 +678,16 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
655
678
|
return response;
|
|
656
679
|
} catch (error) {
|
|
657
680
|
// DenySignal leaked from render (e.g. notFound() in metadata()).
|
|
658
|
-
//
|
|
681
|
+
// Render the deny page with the correct status code.
|
|
659
682
|
if (error instanceof DenySignal) {
|
|
660
|
-
|
|
683
|
+
if (config.renderDenyFallback) {
|
|
684
|
+
try {
|
|
685
|
+
return await config.renderDenyFallback(error, req, responseHeaders);
|
|
686
|
+
} catch {
|
|
687
|
+
// Deny page rendering failed — fall through to bare response
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return new Response(null, { status: error.status, headers: responseHeaders });
|
|
661
691
|
}
|
|
662
692
|
// RedirectSignal leaked from render — honour the redirect
|
|
663
693
|
if (error instanceof RedirectSignal) {
|
|
@@ -32,6 +32,7 @@ import { isDevMode } from '../debug.js';
|
|
|
32
32
|
import { ErrorReconstituter } from '../../client/error-reconstituter.js';
|
|
33
33
|
import type { SerializableError } from '../../client/error-reconstituter.js';
|
|
34
34
|
import { loadModule } from '../safe-load.js';
|
|
35
|
+
import { sourceMapError } from '../dev-source-map.js';
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* A manifest file reference with lazy import and path.
|
|
@@ -176,6 +177,10 @@ export async function renderErrorPage(
|
|
|
176
177
|
clientBootstrap: ClientBootstrapConfig,
|
|
177
178
|
globalError?: GlobalErrorFile
|
|
178
179
|
): Promise<Response> {
|
|
180
|
+
// Source-map the error's stack trace in dev mode so the error page
|
|
181
|
+
// shows original source positions instead of transpiled/bundled ones.
|
|
182
|
+
// See TIM-811.
|
|
183
|
+
sourceMapError(error);
|
|
179
184
|
// Walk segments from leaf to root to find the error component
|
|
180
185
|
const resolution = await resolveErrorFile(status, segments);
|
|
181
186
|
|
|
@@ -54,6 +54,8 @@ import { initDevTracing } from '../tracing.js';
|
|
|
54
54
|
|
|
55
55
|
import { renderFallbackError as renderFallback } from '../fallback-error.js';
|
|
56
56
|
import { loadInstrumentation } from '../instrumentation.js';
|
|
57
|
+
import { loadModule } from '../safe-load.js';
|
|
58
|
+
import { logRenderError } from '../logger.js';
|
|
57
59
|
import { handleApiRoute } from './api-handler.js';
|
|
58
60
|
import { renderErrorPage, renderNoMatchPage } from './error-renderer.js';
|
|
59
61
|
import {
|
|
@@ -69,6 +71,7 @@ import { renderRscStream } from './rsc-stream.js';
|
|
|
69
71
|
import { renderSsrResponse } from './ssr-renderer.js';
|
|
70
72
|
import { callSsr } from './ssr-bridge.js';
|
|
71
73
|
import { isDebug, isDevMode, setDebugFromConfig } from '../debug.js';
|
|
74
|
+
import { setSourceMapCallback } from '../dev-source-map.js';
|
|
72
75
|
import { recordTiming } from '../server-timing.js';
|
|
73
76
|
import { requestContextAls } from '../als-registry.js';
|
|
74
77
|
import { createAutoSitemapHandler } from '../sitemap-handler.js';
|
|
@@ -113,6 +116,20 @@ export function setDevPipelineErrorHandler(
|
|
|
113
116
|
_devPipelineErrorHandler = handler;
|
|
114
117
|
}
|
|
115
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Set the dev source-map handler.
|
|
121
|
+
*
|
|
122
|
+
* Called by the dev server after importing this module to wire Vite's
|
|
123
|
+
* module graph source-mapping into the error rendering pipeline. Errors
|
|
124
|
+
* rendered by renderErrorPage / renderFallbackError will have their
|
|
125
|
+
* stack traces rewritten to show original source positions.
|
|
126
|
+
*
|
|
127
|
+
* No-op in production.
|
|
128
|
+
*/
|
|
129
|
+
export function setDevSourceMapHandler(handler: (error: Error) => void): void {
|
|
130
|
+
setSourceMapCallback(handler);
|
|
131
|
+
}
|
|
132
|
+
|
|
116
133
|
// Dev-only: debug components getter is stored per-request in ALS
|
|
117
134
|
// (RequestContextStore.debugComponentsGetter) to avoid cross-request
|
|
118
135
|
// race conditions. See TIM-557.
|
|
@@ -295,6 +312,7 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
|
|
|
295
312
|
}
|
|
296
313
|
}
|
|
297
314
|
: undefined,
|
|
315
|
+
|
|
298
316
|
renderFallbackError: (error, req, responseHeaders) =>
|
|
299
317
|
renderFallback(
|
|
300
318
|
error,
|
|
@@ -310,6 +328,42 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
|
|
|
310
328
|
// CWD differs from project root (e.g., monorepo custom root) (TIM-807).
|
|
311
329
|
isDev ? manifest.root : undefined
|
|
312
330
|
),
|
|
331
|
+
renderDenyFallback: async (deny, req, responseHeaders) => {
|
|
332
|
+
// Render the deny page (403.tsx, 404.tsx, etc.) for DenySignals
|
|
333
|
+
// that escape from middleware or the render phase. Uses the root
|
|
334
|
+
// segment to resolve status-code files and layout wrapping.
|
|
335
|
+
const segments = [
|
|
336
|
+
manifest.root,
|
|
337
|
+
] as unknown as import('../route-matcher.js').ManifestSegmentNode[];
|
|
338
|
+
const layoutComponents: LayoutEntry[] = [];
|
|
339
|
+
try {
|
|
340
|
+
if (manifest.root.layout) {
|
|
341
|
+
const mod = await loadModule(manifest.root.layout);
|
|
342
|
+
if (mod.default) {
|
|
343
|
+
layoutComponents.push({
|
|
344
|
+
component: mod.default as (...args: unknown[]) => unknown,
|
|
345
|
+
segment:
|
|
346
|
+
manifest.root as unknown as import('../route-matcher.js').ManifestSegmentNode,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
} catch (layoutError) {
|
|
351
|
+
// Layout failed to load — proceed without it.
|
|
352
|
+
logRenderError({ method: req.method, path: new URL(req.url).pathname, error: layoutError });
|
|
353
|
+
}
|
|
354
|
+
const match = { segments: segments as never, segmentParams: {}, middlewareChain: [] };
|
|
355
|
+
return renderDenyPage(
|
|
356
|
+
deny,
|
|
357
|
+
segments,
|
|
358
|
+
layoutComponents,
|
|
359
|
+
req,
|
|
360
|
+
match,
|
|
361
|
+
responseHeaders,
|
|
362
|
+
clientBootstrap,
|
|
363
|
+
createDebugChannelSink,
|
|
364
|
+
callSsr
|
|
365
|
+
);
|
|
366
|
+
},
|
|
313
367
|
// Auto-generated sitemap handler — enabled when sitemap.enabled is true
|
|
314
368
|
// and no user-authored sitemap exists at the app root.
|
|
315
369
|
// See design/16-metadata.md §"Auto-generated Sitemap"
|
|
@@ -41,6 +41,16 @@ export interface RenderSignals {
|
|
|
41
41
|
denySignal: DenySignal | null;
|
|
42
42
|
redirectSignal: RedirectSignal | null;
|
|
43
43
|
renderError: { error: unknown; status: number } | null;
|
|
44
|
+
/**
|
|
45
|
+
* The last unhandled error seen by RSC onError that isn't a signal.
|
|
46
|
+
* Used as a fallback when SSR fails (SsrStreamError) but no structured
|
|
47
|
+
* signal was captured — provides the original error for the error page
|
|
48
|
+
* instead of relying on SsrStreamError.cause extraction.
|
|
49
|
+
*
|
|
50
|
+
* NOT used for page-level error detection (that would break Suspense
|
|
51
|
+
* error isolation). Only consumed when SSR actually fails.
|
|
52
|
+
*/
|
|
53
|
+
lastUnhandledError: unknown | null;
|
|
44
54
|
/** Callback fired when a redirect or deny signal is captured in onError. */
|
|
45
55
|
onSignal?: () => void;
|
|
46
56
|
}
|
|
@@ -68,6 +78,7 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
68
78
|
denySignal: null,
|
|
69
79
|
redirectSignal: null,
|
|
70
80
|
renderError: null,
|
|
81
|
+
lastUnhandledError: null,
|
|
71
82
|
};
|
|
72
83
|
|
|
73
84
|
let rscStream: ReadableStream<Uint8Array> | undefined;
|
|
@@ -150,6 +161,11 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
150
161
|
// Only track as renderError if no Suspense boundary contains it —
|
|
151
162
|
// React will call onShellError for truly unrecoverable errors.
|
|
152
163
|
|
|
164
|
+
// Track the last unhandled error so the pipeline can use it
|
|
165
|
+
// if SSR fails (SsrStreamError). This is NOT used for page-level
|
|
166
|
+
// error detection — only as a fallback when SSR actually fails.
|
|
167
|
+
signals.lastUnhandledError = error;
|
|
168
|
+
|
|
153
169
|
// Return a digest so React emits a per-row error in the Flight
|
|
154
170
|
// stream instead of leaving the lazy reference unresolved.
|
|
155
171
|
//
|
|
@@ -337,10 +337,13 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
337
337
|
);
|
|
338
338
|
}
|
|
339
339
|
// No captured signal — unhandled error in the RSC stream.
|
|
340
|
-
//
|
|
341
|
-
|
|
340
|
+
// Use the lastUnhandledError from RSC onError if available (more
|
|
341
|
+
// reliable than extracting SsrStreamError.cause). Falls back to
|
|
342
|
+
// cause extraction for backward compatibility.
|
|
343
|
+
const originalError =
|
|
344
|
+
signals.lastUnhandledError ?? (ssrError as { cause?: unknown }).cause ?? ssrError;
|
|
342
345
|
return renderErrorPage(
|
|
343
|
-
|
|
346
|
+
originalError,
|
|
344
347
|
500,
|
|
345
348
|
segments,
|
|
346
349
|
layoutComponents as LayoutEntry[],
|
package/LICENSE
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
DONTFUCKINGUSE LICENSE
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Daniel Saewitz
|
|
4
|
-
|
|
5
|
-
This software may not be used, copied, modified, merged, published,
|
|
6
|
-
distributed, sublicensed, or sold by anyone other than the copyright holder.
|
|
7
|
-
|
|
8
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|