@timber-js/app 0.2.0-alpha.3 → 0.2.0-alpha.4
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/_chunks/{als-registry-k-AtAQ9R.js → als-registry-B7DbZ2hS.js} +1 -1
- package/dist/_chunks/{als-registry-k-AtAQ9R.js.map → als-registry-B7DbZ2hS.js.map} +1 -1
- package/dist/_chunks/debug-B4WUeqJ-.js +75 -0
- package/dist/_chunks/debug-B4WUeqJ-.js.map +1 -0
- package/dist/_chunks/{format-DNt20Kt8.js → format-CwdaB0_2.js} +3 -2
- package/dist/_chunks/format-CwdaB0_2.js.map +1 -0
- package/dist/_chunks/{interception-DGDIjDbR.js → interception-BOoWmLUA.js} +2 -2
- package/dist/_chunks/{interception-DGDIjDbR.js.map → interception-BOoWmLUA.js.map} +1 -1
- package/dist/_chunks/{metadata-routes-CQCnF4VK.js → metadata-routes-Cjmvi3rQ.js} +1 -1
- package/dist/_chunks/{metadata-routes-CQCnF4VK.js.map → metadata-routes-Cjmvi3rQ.js.map} +1 -1
- package/dist/_chunks/{request-context-CRj2Zh1E.js → request-context-CZJi4CuK.js} +5 -4
- package/dist/_chunks/request-context-CZJi4CuK.js.map +1 -0
- package/dist/_chunks/{ssr-data-DLnbYpj1.js → ssr-data-MjmprTmO.js} +1 -1
- package/dist/_chunks/{ssr-data-DLnbYpj1.js.map → ssr-data-MjmprTmO.js.map} +1 -1
- package/dist/_chunks/{tracing-DF0G3FB7.js → tracing-Cwn7697K.js} +2 -2
- package/dist/_chunks/{tracing-DF0G3FB7.js.map → tracing-Cwn7697K.js.map} +1 -1
- package/dist/_chunks/{use-cookie-dDbpCTx-.js → use-cookie-DX-l1_5E.js} +2 -2
- package/dist/_chunks/{use-cookie-dDbpCTx-.js.map → use-cookie-DX-l1_5E.js.map} +1 -1
- package/dist/_chunks/{use-query-states-DAhgj8Gx.js → use-query-states-D5KaffOK.js} +1 -1
- package/dist/_chunks/{use-query-states-DAhgj8Gx.js.map → use-query-states-D5KaffOK.js.map} +1 -1
- package/dist/cache/index.js +2 -2
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/index.js +3 -3
- package/dist/cookies/index.js +4 -4
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/build-report.d.ts +11 -1
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/search-params/index.js +1 -1
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/debug.d.ts +51 -0
- package/dist/server/debug.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-warnings.d.ts.map +1 -1
- package/dist/server/index.js +14 -13
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/response-cache.d.ts +53 -0
- package/dist/server/response-cache.d.ts.map +1 -0
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- 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/dist/server/rsc-prop-warnings.d.ts.map +1 -1
- package/dist/shims/image.d.ts +15 -15
- package/package.json +1 -1
- package/src/client/stale-reload.ts +1 -1
- package/src/index.ts +40 -0
- package/src/plugins/build-report.ts +23 -3
- package/src/plugins/entries.ts +2 -0
- package/src/plugins/server-bundle.ts +4 -0
- package/src/server/access-gate.tsx +3 -2
- package/src/server/action-client.ts +3 -2
- package/src/server/debug.ts +99 -0
- package/src/server/deny-renderer.ts +3 -2
- package/src/server/dev-warnings.ts +2 -1
- package/src/server/logger.ts +4 -3
- package/src/server/primitives.ts +2 -1
- package/src/server/request-context.ts +3 -2
- package/src/server/response-cache.ts +277 -0
- package/src/server/rsc-entry/index.ts +36 -9
- package/src/server/rsc-entry/rsc-payload.ts +4 -1
- package/src/server/rsc-entry/rsc-stream.ts +2 -1
- package/src/server/rsc-entry/ssr-renderer.ts +6 -2
- package/src/server/rsc-prop-warnings.ts +3 -1
- package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
- package/dist/_chunks/request-context-CRj2Zh1E.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1D;AAMD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,YAAY,GAAG,IAAI,CAE/C;AAsBD,4CAA4C;AAC5C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAEP;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE/E;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAEP;AAED,kDAAkD;AAClD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAEP;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM/F;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAQ3F;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM5D;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEnE;AAED,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEpF;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAMnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAS,GAAG,MAAM,GAAG,IAAI,CA8DhF;AAsBD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC;gBAEhC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB;IAOnD;;;;OAIG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAqBnC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,MAAY,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,KAAK,CASzE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAEhC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAIX;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM7C;AAKD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAWlE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAoB9F;AAID;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB;IAEjD,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAW,CACtB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB,CACjD,SAAQ,KAAK;IACb,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAcpE;AAID,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAqBrF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAID;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,KAAK;aAGrB,KAAK,EAAE,OAAO;gBAD9B,OAAO,EAAE,MAAM,EACC,KAAK,EAAE,OAAO;CAKjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAA8C,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render-level response deduplication and short-TTL LRU cache.
|
|
3
|
+
*
|
|
4
|
+
* Two layers of optimization:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Singleflight** — concurrent requests to the same URL share a single
|
|
7
|
+
* render. Uses createSingleflight() from cache/singleflight.ts.
|
|
8
|
+
*
|
|
9
|
+
* 2. **LRU cache** — recently rendered responses are reused without
|
|
10
|
+
* re-executing the RSC-to-SSR pipeline. Entries have a short TTL
|
|
11
|
+
* (default 5s) and the cache has a bounded size (default 150 entries).
|
|
12
|
+
*
|
|
13
|
+
* Cache keys are compound: method + pathname + isRscPayload. Responses
|
|
14
|
+
* with Set-Cookie headers are never cached (they contain user-specific
|
|
15
|
+
* state). When `publicOnly` is true (default), requests with Cookie or
|
|
16
|
+
* Authorization headers bypass the cache entirely.
|
|
17
|
+
*
|
|
18
|
+
* See design/02-rendering-pipeline.md, design/31-benchmarking.md.
|
|
19
|
+
*/
|
|
20
|
+
export interface ResponseCacheConfig {
|
|
21
|
+
/** Maximum number of entries in the LRU cache. Default: 150. */
|
|
22
|
+
maxSize?: number;
|
|
23
|
+
/** TTL for cached entries in milliseconds. Default: 5000 (5s). */
|
|
24
|
+
ttlMs?: number;
|
|
25
|
+
/**
|
|
26
|
+
* When true (default), requests with Cookie or Authorization headers
|
|
27
|
+
* bypass the cache entirely. This prevents sharing user-specific
|
|
28
|
+
* responses across requests.
|
|
29
|
+
*/
|
|
30
|
+
publicOnly?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface ResolvedResponseCacheConfig {
|
|
33
|
+
maxSize: number;
|
|
34
|
+
ttlMs: number;
|
|
35
|
+
publicOnly: boolean;
|
|
36
|
+
}
|
|
37
|
+
export declare function resolveResponseCacheConfig(config?: ResponseCacheConfig | false): ResolvedResponseCacheConfig | null;
|
|
38
|
+
export interface ResponseCache {
|
|
39
|
+
/**
|
|
40
|
+
* Wrap a render function with singleflight dedup + LRU caching.
|
|
41
|
+
* Returns the cached Response or executes the render function.
|
|
42
|
+
*/
|
|
43
|
+
getOrRender(req: Request, isRscPayload: boolean, renderFn: () => Promise<Response>): Promise<Response>;
|
|
44
|
+
/** Number of entries currently in the LRU cache. */
|
|
45
|
+
readonly size: number;
|
|
46
|
+
/** Clear all cached entries. */
|
|
47
|
+
clear(): void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a response cache with singleflight deduplication and LRU caching.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createResponseCache(config: ResolvedResponseCacheConfig): ResponseCache;
|
|
53
|
+
//# sourceMappingURL=response-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/server/response-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,CAAC,EAAE,mBAAmB,GAAG,KAAK,GACnC,2BAA2B,GAAG,IAAI,CASpC;AAoFD,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,WAAW,CACT,GAAG,EAAE,OAAO,EACZ,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAChC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,gCAAgC;IAChC,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,2BAA2B,GAAG,aAAa,CAqHtF"}
|
|
@@ -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":"AAgFA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AA8YD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;8BA7P3C,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA+PhD,wBAAiE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,CA0FnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAMjF;;;;;GAKG;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;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CA8G1F"}
|
|
@@ -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,4BAA4B,CAAC;AAGxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAYrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,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;CAC1B;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,4BAA4B,CAAC;AAGxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAYrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,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;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmKjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-prop-warnings.d.ts","sourceRoot":"","sources":["../../src/server/rsc-prop-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"rsc-prop-warnings.d.ts","sourceRoot":"","sources":["../../src/server/rsc-prop-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAkFD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAU9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAeR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAUrF"}
|
package/dist/shims/image.d.ts
CHANGED
|
@@ -51,17 +51,17 @@ export declare function Image({ priority: _priority, quality: _quality, fill: _f
|
|
|
51
51
|
autoCapitalize?: "off" | "none" | "on" | "sentences" | "words" | "characters" | undefined | (string & {});
|
|
52
52
|
autoFocus?: boolean | undefined;
|
|
53
53
|
className?: string | undefined;
|
|
54
|
-
contentEditable?: (boolean | "
|
|
54
|
+
contentEditable?: (boolean | "false" | "true") | "inherit" | "plaintext-only" | undefined;
|
|
55
55
|
contextMenu?: string | undefined;
|
|
56
56
|
dir?: string | undefined;
|
|
57
|
-
draggable?: (boolean | "
|
|
57
|
+
draggable?: (boolean | "false" | "true") | undefined;
|
|
58
58
|
enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined;
|
|
59
59
|
hidden?: boolean | undefined;
|
|
60
60
|
id?: string | undefined;
|
|
61
61
|
lang?: string | undefined;
|
|
62
62
|
nonce?: string | undefined;
|
|
63
63
|
slot?: string | undefined;
|
|
64
|
-
spellCheck?: (boolean | "
|
|
64
|
+
spellCheck?: (boolean | "false" | "true") | undefined;
|
|
65
65
|
style?: import("react").CSSProperties | undefined;
|
|
66
66
|
tabIndex?: number | undefined;
|
|
67
67
|
title?: string | undefined;
|
|
@@ -99,11 +99,11 @@ export declare function Image({ priority: _priority, quality: _quality, fill: _f
|
|
|
99
99
|
exportparts?: string | undefined;
|
|
100
100
|
part?: string | undefined;
|
|
101
101
|
"aria-activedescendant"?: string | undefined;
|
|
102
|
-
"aria-atomic"?: (boolean | "
|
|
102
|
+
"aria-atomic"?: (boolean | "false" | "true") | undefined;
|
|
103
103
|
"aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined;
|
|
104
104
|
"aria-braillelabel"?: string | undefined;
|
|
105
105
|
"aria-brailleroledescription"?: string | undefined;
|
|
106
|
-
"aria-busy"?: (boolean | "
|
|
106
|
+
"aria-busy"?: (boolean | "false" | "true") | undefined;
|
|
107
107
|
"aria-checked"?: boolean | "false" | "mixed" | "true" | undefined;
|
|
108
108
|
"aria-colcount"?: number | undefined;
|
|
109
109
|
"aria-colindex"?: number | undefined;
|
|
@@ -114,37 +114,37 @@ export declare function Image({ priority: _priority, quality: _quality, fill: _f
|
|
|
114
114
|
"aria-describedby"?: string | undefined;
|
|
115
115
|
"aria-description"?: string | undefined;
|
|
116
116
|
"aria-details"?: string | undefined;
|
|
117
|
-
"aria-disabled"?: (boolean | "
|
|
117
|
+
"aria-disabled"?: (boolean | "false" | "true") | undefined;
|
|
118
118
|
"aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined;
|
|
119
119
|
"aria-errormessage"?: string | undefined;
|
|
120
|
-
"aria-expanded"?: (boolean | "
|
|
120
|
+
"aria-expanded"?: (boolean | "false" | "true") | undefined;
|
|
121
121
|
"aria-flowto"?: string | undefined;
|
|
122
|
-
"aria-grabbed"?: (boolean | "
|
|
122
|
+
"aria-grabbed"?: (boolean | "false" | "true") | undefined;
|
|
123
123
|
"aria-haspopup"?: boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined;
|
|
124
|
-
"aria-hidden"?: (boolean | "
|
|
124
|
+
"aria-hidden"?: (boolean | "false" | "true") | undefined;
|
|
125
125
|
"aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined;
|
|
126
126
|
"aria-keyshortcuts"?: string | undefined;
|
|
127
127
|
"aria-label"?: string | undefined;
|
|
128
128
|
"aria-labelledby"?: string | undefined;
|
|
129
129
|
"aria-level"?: number | undefined;
|
|
130
130
|
"aria-live"?: "off" | "assertive" | "polite" | undefined;
|
|
131
|
-
"aria-modal"?: (boolean | "
|
|
132
|
-
"aria-multiline"?: (boolean | "
|
|
133
|
-
"aria-multiselectable"?: (boolean | "
|
|
131
|
+
"aria-modal"?: (boolean | "false" | "true") | undefined;
|
|
132
|
+
"aria-multiline"?: (boolean | "false" | "true") | undefined;
|
|
133
|
+
"aria-multiselectable"?: (boolean | "false" | "true") | undefined;
|
|
134
134
|
"aria-orientation"?: "horizontal" | "vertical" | undefined;
|
|
135
135
|
"aria-owns"?: string | undefined;
|
|
136
136
|
"aria-placeholder"?: string | undefined;
|
|
137
137
|
"aria-posinset"?: number | undefined;
|
|
138
138
|
"aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined;
|
|
139
|
-
"aria-readonly"?: (boolean | "
|
|
139
|
+
"aria-readonly"?: (boolean | "false" | "true") | undefined;
|
|
140
140
|
"aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined;
|
|
141
|
-
"aria-required"?: (boolean | "
|
|
141
|
+
"aria-required"?: (boolean | "false" | "true") | undefined;
|
|
142
142
|
"aria-roledescription"?: string | undefined;
|
|
143
143
|
"aria-rowcount"?: number | undefined;
|
|
144
144
|
"aria-rowindex"?: number | undefined;
|
|
145
145
|
"aria-rowindextext"?: string | undefined;
|
|
146
146
|
"aria-rowspan"?: number | undefined;
|
|
147
|
-
"aria-selected"?: (boolean | "
|
|
147
|
+
"aria-selected"?: (boolean | "false" | "true") | undefined;
|
|
148
148
|
"aria-setsize"?: number | undefined;
|
|
149
149
|
"aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined;
|
|
150
150
|
"aria-valuemax"?: number | undefined;
|
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.4",
|
|
4
4
|
"description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -29,7 +29,7 @@ const RELOAD_FLAG_KEY = '__timber_stale_reload';
|
|
|
29
29
|
export function isStaleClientReference(error: unknown): boolean {
|
|
30
30
|
if (!(error instanceof Error)) return false;
|
|
31
31
|
const msg = error.message;
|
|
32
|
-
return msg.includes('Could not find the module');
|
|
32
|
+
return msg.includes('Could not find the module') || msg.includes('client reference not found');
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
package/src/index.ts
CHANGED
|
@@ -46,6 +46,18 @@ export interface ResolvedClientJavascript {
|
|
|
46
46
|
|
|
47
47
|
export interface TimberUserConfig {
|
|
48
48
|
output?: 'server' | 'static';
|
|
49
|
+
/**
|
|
50
|
+
* Enable timber debug logging in production builds.
|
|
51
|
+
*
|
|
52
|
+
* When `true`, timber's own diagnostics (dev warnings, verbose logging)
|
|
53
|
+
* are active even in production mode. React stays in production mode —
|
|
54
|
+
* only timber's logs are affected.
|
|
55
|
+
*
|
|
56
|
+
* Can also be enabled at runtime via the `TIMBER_DEBUG` environment variable.
|
|
57
|
+
*
|
|
58
|
+
* Default: `false`.
|
|
59
|
+
*/
|
|
60
|
+
debug?: boolean;
|
|
49
61
|
/**
|
|
50
62
|
* Control client-side JavaScript output.
|
|
51
63
|
*
|
|
@@ -134,6 +146,34 @@ export interface TimberUserConfig {
|
|
|
134
146
|
/** CSS z-index. Default: 1600. */
|
|
135
147
|
zIndex?: number;
|
|
136
148
|
};
|
|
149
|
+
/**
|
|
150
|
+
* Response-level caching and deduplication.
|
|
151
|
+
*
|
|
152
|
+
* When enabled, concurrent requests to the same URL share a single render
|
|
153
|
+
* (singleflight), and recently rendered responses are reused from a short-TTL
|
|
154
|
+
* LRU cache without re-executing the RSC-to-SSR pipeline.
|
|
155
|
+
*
|
|
156
|
+
* Set to `false` to disable entirely. Default: enabled with sensible defaults.
|
|
157
|
+
*
|
|
158
|
+
* See design/31-benchmarking.md for performance context.
|
|
159
|
+
*/
|
|
160
|
+
responseCache?:
|
|
161
|
+
| false
|
|
162
|
+
| {
|
|
163
|
+
/** Maximum number of entries in the LRU cache. Default: 150. */
|
|
164
|
+
maxSize?: number;
|
|
165
|
+
/** TTL for cached entries in milliseconds. Default: 5000 (5s). */
|
|
166
|
+
ttlMs?: number;
|
|
167
|
+
/**
|
|
168
|
+
* When true (default), requests with Cookie or Authorization headers
|
|
169
|
+
* bypass the cache entirely. This prevents sharing user-specific
|
|
170
|
+
* responses across requests.
|
|
171
|
+
*
|
|
172
|
+
* Set to false to cache all responses regardless of auth state.
|
|
173
|
+
* Only do this if your pages are truly public and don't vary by user.
|
|
174
|
+
*/
|
|
175
|
+
publicOnly?: boolean;
|
|
176
|
+
};
|
|
137
177
|
}
|
|
138
178
|
|
|
139
179
|
/**
|
|
@@ -80,7 +80,17 @@ interface RouteInfo {
|
|
|
80
80
|
entryFilePath: string | null;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Walk the route tree and collect all leaf routes (pages + API endpoints).
|
|
85
|
+
*
|
|
86
|
+
* Parallel slots (`@artists`, `@shows`, etc.) are intentionally skipped —
|
|
87
|
+
* they render alongside the parent page at the same URL and are not
|
|
88
|
+
* separately URL-addressable. Their JS is captured in shared/layout chunks.
|
|
89
|
+
*
|
|
90
|
+
* After collection, entries are deduplicated by URL path so that overlapping
|
|
91
|
+
* route groups (e.g. `(browse)` and `(marketing)` both producing `/`) only
|
|
92
|
+
* appear once. The entry with the largest route-specific size wins.
|
|
93
|
+
*/
|
|
84
94
|
export function collectRoutes(tree: RouteTree): RouteInfo[] {
|
|
85
95
|
const routes: RouteInfo[] = [];
|
|
86
96
|
|
|
@@ -95,12 +105,22 @@ export function collectRoutes(tree: RouteTree): RouteInfo[] {
|
|
|
95
105
|
routes.push({ path, segments: currentChain, entryFilePath: node.route.filePath });
|
|
96
106
|
}
|
|
97
107
|
|
|
108
|
+
// Recurse into child segments only — skip parallel slots (node.slots)
|
|
98
109
|
for (const child of node.children) walk(child, currentChain);
|
|
99
|
-
for (const slot of node.slots.values()) walk(slot, currentChain);
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
walk(tree.root, []);
|
|
103
|
-
|
|
113
|
+
|
|
114
|
+
// Deduplicate entries with the same URL path (e.g. from overlapping route groups).
|
|
115
|
+
// Keep the entry with the longest segment chain (most specific match).
|
|
116
|
+
const seen = new Map<string, RouteInfo>();
|
|
117
|
+
for (const route of routes) {
|
|
118
|
+
const existing = seen.get(route.path);
|
|
119
|
+
if (!existing || route.segments.length > existing.segments.length) {
|
|
120
|
+
seen.set(route.path, route);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return Array.from(seen.values());
|
|
104
124
|
}
|
|
105
125
|
|
|
106
126
|
// ─── Report formatting ────────────────────────────────────────────────────
|
package/src/plugins/entries.ts
CHANGED
|
@@ -110,6 +110,8 @@ function generateConfigModule(ctx: PluginContext): string {
|
|
|
110
110
|
slowRequestMs: ctx.config.slowRequestMs ?? 3000,
|
|
111
111
|
cookieSecrets,
|
|
112
112
|
topLoader: ctx.config.topLoader,
|
|
113
|
+
responseCache: ctx.config.responseCache,
|
|
114
|
+
debug: ctx.config.debug ?? false,
|
|
113
115
|
};
|
|
114
116
|
|
|
115
117
|
return [
|
|
@@ -65,6 +65,10 @@ export function timberServerBundle(): Plugin[] {
|
|
|
65
65
|
// eliminated by Rollup's tree-shaking. Without this, the runtime
|
|
66
66
|
// check falls through on platforms where process.env is empty
|
|
67
67
|
// (e.g. Cloudflare Workers), causing dev code to run in production.
|
|
68
|
+
// Define process.env.NODE_ENV so dev-only React code is tree-shaken.
|
|
69
|
+
// TIMBER_DEBUG is intentionally NOT defined here — it must remain a
|
|
70
|
+
// runtime check so `isDebug()` in server/debug.ts can read it at
|
|
71
|
+
// request time. See TIM-365.
|
|
68
72
|
const serverDefine = {
|
|
69
73
|
'process.env.NODE_ENV': JSON.stringify('production'),
|
|
70
74
|
};
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { DenySignal, RedirectSignal } from './primitives.js';
|
|
17
17
|
import type { AccessGateProps, SlotAccessGateProps, ReactElement } from './tree-builder.js';
|
|
18
18
|
import { withSpan, setSpanAttribute } from './tracing.js';
|
|
19
|
+
import { isDebug } from './debug.js';
|
|
19
20
|
|
|
20
21
|
// ─── AccessGate ─────────────────────────────────────────────────────────────
|
|
21
22
|
|
|
@@ -114,7 +115,7 @@ export async function SlotAccessGate(props: SlotAccessGateProps): Promise<ReactE
|
|
|
114
115
|
// slot would redirect the entire page, which breaks the contract that
|
|
115
116
|
// slot failure is graceful degradation.
|
|
116
117
|
if (error instanceof RedirectSignal) {
|
|
117
|
-
if (
|
|
118
|
+
if (isDebug()) {
|
|
118
119
|
console.error(
|
|
119
120
|
'[timber] redirect() is not allowed in slot access.ts. ' +
|
|
120
121
|
'Slots use deny() for graceful degradation — denied.tsx → default.tsx → null. ' +
|
|
@@ -127,7 +128,7 @@ export async function SlotAccessGate(props: SlotAccessGateProps): Promise<ReactE
|
|
|
127
128
|
|
|
128
129
|
// Unhandled error — re-throw so error boundaries can catch it.
|
|
129
130
|
// Dev-mode warning: slot access should use deny(), not throw.
|
|
130
|
-
if (
|
|
131
|
+
if (isDebug()) {
|
|
131
132
|
console.warn(
|
|
132
133
|
'[timber] Unhandled error in slot access.ts. ' +
|
|
133
134
|
'Use deny() for access control, not unhandled throws.',
|
|
@@ -184,6 +184,7 @@ async function runActionMiddleware<TCtx>(
|
|
|
184
184
|
// Re-export parseFormData for use throughout the framework
|
|
185
185
|
import { parseFormData } from './form-data.js';
|
|
186
186
|
import { formatSize } from '#/utils/format.js';
|
|
187
|
+
import { isDebug } from './debug.js';
|
|
187
188
|
|
|
188
189
|
/**
|
|
189
190
|
* Extract validation errors from a schema error.
|
|
@@ -247,7 +248,7 @@ export function handleActionError(error: unknown): ActionResult<never> {
|
|
|
247
248
|
}
|
|
248
249
|
|
|
249
250
|
// In dev, include the message for debugging
|
|
250
|
-
const isDev =
|
|
251
|
+
const isDev = isDebug();
|
|
251
252
|
return {
|
|
252
253
|
serverError: {
|
|
253
254
|
code: 'INTERNAL_ERROR',
|
|
@@ -413,7 +414,7 @@ export function validated<TInput, TData>(
|
|
|
413
414
|
* In production, validation errors are only returned to the client.
|
|
414
415
|
*/
|
|
415
416
|
function logValidationFailure(errors: ValidationErrors): void {
|
|
416
|
-
const isDev =
|
|
417
|
+
const isDev = isDebug();
|
|
417
418
|
if (!isDev) return;
|
|
418
419
|
|
|
419
420
|
const fields = Object.entries(errors)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime debug flag for timber.js.
|
|
3
|
+
*
|
|
4
|
+
* Provides `isDebug()` — a runtime check that returns true when timber's
|
|
5
|
+
* debug/warning logging should be active. This is true in two cases:
|
|
6
|
+
*
|
|
7
|
+
* 1. Development mode: `process.env.NODE_ENV !== 'production'`
|
|
8
|
+
* (statically replaced and tree-shaken in production builds — zero cost)
|
|
9
|
+
*
|
|
10
|
+
* 2. TIMBER_DEBUG flag: A runtime environment variable that survives
|
|
11
|
+
* production builds. When set to any truthy value ("1", "true", etc.),
|
|
12
|
+
* timber's own diagnostics are re-enabled without affecting React's mode.
|
|
13
|
+
*
|
|
14
|
+
* The TIMBER_DEBUG check uses a dynamic property access pattern that
|
|
15
|
+
* prevents the bundler from statically replacing or eliminating it.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* In Cloudflare Workers wrangler.toml:
|
|
19
|
+
* [vars]
|
|
20
|
+
* TIMBER_DEBUG = "1"
|
|
21
|
+
*
|
|
22
|
+
* In Node.js:
|
|
23
|
+
* TIMBER_DEBUG=1 node server.js
|
|
24
|
+
*
|
|
25
|
+
* In timber.config.ts:
|
|
26
|
+
* export default { debug: true }
|
|
27
|
+
*
|
|
28
|
+
* See design/18-build-system.md for build pipeline details.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// ─── Debug Flag ─────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Config-level debug override. Set via `setDebugFromConfig()` during
|
|
35
|
+
* initialization when timber.config.ts has `debug: true`.
|
|
36
|
+
*/
|
|
37
|
+
let _configDebug = false;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Set the debug flag from timber.config.ts.
|
|
41
|
+
* Called during handler initialization.
|
|
42
|
+
*/
|
|
43
|
+
export function setDebugFromConfig(debug: boolean): void {
|
|
44
|
+
_configDebug = debug;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if timber debug logging is active.
|
|
49
|
+
*
|
|
50
|
+
* Returns true if ANY of these conditions hold:
|
|
51
|
+
* - NODE_ENV is not 'production' (standard dev mode)
|
|
52
|
+
* - TIMBER_DEBUG environment variable is set to a truthy value at runtime
|
|
53
|
+
* - timber.config.ts has `debug: true`
|
|
54
|
+
*
|
|
55
|
+
* The TIMBER_DEBUG check is deliberately written as a dynamic property
|
|
56
|
+
* access so bundlers cannot statically replace it. The `_envKey` variable
|
|
57
|
+
* prevents the bundler from seeing `process.env.TIMBER_DEBUG` as a
|
|
58
|
+
* compile-time constant.
|
|
59
|
+
*
|
|
60
|
+
* This function is intentionally NOT inlineable — it reads runtime state.
|
|
61
|
+
*/
|
|
62
|
+
export function isDebug(): boolean {
|
|
63
|
+
// Fast path: dev mode (statically replaced to `true` in dev, `false` in prod)
|
|
64
|
+
if (process.env.NODE_ENV !== 'production') return true;
|
|
65
|
+
|
|
66
|
+
// Config override
|
|
67
|
+
if (_configDebug) return true;
|
|
68
|
+
|
|
69
|
+
// Runtime env var check — uses dynamic access to prevent static replacement.
|
|
70
|
+
// In production builds, process.env.NODE_ENV is statically replaced, but
|
|
71
|
+
// TIMBER_DEBUG must survive as a runtime check. The dynamic key access
|
|
72
|
+
// pattern ensures the bundler treats this as opaque.
|
|
73
|
+
return _readTimberDebugEnv();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Read TIMBER_DEBUG from the environment at runtime.
|
|
78
|
+
*
|
|
79
|
+
* Extracted to a separate function to:
|
|
80
|
+
* 1. Prevent bundler inlining (cross-module function calls are not inlined)
|
|
81
|
+
* 2. Handle platforms where `process` may not exist (Cloudflare Workers)
|
|
82
|
+
* 3. Support globalThis.__TIMBER_DEBUG for programmatic control
|
|
83
|
+
*/
|
|
84
|
+
function _readTimberDebugEnv(): boolean {
|
|
85
|
+
// globalThis override — useful for programmatic control and testing
|
|
86
|
+
if ((globalThis as Record<string, unknown>).__TIMBER_DEBUG) return true;
|
|
87
|
+
|
|
88
|
+
// process.env — works in Node.js and platforms that polyfill process
|
|
89
|
+
try {
|
|
90
|
+
const key = 'TIMBER_DEBUG';
|
|
91
|
+
const val =
|
|
92
|
+
typeof process !== 'undefined' && process.env ? (process.env as Record<string, string | undefined>)[key] : undefined;
|
|
93
|
+
if (val && val !== '0' && val !== 'false') return true;
|
|
94
|
+
} catch {
|
|
95
|
+
// process may not exist or env may throw — safe to ignore
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
@@ -20,6 +20,7 @@ import { renderToReadableStream } from '#/rsc-runtime/rsc.js';
|
|
|
20
20
|
|
|
21
21
|
import { DenySignal } from './primitives.js';
|
|
22
22
|
import { logRenderError } from './logger.js';
|
|
23
|
+
import { isDebug } from './debug.js';
|
|
23
24
|
import { resolveMetadata, renderMetadataToElements } from './metadata.js';
|
|
24
25
|
import { resolveManifestStatusFile } from './manifest-status-resolver.js';
|
|
25
26
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
@@ -94,7 +95,7 @@ export async function renderDenyPage(
|
|
|
94
95
|
|
|
95
96
|
// Dev warning: JSON status file exists but is shadowed by the component chain.
|
|
96
97
|
// This helps developers understand why their .json file isn't being served.
|
|
97
|
-
if (
|
|
98
|
+
if (isDebug()) {
|
|
98
99
|
const jsonResolution = resolveManifestStatusFile(deny.status, segments, 'json');
|
|
99
100
|
if (jsonResolution) {
|
|
100
101
|
console.warn(
|
|
@@ -133,7 +134,7 @@ export async function renderDenyPage(
|
|
|
133
134
|
const { component } = layoutsToWrap[i];
|
|
134
135
|
element = h(component, null, element);
|
|
135
136
|
}
|
|
136
|
-
} else if (
|
|
137
|
+
} else if (isDebug()) {
|
|
137
138
|
// Dev-mode: warn if shell=false might conflict with Suspense
|
|
138
139
|
// The actual Suspense boundary check happens at render time in the pipeline.
|
|
139
140
|
// This is a preemptive log for developer awareness.
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { ViteDevServer } from 'vite';
|
|
18
|
+
import { isDebug } from './debug.js';
|
|
18
19
|
|
|
19
20
|
// ─── Warning IDs ───────────────────────────────────────────────────────────
|
|
20
21
|
|
|
@@ -54,7 +55,7 @@ export function setViteServer(server: ViteDevServer | null): void {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
function isDev(): boolean {
|
|
57
|
-
return
|
|
58
|
+
return isDebug();
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/**
|
package/src/server/logger.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { getTraceStore } from './tracing.js';
|
|
12
12
|
import { formatSsrError } from './error-formatter.js';
|
|
13
|
+
import { isDebug } from './debug.js';
|
|
13
14
|
|
|
14
15
|
// ─── Logger Interface ─────────────────────────────────────────────────────
|
|
15
16
|
|
|
@@ -103,7 +104,7 @@ export function logMiddlewareShortCircuit(data: {
|
|
|
103
104
|
export function logMiddlewareError(data: { method: string; path: string; error: unknown }): void {
|
|
104
105
|
if (_logger) {
|
|
105
106
|
_logger.error('unhandled error in middleware phase', withTraceContext(data));
|
|
106
|
-
} else if (
|
|
107
|
+
} else if (isDebug()) {
|
|
107
108
|
console.error('[timber] middleware error', data.error);
|
|
108
109
|
}
|
|
109
110
|
}
|
|
@@ -112,7 +113,7 @@ export function logMiddlewareError(data: { method: string; path: string; error:
|
|
|
112
113
|
export function logRenderError(data: { method: string; path: string; error: unknown }): void {
|
|
113
114
|
if (_logger) {
|
|
114
115
|
_logger.error('unhandled render-phase error', withTraceContext(data));
|
|
115
|
-
} else if (
|
|
116
|
+
} else if (isDebug()) {
|
|
116
117
|
// No logger configured — fall back to console.error in dev with
|
|
117
118
|
// cleaned-up error messages (vendor paths rewritten, hints added).
|
|
118
119
|
console.error('[timber] render error:', formatSsrError(data.error));
|
|
@@ -123,7 +124,7 @@ export function logRenderError(data: { method: string; path: string; error: unkn
|
|
|
123
124
|
export function logProxyError(data: { error: unknown }): void {
|
|
124
125
|
if (_logger) {
|
|
125
126
|
_logger.error('proxy.ts threw uncaught error', withTraceContext(data));
|
|
126
|
-
} else if (
|
|
127
|
+
} else if (isDebug()) {
|
|
127
128
|
console.error('[timber] proxy error', data.error);
|
|
128
129
|
}
|
|
129
130
|
}
|
package/src/server/primitives.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { JsonSerializable } from './types.js';
|
|
7
7
|
import { getWaitUntil as _getWaitUntil } from './waituntil-bridge.js';
|
|
8
|
+
import { isDebug } from './debug.js';
|
|
8
9
|
|
|
9
10
|
// ─── Dev-mode validation ────────────────────────────────────────────────────
|
|
10
11
|
|
|
@@ -83,7 +84,7 @@ export function findNonSerializable(value: unknown, path = 'data'): string | nul
|
|
|
83
84
|
* No-op in production.
|
|
84
85
|
*/
|
|
85
86
|
function warnIfNotSerializable(data: unknown, callerName: string): void {
|
|
86
|
-
if (
|
|
87
|
+
if (!isDebug()) return;
|
|
87
88
|
if (data === undefined) return;
|
|
88
89
|
|
|
89
90
|
const issue = findNonSerializable(data);
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
14
14
|
import type { Routes } from '#/index.js';
|
|
15
15
|
import { requestContextAls, type RequestContextStore, type CookieEntry } from './als-registry.js';
|
|
16
|
+
import { isDebug } from './debug.js';
|
|
16
17
|
|
|
17
18
|
// Re-export the ALS for framework-internal consumers that need direct access.
|
|
18
19
|
export { requestContextAls };
|
|
@@ -117,7 +118,7 @@ export function cookies(): RequestCookies {
|
|
|
117
118
|
set(name: string, value: string, options?: CookieOptions): void {
|
|
118
119
|
assertMutable(store, 'set');
|
|
119
120
|
if (store.flushed) {
|
|
120
|
-
if (
|
|
121
|
+
if (isDebug()) {
|
|
121
122
|
console.warn(
|
|
122
123
|
`[timber] warn: cookies().set('${name}') called after response headers were committed.\n` +
|
|
123
124
|
` The cookie will NOT be sent. Move cookie mutations to middleware.ts, a server action,\n` +
|
|
@@ -146,7 +147,7 @@ export function cookies(): RequestCookies {
|
|
|
146
147
|
delete(name: string, options?: Pick<CookieOptions, 'path' | 'domain'>): void {
|
|
147
148
|
assertMutable(store, 'delete');
|
|
148
149
|
if (store.flushed) {
|
|
149
|
-
if (
|
|
150
|
+
if (isDebug()) {
|
|
150
151
|
console.warn(
|
|
151
152
|
`[timber] warn: cookies().delete('${name}') called after response headers were committed.\n` +
|
|
152
153
|
` The cookie will NOT be deleted. Move cookie mutations to middleware.ts, a server action,\n` +
|