@timber-js/app 0.2.0-alpha.42 → 0.2.0-alpha.43
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot-resolver.d.ts","sourceRoot":"","sources":["../../src/server/slot-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"slot-resolver.d.ts","sourceRoot":"","sources":["../../src/server/slot-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,KAAK,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,YAAY,CAAC;AAkHlE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,UAAU,EACjB,CAAC,EAAE,eAAe,EAClB,YAAY,CAAC,EAAE,mBAAmB,GACjC,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAyFpC"}
|
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.43",
|
|
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",
|
|
@@ -22,6 +22,7 @@ import { SlotAccessGate } from './access-gate.js';
|
|
|
22
22
|
import { wrapSegmentWithErrorBoundaries } from './error-boundary-wrapper.js';
|
|
23
23
|
import type { InterceptionContext, RouteMatch } from './pipeline.js';
|
|
24
24
|
import { DenySignal } from './primitives.js';
|
|
25
|
+
import { logRenderError } from './logger.js';
|
|
25
26
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
26
27
|
|
|
27
28
|
type CreateElementFn = (...args: unknown[]) => React.ReactElement;
|
|
@@ -174,11 +175,19 @@ export async function resolveSlotElement(
|
|
|
174
175
|
// §"Slot Access Failure = Graceful Degradation"
|
|
175
176
|
const denyFallback = await renderDefaultFallback(slotNode, h);
|
|
176
177
|
|
|
177
|
-
// Wrap the slot page to catch
|
|
178
|
-
//
|
|
179
|
-
// RSC
|
|
180
|
-
//
|
|
181
|
-
//
|
|
178
|
+
// Wrap the slot page to catch ALL errors at the component level.
|
|
179
|
+
// This prevents errors from leaving unresolved Flight rows in the
|
|
180
|
+
// RSC stream — when a slot component throws and the error propagates
|
|
181
|
+
// to React's Flight renderer, it may not emit a resolution row for
|
|
182
|
+
// the slot's lazy reference. The client's createFromReadableStream
|
|
183
|
+
// then throws "Connection closed" when the stream ends with pending
|
|
184
|
+
// references. By catching all errors here and returning a fallback,
|
|
185
|
+
// React sees a resolved component and emits a proper Flight row.
|
|
186
|
+
//
|
|
187
|
+
// DenySignal (from notFound() or deny()) returns the deny fallback.
|
|
188
|
+
// All other errors return the deny fallback or null — the slot
|
|
189
|
+
// gracefully degrades rather than breaking the entire page.
|
|
190
|
+
// See TIM-524.
|
|
182
191
|
const SafeSlotPage = async (props: Record<string, unknown>) => {
|
|
183
192
|
try {
|
|
184
193
|
return await (SlotPage as (props: Record<string, unknown>) => unknown)(props);
|
|
@@ -186,7 +195,14 @@ export async function resolveSlotElement(
|
|
|
186
195
|
if (error instanceof DenySignal) {
|
|
187
196
|
return denyFallback;
|
|
188
197
|
}
|
|
189
|
-
throw
|
|
198
|
+
// Log the error but don't re-throw — returning fallback ensures
|
|
199
|
+
// the Flight row is resolved and the page hydrates correctly.
|
|
200
|
+
logRenderError({
|
|
201
|
+
method: '',
|
|
202
|
+
path: '',
|
|
203
|
+
error,
|
|
204
|
+
});
|
|
205
|
+
return denyFallback;
|
|
190
206
|
}
|
|
191
207
|
};
|
|
192
208
|
|