@timber-js/app 0.2.0-alpha.163 → 0.2.0-alpha.164
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/{actions-cjklt63G.js → actions-CSDD6x7U.js} +2 -2
- package/dist/_chunks/{actions-cjklt63G.js.map → actions-CSDD6x7U.js.map} +1 -1
- package/dist/_chunks/{cache-api-CzYUlgXA.js → cache-api-eb1gydM7.js} +41 -13
- package/dist/_chunks/cache-api-eb1gydM7.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync-NfLbLnDw.js → cli-schema-sync-mGfRbjh2.js} +2 -2
- package/dist/_chunks/{cli-schema-sync-NfLbLnDw.js.map → cli-schema-sync-mGfRbjh2.js.map} +1 -1
- package/dist/_chunks/{plugin-context-DeAxFRMq.js → plugin-context-BnaiU_cF.js} +37 -2
- package/dist/_chunks/plugin-context-BnaiU_cF.js.map +1 -0
- package/dist/_chunks/{walkers-9mz9T7mb.js → walkers-BL3MCMgO.js} +2 -2
- package/dist/_chunks/{walkers-9mz9T7mb.js.map → walkers-BL3MCMgO.js.map} +1 -1
- package/dist/adapters/cloudflare-kv-cache.d.ts +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -1
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
- package/dist/adapters/nitro.d.ts +11 -0
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +77 -64
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/index.d.ts +3 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cache/redis-handler.d.ts +1 -0
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/tag-aware-handler.d.ts +1 -0
- package/dist/cache/tag-aware-handler.d.ts.map +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/client/slot-context.d.ts +29 -0
- package/dist/client/slot-context.d.ts.map +1 -0
- package/dist/client/slot-outlet.d.ts +16 -0
- package/dist/client/slot-outlet.d.ts.map +1 -0
- package/dist/client/slot-provider.d.ts +20 -0
- package/dist/client/slot-provider.d.ts.map +1 -0
- package/dist/config-types.d.ts +2 -1
- package/dist/config-types.d.ts.map +1 -1
- package/dist/dev-tools/logs.d.ts.map +1 -1
- package/dist/index.js +293 -124
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +27 -0
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/cache.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/prebuilt-options-analysis.d.ts +40 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts.map +1 -0
- package/dist/plugins/prebuilt.d.ts.map +1 -1
- package/dist/plugins/prerender-sugar.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/server/html-injector-core.d.ts +30 -9
- package/dist/server/html-injector-core.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/internal.js +346 -51
- package/dist/server/internal.js.map +1 -1
- package/dist/server/node-stream-transforms.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/prebuilt/cache-key.d.ts +4 -0
- package/dist/server/prebuilt/cache-key.d.ts.map +1 -1
- package/dist/server/prebuilt/key-discipline.d.ts +23 -0
- package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +74 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts.map +1 -1
- package/dist/server/prebuilt-runtime.d.ts +12 -2
- package/dist/server/prebuilt-runtime.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +29 -0
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/docs/api/34-api-config.mdx +165 -3
- package/docs/learn/00-introduction.mdx +78 -44
- package/docs/learn/13-configuration.mdx +27 -8
- package/package.json +3 -2
- package/src/adapters/cloudflare-kv-cache.ts +5 -1
- package/src/adapters/nitro.ts +82 -64
- package/src/cache/index.ts +25 -2
- package/src/cache/redis-handler.ts +27 -7
- package/src/cache/tag-aware-handler.ts +5 -1
- package/src/cache/timber-cache.ts +21 -10
- package/src/client/slot-context.ts +48 -0
- package/src/client/slot-outlet.tsx +22 -0
- package/src/client/slot-provider.tsx +25 -0
- package/src/config-types.ts +2 -1
- package/src/dev-tools/logs.ts +7 -0
- package/src/plugin-context.ts +54 -0
- package/src/plugins/cache.ts +1 -2
- package/src/plugins/client-chunks.ts +42 -1
- package/src/plugins/dev-server.ts +12 -69
- package/src/plugins/prebuilt-options-analysis.ts +175 -0
- package/src/plugins/prebuilt.ts +82 -127
- package/src/plugins/prerender-sugar.ts +1 -2
- package/src/server/html-injector-core.ts +85 -27
- package/src/server/html-injectors.ts +5 -1
- package/src/server/node-stream-transforms.ts +6 -1
- package/src/server/pipeline-phases.ts +4 -1
- package/src/server/prebuilt/cache-key.ts +74 -0
- package/src/server/prebuilt/key-discipline.ts +53 -0
- package/src/server/prebuilt/slots.ts +167 -0
- package/src/server/prebuilt-builder.ts +57 -23
- package/src/server/prebuilt-runtime.ts +144 -60
- package/src/server/rsc-entry/deny-fallback.ts +92 -0
- package/src/server/rsc-entry/index.ts +16 -70
- package/dist/_chunks/cache-api-CzYUlgXA.js.map +0 -1
- package/dist/_chunks/plugin-context-DeAxFRMq.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-stream-transforms.d.ts","sourceRoot":"","sources":["../../src/server/node-stream-transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGpE,OAAO,EAGL,YAAY,EAOb,MAAM,yBAAyB,CAAC;AAOjC,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,SAAS,CA2BjG;AAID;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,SAAS,
|
|
1
|
+
{"version":3,"file":"node-stream-transforms.d.ts","sourceRoot":"","sources":["../../src/server/node-stream-transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGpE,OAAO,EAGL,YAAY,EAOb,MAAM,yBAAyB,CAAC;AAOjC,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,SAAS,CA2BjG;AAID;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,SAAS,CAyBzD;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC;AAIxB;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CA2BlE;AAID;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,EACjD,OAAO,CAAC,EAAE,yBAAyB,GAClC,SAAS,CAiEX;AAID;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,SAAS,CAAC,SAAS,EAAE,GAAG,SAAS,EAAE,CAAC,EAChD,MAAM,CAAC,EAAE,WAAW,GACnB,WAAW,CAgCb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,QAAQ,CAAC,CAmTnB"}
|
|
@@ -47,6 +47,10 @@
|
|
|
47
47
|
* bigints, …) live in exactly one place.
|
|
48
48
|
*/
|
|
49
49
|
export declare function tryCanonicalize(value: unknown): string | null;
|
|
50
|
+
export declare function splitSlotProps(props: Record<string, unknown>, slots: readonly string[]): {
|
|
51
|
+
dataProps: Record<string, unknown>;
|
|
52
|
+
slotValues: Record<string, unknown>;
|
|
53
|
+
} | null;
|
|
50
54
|
/**
|
|
51
55
|
* Compute the cache-entry hash for a component render:
|
|
52
56
|
* `sha256({props, params}).slice(0, 16)` over canonical JSON.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-key.d.ts","sourceRoot":"","sources":["../../../src/server/prebuilt/cache-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAwGH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAM7D;
|
|
1
|
+
{"version":3,"file":"cache-key.d.ts","sourceRoot":"","sources":["../../../src/server/prebuilt/cache-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAwGH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAM7D;AAsDD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB;IAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,CAqCpF;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACxC,MAAM,GAAG,IAAI,CAkCf"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key-discipline diagnostic for cache.component (design/45 §Enforcement).
|
|
3
|
+
*
|
|
4
|
+
* Runtime-tier cached components MAY read request context, but the cache
|
|
5
|
+
* key is computed from props and segment params only — request-derived
|
|
6
|
+
* values in cached output are the data-leak danger zone (design/06
|
|
7
|
+
* security note). During a capture render the ALS store is wrapped in a
|
|
8
|
+
* transparent observing proxy; any request-context read produces a
|
|
9
|
+
* once-per-component warning.
|
|
10
|
+
*/
|
|
11
|
+
import type { RequestContextStore } from '../als-registry.js';
|
|
12
|
+
/** Components already warned — exported so tests can reset between cases. */
|
|
13
|
+
export declare const keyDisciplineWarned: Set<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Wrap a store with a proxy that records per-request field access.
|
|
16
|
+
* The proxy forwards all reads/writes transparently — it only observes.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createKeyDisciplineProxy(store: RequestContextStore): {
|
|
19
|
+
proxy: RequestContextStore;
|
|
20
|
+
accessedApis: Set<string>;
|
|
21
|
+
};
|
|
22
|
+
export declare function emitKeyDisciplineWarning(id: string, apis: Set<string>): void;
|
|
23
|
+
//# sourceMappingURL=key-discipline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-discipline.d.ts","sourceRoot":"","sources":["../../../src/server/prebuilt/key-discipline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,aAAoB,CAAC;AAQrD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG;IACpE,KAAK,EAAE,mBAAmB,CAAC;IAC3B,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B,CAUA;AAED,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAW5E"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slot-component helpers for cache.component (TIM-1173).
|
|
3
|
+
*
|
|
4
|
+
* A `slots: ['children', ...]` declaration caches the component's output
|
|
5
|
+
* as a shell with a stable <SlotOutlet slot={name} /> client-reference
|
|
6
|
+
* hole per declared slot prop; live slot content composes in per instance
|
|
7
|
+
* at request time via SlotsProvider/SlotContext. This generalizes the
|
|
8
|
+
* TIM-1181 layout mechanism (ChildSegmentOutlet) to explicitly declared,
|
|
9
|
+
* named slots on any cached component.
|
|
10
|
+
*
|
|
11
|
+
* Both the production wrapper (cache path) and the dev wrapper (no cache,
|
|
12
|
+
* same tree shape for dev/prod parity) build their render from these
|
|
13
|
+
* helpers. See design/45-cache-lifetimes.md §Slot Components.
|
|
14
|
+
*/
|
|
15
|
+
import type { PrebuiltComponentOptions } from '../prebuilt-runtime.js';
|
|
16
|
+
/**
|
|
17
|
+
* Is this value the framework-injected `<ChildSegmentOutlet />` element?
|
|
18
|
+
* Total: the `in` probe and `.type` read run against a user-controlled
|
|
19
|
+
* value, and a Proxy trap can throw — that must classify as "not the
|
|
20
|
+
* outlet" (the canonicalizer then rejects the value as unkeyable → live
|
|
21
|
+
* render), not abort the request (codex P2 on PR #890).
|
|
22
|
+
*/
|
|
23
|
+
export declare function isChildSegmentOutletElement(value: unknown): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Outcome of validating a `slots` declaration at registration time.
|
|
26
|
+
*
|
|
27
|
+
* - `none` — not declared (or an empty array): plain non-slot component.
|
|
28
|
+
* - `disabled` — declared but unusable (malformed shape, or missing the
|
|
29
|
+
* required runtime lifetime): warned once here (module load); the
|
|
30
|
+
* component falls back WHOLESALE to non-slot semantics — the caller
|
|
31
|
+
* strips `slots` from the options and every other option (including
|
|
32
|
+
* `prerender`) keeps its normal meaning. Safe by construction:
|
|
33
|
+
* element-valued props are unkeyable on the non-slot path, so renders
|
|
34
|
+
* with slot content go live. Slower, never wrong.
|
|
35
|
+
* - `active` — usable slot names.
|
|
36
|
+
*/
|
|
37
|
+
export type SlotResolution = {
|
|
38
|
+
kind: 'none' | 'disabled';
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'active';
|
|
41
|
+
slots: string[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Validate the `slots` option. Both the production and dev wrappers gate
|
|
45
|
+
* on this — slot substitution is active in dev exactly when it would be
|
|
46
|
+
* active in production, so the tree shape a component sees never
|
|
47
|
+
* diverges between the two.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveSlotNames(id: string, options: PrebuiltComponentOptions): SlotResolution;
|
|
50
|
+
export interface SlotRender {
|
|
51
|
+
/** Props the shell renders with: data props + a SlotOutlet per slot. */
|
|
52
|
+
shellProps: Record<string, unknown>;
|
|
53
|
+
/** Non-slot props — the only props that participate in the cache key. */
|
|
54
|
+
dataProps: Record<string, unknown>;
|
|
55
|
+
/** Live slot content, keyed by slot name, for the SlotsProvider. */
|
|
56
|
+
slotValues: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Split the live props into the cacheable shell render (data props plus a
|
|
60
|
+
* deterministic SlotOutlet placeholder per declared slot — identical
|
|
61
|
+
* whether or not the caller passed the slot) and the per-instance live
|
|
62
|
+
* slot values.
|
|
63
|
+
*
|
|
64
|
+
* Null when the props object itself is unkeyable at the top level
|
|
65
|
+
* (accessors, hidden properties, exotic prototype — see splitSlotProps):
|
|
66
|
+
* the caller must render live with the original props.
|
|
67
|
+
*/
|
|
68
|
+
export declare function prepareSlotRender(props: Record<string, unknown>, slots: readonly string[]): SlotRender | null;
|
|
69
|
+
/**
|
|
70
|
+
* Wrap a rendered shell (revived payload or live element) in a
|
|
71
|
+
* per-instance SlotsProvider feeding the live values to its outlets.
|
|
72
|
+
*/
|
|
73
|
+
export declare function wrapInSlotsProvider(shell: unknown, slotValues: Record<string, unknown>): React.ReactElement;
|
|
74
|
+
//# sourceMappingURL=slots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/server/prebuilt/slots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEvE;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWnE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAqBjG;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,cAAc,CA0B9F;AAED,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,UAAU,GAAG,IAAI,CAiBnB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,KAAK,CAAC,YAAY,CAMpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prebuilt-builder.d.ts","sourceRoot":"","sources":["../../src/server/prebuilt-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAuBH,OAAO,KAAK,EAAgB,YAAY,EAAuB,MAAM,oBAAoB,CAAC;AAO1F,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,UAAU,CAAC;IAClB,gGAAgG;IAChG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,mEAAmE;IACnE,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,qEAAqE;IACrE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1D;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;
|
|
1
|
+
{"version":3,"file":"prebuilt-builder.d.ts","sourceRoot":"","sources":["../../src/server/prebuilt-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAuBH,OAAO,KAAK,EAAgB,YAAY,EAAuB,MAAM,oBAAoB,CAAC;AAO1F,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,UAAU,CAAC;IAClB,gGAAgG;IAChG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,mEAAmE;IACnE,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,qEAAqE;IACrE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1D;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAqVD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CA2TzB"}
|
|
@@ -53,6 +53,17 @@ export interface PrebuiltComponentOptions {
|
|
|
53
53
|
tags?: string[] | ((props: Record<string, unknown>) => string[]);
|
|
54
54
|
/** Serve stale while a background re-render refreshes (design/45 §SWR). */
|
|
55
55
|
staleWhileRevalidate?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Slot props (TIM-1173): prop names whose values are live React
|
|
58
|
+
* elements composed into the cached shell at request time instead of
|
|
59
|
+
* participating in the cache. Each declared slot renders as a stable
|
|
60
|
+
* SlotOutlet client reference at capture time; the live value flows in
|
|
61
|
+
* through SlotContext per instance. Slot props are excluded from the
|
|
62
|
+
* cache key — only the remaining data props (+ segment params) hash.
|
|
63
|
+
* Runtime tier only: `prerender` is ignored (with a warning) because
|
|
64
|
+
* the build cannot enumerate children variants.
|
|
65
|
+
*/
|
|
66
|
+
slots?: string[];
|
|
56
67
|
/**
|
|
57
68
|
* On a cache miss, render the component live (default: true). When false,
|
|
58
69
|
* a miss throws instead — for sites that must never render unknown params
|
|
@@ -78,7 +89,6 @@ interface RscFunctions {
|
|
|
78
89
|
* startup from the RSC entry module.
|
|
79
90
|
*/
|
|
80
91
|
export declare function setRscFunctions(fns: RscFunctions): void;
|
|
81
|
-
export declare const keyDisciplineWarned: Set<string>;
|
|
82
92
|
/**
|
|
83
93
|
* Production wrapper injected by the timber-prebuilt transform. Registers
|
|
84
94
|
* the component under its stable ID and returns a wrapper component that
|
|
@@ -96,6 +106,6 @@ export declare function getPrebuiltRegistry(): ReadonlyMap<string, PrebuiltRegis
|
|
|
96
106
|
* component on first render so the production behavior difference is visible.
|
|
97
107
|
* See design/44 §Dev Mode.
|
|
98
108
|
*/
|
|
99
|
-
export declare function __prebuiltDev<C extends ServerComponent>(name: string, component: C,
|
|
109
|
+
export declare function __prebuiltDev<C extends ServerComponent>(name: string, component: C, options?: PrebuiltComponentOptions): C;
|
|
100
110
|
export {};
|
|
101
111
|
//# sourceMappingURL=prebuilt-runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prebuilt-runtime.d.ts","sourceRoot":"","sources":["../../src/server/prebuilt-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;
|
|
1
|
+
{"version":3,"file":"prebuilt-runtime.d.ts","sourceRoot":"","sources":["../../src/server/prebuilt-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AA6CH;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAGlE;AAID;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;IACjE,2EAA2E;IAC3E,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAC1C;AAED,2DAA2D;AAE3D,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC;AAY/C,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,eAAe,CAAC;IAC3B,OAAO,EAAE,wBAAwB,CAAC;CACnC;AAqID,UAAU,YAAY;IACpB,wBAAwB,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,sBAAsB,EAAE,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAA;KAAE,KAC/C,cAAc,CAAC,UAAU,CAAC,CAAC;CACjC;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAEvD;AAoYD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,eAAe,EAClD,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,CAAC,EACZ,OAAO,GAAE,wBAA6B,GACrC,CAAC,CAoEH;AAED,qDAAqD;AACrD,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAEpF;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,IAAI,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAE/E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,eAAe,EACrD,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,CAAC,EACZ,OAAO,GAAE,wBAA6B,GACrC,CAAC,CAmCH"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deny fallback renderer — renders the deny page (403.tsx, 404.tsx, etc.)
|
|
3
|
+
* for DenySignals that escape from middleware or the render phase.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from index.ts (TIM-968) as a pure move. The factory captures
|
|
6
|
+
* the root segment and client bootstrap config once at handler creation;
|
|
7
|
+
* the returned function is wired into `PipelineConfig.renderDenyFallback`
|
|
8
|
+
* and reused by the action-dispatch wrapper.
|
|
9
|
+
*
|
|
10
|
+
* Design docs: 04-authorization.md, 10-error-handling.md
|
|
11
|
+
*/
|
|
12
|
+
import type { ClientBootstrapConfig } from '../html-injectors.js';
|
|
13
|
+
import type { PipelineConfig } from '../pipeline.js';
|
|
14
|
+
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
15
|
+
/**
|
|
16
|
+
* Create the pipeline's deny fallback renderer.
|
|
17
|
+
*
|
|
18
|
+
* When the pipeline already matched a route (the common case — matching
|
|
19
|
+
* runs before middleware and rendering), resolve the status file against
|
|
20
|
+
* the matched chain so colocated files like a nested `403.tsx` or an API
|
|
21
|
+
* route's `401.json` are picked up. Fall back to the root chain when no
|
|
22
|
+
* match is available (e.g. proxy-stage deny before route matching).
|
|
23
|
+
* See TIM-822, design/04-authorization.md, design/10-error-handling.md.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createDenyFallbackRenderer(options: {
|
|
26
|
+
rootSegment: ManifestSegmentNode;
|
|
27
|
+
clientBootstrap: ClientBootstrapConfig;
|
|
28
|
+
}): NonNullable<PipelineConfig['renderDenyFallback']>;
|
|
29
|
+
//# sourceMappingURL=deny-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deny-fallback.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/deny-fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAK/D;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE;IAClD,WAAW,EAAE,mBAAmB,CAAC;IACjC,eAAe,EAAE,qBAAqB,CAAC;CACxC,GAAG,WAAW,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC,CAwDpD"}
|
|
@@ -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":"AA+BA,OAAO,uCAAuC,CAAC;AAqB/C,OAAO,KAAK,EAAuB,cAAc,EAAc,MAAM,gBAAgB,CAAC;AAmCtF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;AA4VD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,wBAAwB,EAAE,cAAc,GACvD,OAAO,CAAC,OAAO,wBAAwB,EAAE,cAAc,CAAC,CAE1D;AAyCD;;;GAGG;AACH,eAAO,MAAM,cAAc,gBAAmB,CAAC;8BAb1B,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC;AAelD,wBAAyB"}
|
|
@@ -13,10 +13,12 @@ Project-wide configuration. Export a default object from `timber.config.ts` at t
|
|
|
13
13
|
```ts
|
|
14
14
|
interface TimberUserConfig {
|
|
15
15
|
output?: 'server' | 'static';
|
|
16
|
+
debug?: boolean;
|
|
16
17
|
buildDir?: string;
|
|
17
18
|
clientJavascript?: boolean | ClientJavascriptConfig;
|
|
18
19
|
adapter?: TimberPlatformAdapter;
|
|
19
20
|
cacheHandler?: CacheHandler;
|
|
21
|
+
cdnPurge?: CdnPurgeHandler;
|
|
20
22
|
serverTiming?: 'detailed' | 'total' | false;
|
|
21
23
|
allowedOrigins?: string[];
|
|
22
24
|
csrf?: boolean;
|
|
@@ -29,18 +31,44 @@ interface TimberUserConfig {
|
|
|
29
31
|
runMiddleware?: boolean;
|
|
30
32
|
};
|
|
31
33
|
forms?: {
|
|
32
|
-
stripSensitiveFields?: boolean | string[];
|
|
34
|
+
stripSensitiveFields?: boolean | readonly string[];
|
|
33
35
|
};
|
|
34
36
|
pageExtensions?: string[];
|
|
37
|
+
slowRequestMs?: number;
|
|
38
|
+
renderTimeoutMs?: number;
|
|
39
|
+
devBrowserLogs?: 'error' | 'warn' | 'info' | 'none';
|
|
35
40
|
dev?: {
|
|
36
41
|
slowPhaseMs?: number;
|
|
37
42
|
};
|
|
43
|
+
budget?: {
|
|
44
|
+
firstLoadJs?: number;
|
|
45
|
+
};
|
|
46
|
+
appDir?: string;
|
|
38
47
|
mdx?: {
|
|
39
48
|
remarkPlugins?: any[];
|
|
40
49
|
rehypePlugins?: any[];
|
|
41
50
|
recmaPlugins?: any[];
|
|
42
51
|
remarkRehypeOptions?: any;
|
|
43
52
|
};
|
|
53
|
+
actionEncryption?: {
|
|
54
|
+
disableInDev?: boolean;
|
|
55
|
+
};
|
|
56
|
+
reactCompiler?: boolean | { compilationMode?: string; target?: string };
|
|
57
|
+
sitemap?: {
|
|
58
|
+
enabled?: boolean;
|
|
59
|
+
baseUrl?: string;
|
|
60
|
+
defaultChangeFrequency?: string;
|
|
61
|
+
defaultPriority?: number;
|
|
62
|
+
includeProtected?: boolean;
|
|
63
|
+
};
|
|
64
|
+
topLoader?: {
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
color?: string;
|
|
67
|
+
height?: number;
|
|
68
|
+
shadow?: boolean;
|
|
69
|
+
delay?: number;
|
|
70
|
+
zIndex?: number;
|
|
71
|
+
};
|
|
44
72
|
}
|
|
45
73
|
```
|
|
46
74
|
|
|
@@ -156,12 +184,71 @@ Code-only conventions (`middleware.*`, `access.*`, `route.*`, `params.*`) always
|
|
|
156
184
|
|
|
157
185
|
Two files claiming the same convention in one directory (e.g. `page.tsx` + `page.jsx`) are a build error — filesystem order is platform-dependent, so timber refuses to pick one silently.
|
|
158
186
|
|
|
187
|
+
### `debug`
|
|
188
|
+
|
|
189
|
+
- **Type:** `boolean`
|
|
190
|
+
- **Default:** `false`
|
|
191
|
+
|
|
192
|
+
Enable timber debug logging in production builds. When `true`, timber's own diagnostics (dev warnings, verbose logging) are active even in production mode. React stays in production mode — only timber's logs are affected. Can also be enabled at runtime via the `TIMBER_DEBUG` environment variable.
|
|
193
|
+
|
|
194
|
+
### `cdnPurge`
|
|
195
|
+
|
|
196
|
+
- **Type:** `CdnPurgeHandler`
|
|
197
|
+
- **Default:** none
|
|
198
|
+
|
|
199
|
+
CDN purge handler called on `revalidateTag` / `cache.invalidate` to purge CDN-cached responses.
|
|
200
|
+
|
|
201
|
+
### `slowRequestMs`
|
|
202
|
+
|
|
203
|
+
- **Type:** `number`
|
|
204
|
+
- **Default:** `3000`
|
|
205
|
+
|
|
206
|
+
Slow request threshold in milliseconds. Requests exceeding this emit a warning via the logger. Set to `0` to disable.
|
|
207
|
+
|
|
208
|
+
### `renderTimeoutMs`
|
|
209
|
+
|
|
210
|
+
- **Type:** `number`
|
|
211
|
+
- **Default:** `30000`
|
|
212
|
+
|
|
213
|
+
Render timeout in milliseconds. If an SSR render or RSC stream read does not complete within this duration, the render is aborted and the connection is closed. Protects against hung fetches and Suspense components that never resolve. Setting `0` uses a 120-second safety ceiling rather than disabling the timeout entirely.
|
|
214
|
+
|
|
215
|
+
### `devBrowserLogs`
|
|
216
|
+
|
|
217
|
+
- **Type:** `'error' | 'warn' | 'info' | 'none'`
|
|
218
|
+
- **Default:** `'warn'`
|
|
219
|
+
|
|
220
|
+
Forward browser console output to the server terminal in dev mode. Sets the minimum log level to forward. Does not intercept `console.log` or `console.debug` (too noisy). No effect in production builds.
|
|
221
|
+
|
|
159
222
|
### `dev.slowPhaseMs`
|
|
160
223
|
|
|
161
224
|
- **Type:** `number`
|
|
162
|
-
- **Default:**
|
|
225
|
+
- **Default:** `200`
|
|
226
|
+
|
|
227
|
+
Threshold in milliseconds to highlight slow phases in dev logging output.
|
|
228
|
+
|
|
229
|
+
### `budget`
|
|
230
|
+
|
|
231
|
+
Build-time performance budgets. When exceeded, the build report emits a warning (does not fail the build).
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
budget: {
|
|
235
|
+
firstLoadJs: 100_000, // bytes (gzipped)
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### `budget.firstLoadJs`
|
|
240
|
+
|
|
241
|
+
- **Type:** `number`
|
|
242
|
+
- **Default:** none
|
|
163
243
|
|
|
164
|
-
|
|
244
|
+
Warn when any route's first-load JS (gzip) exceeds this many bytes.
|
|
245
|
+
|
|
246
|
+
### `appDir`
|
|
247
|
+
|
|
248
|
+
- **Type:** `string`
|
|
249
|
+
- **Default:** auto-detected (`app/` or `src/app/`)
|
|
250
|
+
|
|
251
|
+
Override the app directory location. Set to a relative path from the project root (e.g. `'src/app'`) to use a custom location.
|
|
165
252
|
|
|
166
253
|
### `mdx`
|
|
167
254
|
|
|
@@ -174,6 +261,81 @@ mdx: {
|
|
|
174
261
|
}
|
|
175
262
|
```
|
|
176
263
|
|
|
264
|
+
### `actionEncryption`
|
|
265
|
+
|
|
266
|
+
Server action bound args encryption configuration. The RSC plugin encrypts closure variables captured by `'use server'` functions using AES-256-GCM so they are opaque and tamper-proof in the Flight payload. Encryption is always enabled in production.
|
|
267
|
+
|
|
268
|
+
The encryption key is auto-generated at build time and embedded in the server bundle. For rolling/blue-green deployments where multiple builds coexist, set `TIMBER_ACTIONS_ENCRYPTION_KEY` env var to share a key across builds.
|
|
269
|
+
|
|
270
|
+
#### `actionEncryption.disableInDev`
|
|
271
|
+
|
|
272
|
+
- **Type:** `boolean`
|
|
273
|
+
- **Default:** `false`
|
|
274
|
+
|
|
275
|
+
Disable encryption in dev mode for easier debugging of bound args. Has no effect in production — encryption is always enabled.
|
|
276
|
+
|
|
277
|
+
### `reactCompiler`
|
|
278
|
+
|
|
279
|
+
- **Type:** `boolean | { compilationMode?: string; target?: string }`
|
|
280
|
+
- **Default:** `false`
|
|
281
|
+
|
|
282
|
+
Enable the React Compiler (`babel-plugin-react-compiler`) for automatic memoization of components and hooks at build time.
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
reactCompiler: true // enable with defaults
|
|
286
|
+
reactCompiler: { compilationMode: 'annotation' } // only compile 'use memo' files
|
|
287
|
+
reactCompiler: { target: '18' } // target React 18
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Requires `babel-plugin-react-compiler` as a peer dependency.
|
|
291
|
+
|
|
292
|
+
### `sitemap`
|
|
293
|
+
|
|
294
|
+
Auto-generate `sitemap.xml` from the route tree. When enabled, timber walks the file-system route tree and produces a sitemap for all discoverable pages. Dynamic routes with `generateStaticSegmentParams()` are enumerated. Routes protected by `access.ts` are excluded by default. Supports automatic pagination (sitemap index) for sites with > 50,000 URLs.
|
|
295
|
+
|
|
296
|
+
If a user-authored `sitemap.ts` or `sitemap.xml` exists at the app root, auto-generation is disabled.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
sitemap: {
|
|
300
|
+
enabled: true,
|
|
301
|
+
baseUrl: 'https://example.com',
|
|
302
|
+
defaultChangeFrequency: 'weekly',
|
|
303
|
+
defaultPriority: 0.5,
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
| Sub-option | Type | Default | Description |
|
|
308
|
+
| ------------------------- | --------- | ------- | ------------------------------------------------ |
|
|
309
|
+
| `enabled` | `boolean` | `false` | Must be `true` to enable auto-generation |
|
|
310
|
+
| `baseUrl` | `string` | — | Base URL for absolute URLs. Required when enabled |
|
|
311
|
+
| `defaultChangeFrequency` | `string` | — | Default `<changefreq>` for all entries |
|
|
312
|
+
| `defaultPriority` | `number` | — | Default `<priority>` (0.0–1.0) |
|
|
313
|
+
| `includeProtected` | `boolean` | `false` | Include routes protected by `access.ts` |
|
|
314
|
+
|
|
315
|
+
### `topLoader`
|
|
316
|
+
|
|
317
|
+
Navigation progress bar shown at the top of the page during client-side navigations.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
topLoader: {
|
|
321
|
+
enabled: true,
|
|
322
|
+
color: '#2299DD',
|
|
323
|
+
height: 3,
|
|
324
|
+
shadow: true,
|
|
325
|
+
delay: 0,
|
|
326
|
+
zIndex: 1600,
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
| Sub-option | Type | Default | Description |
|
|
331
|
+
| ---------- | --------- | ----------- | -------------------------------------------------- |
|
|
332
|
+
| `enabled` | `boolean` | `true` | Whether the top-loader is enabled |
|
|
333
|
+
| `color` | `string` | `'#2299DD'` | Bar color |
|
|
334
|
+
| `height` | `number` | `3` | Bar height in pixels |
|
|
335
|
+
| `shadow` | `boolean` | `true` | Show subtle glow/shadow effect |
|
|
336
|
+
| `delay` | `number` | `0` | Delay in ms before showing (avoids flash on fast navs) |
|
|
337
|
+
| `zIndex` | `number` | `1600` | CSS z-index |
|
|
338
|
+
|
|
177
339
|
## `TimberPlatformAdapter`
|
|
178
340
|
|
|
179
341
|
The adapter interface for community adapters:
|
|
@@ -9,68 +9,102 @@ notAI: true
|
|
|
9
9
|
|
|
10
10
|
## Basics
|
|
11
11
|
|
|
12
|
-
Timber is a react-based web framework built on
|
|
12
|
+
Timber is a react-based web framework built on Vite and Server Components. It is inspired by next.js, tanstack start, and remix however it brings an independent approach built on a modern and flexible foundation.
|
|
13
13
|
|
|
14
|
-
It is
|
|
14
|
+
It is designed to align with web standards and attempts to use as little framework magic as possible. We feel it unlocks both the most flexible UX and DX possible. Rather than using heuristics to adjust how the framework operates, it gives you the knobs to fine-tune your website to your liking.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Here are some of the ideas that drive Timber.
|
|
19
|
+
|
|
20
|
+
### Architectural Optionality
|
|
21
|
+
|
|
22
|
+
Timber is a framework that aims to bring architectural optionality. All websites run in three environments:
|
|
23
|
+
|
|
24
|
+
* The Server
|
|
25
|
+
* The Server and the Client (often called SSR or pre-rendering)
|
|
26
|
+
* The Client
|
|
27
|
+
|
|
28
|
+
The server brings forth access control, privacy, and performance and sets up the initial response to the user.
|
|
29
|
+
|
|
30
|
+
The client unlocks interactivity, dynamic rendering, and cross-route state.
|
|
31
|
+
|
|
32
|
+
SSR and pre-rendering bridge the two.
|
|
33
|
+
|
|
34
|
+
Server Components unlock each environment to its fullest capacity, while allowing you to step through them via one unified component tree. And timber embraces them fully.
|
|
35
|
+
|
|
36
|
+
### Upside-Down Astro
|
|
37
|
+
|
|
38
|
+
Astro is a framework built for content and it's philsophy is: static first, islands of interactivity and dynamic content.
|
|
39
|
+
|
|
40
|
+
Timber is the inverse of this approach: dynamic first, with islands of static content. In our experience, most webpages require some form of dynamic rendering. Expensive stuff, cached stuff, is usually on the leafier side – a component tree here and there. Only caching subsets of your tree gives you powerful performance without sacrificing the full server functionality (access control, middleware, logging, and more).
|
|
41
|
+
|
|
42
|
+
We also find this to be a simpler mental model. Requests flow through the server – subsets of the page are cached. Interactivity and state exists throughout the tree and across routes.
|
|
43
|
+
|
|
44
|
+
### Serialized Building Blocks: Cookies, Search Params, Segment Params
|
|
45
|
+
|
|
46
|
+
Timber takes all of the building blocks of the web that are effectively: serialize data to a string and back and it gives you the guard rails to properly type and validate them. Things like cookies, search params, and segment params.
|
|
47
|
+
|
|
48
|
+
Everything is driven by standard schemas (zod, valibot, nuqs, custom, etc.) and you create factory functions to access that data on the server and the client.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { defineSearchParams } from '@timber-js/app/search-params';
|
|
52
|
+
import { z } from 'zod/v4';
|
|
53
|
+
|
|
54
|
+
export const searchParams = defineSearchParams({
|
|
55
|
+
month: z.string().optional(),
|
|
56
|
+
day: z.string().optional(),
|
|
57
|
+
slug: z.string().optional(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// later on
|
|
61
|
+
const sp = searchParams.get();
|
|
62
|
+
|
|
63
|
+
// or on the client
|
|
64
|
+
|
|
65
|
+
const [sp, setSearchParams] = searchParams.useQueryState();
|
|
66
|
+
```
|
|
17
67
|
|
|
18
|
-
|
|
68
|
+
### Typed Routes
|
|
19
69
|
|
|
20
|
-
|
|
70
|
+
All routing in timber is fully typed and integrated. So you can write a `<Link>` as:
|
|
21
71
|
|
|
22
|
-
|
|
72
|
+
```tsx
|
|
73
|
+
<Link href="/blog/[slug]" segmentParams={{ slug: 'a-post' }} searchParams={{ foo: 'bar' }}>Page</Link>
|
|
74
|
+
```
|
|
23
75
|
|
|
24
|
-
|
|
76
|
+
Or just normal `<a>` tags work too.
|
|
25
77
|
|
|
26
|
-
|
|
78
|
+
### Middleware and Access Control
|
|
27
79
|
|
|
28
|
-
|
|
80
|
+
Timber's routing and layouting system is almost 1:1 inspired by next.js. This file based routing structure lends itself to a compositional architecture, where you can build up layers of functionality as you go deeper into the route tree.
|
|
29
81
|
|
|
30
|
-
|
|
82
|
+
The filesystem maps directly to the route tree. On top of that, because our architecture is dynamic first, we can give you: proper middleware and `access.ts` access control.
|
|
31
83
|
|
|
32
|
-
|
|
84
|
+
When you hit a route, every segment's `middleware.ts` and `access.ts` is executed in series. Though some would call this slow, with a proper data architecture, we find that this is rarely the bottleneck to building a fast and performant website.
|
|
33
85
|
|
|
34
|
-
|
|
86
|
+
And the DX clarity and functionality gains are immense. Give it a try, you'll be surprised how nice it feels.
|
|
35
87
|
|
|
36
|
-
|
|
88
|
+
### Forms
|
|
37
89
|
|
|
38
|
-
|
|
90
|
+
Forms have long been the biggest pain point of building React apps. They are chonky, buggy, and painful to write. Timber flips forms on their head and make the whole process feel a lot more like _react_.
|
|
39
91
|
|
|
40
|
-
|
|
92
|
+
Here are our rules for forms:
|
|
41
93
|
|
|
42
|
-
|
|
94
|
+
1. Forms must work consistently with or without javascript
|
|
95
|
+
2. Inputs must _own their own state_ or be uncontrolled – no more hoisting your logic and context above the form. This makes sure forms are composable.
|
|
96
|
+
3. You should be able to have global validation and input-level validation
|
|
97
|
+
4. Validation should be possible to run on either the server, or the client
|
|
98
|
+
5. Forms should maintain their data if submission fails (whether you are on the JS or non-JS track)
|
|
43
99
|
|
|
44
|
-
|
|
100
|
+
Now you might say, wow, these are a lot of rules – even though they all sound good. But to handle all of these features, you'd need way more code.
|
|
45
101
|
|
|
46
|
-
|
|
102
|
+
Turns out – the opposite. It's way less code. It's more functional, more flexible, and you write less code to handle it all. Does the science back it up? Let's see:
|
|
47
103
|
|
|
48
|
-
|
|
104
|
+
### Developer Clarity
|
|
49
105
|
|
|
50
|
-
|
|
106
|
+
We believe the good UX is invisible, but good DX is _transparent_. You should always be able to see what's going on. No caching is implicit.
|
|
51
107
|
|
|
52
|
-
|
|
53
|
-
- Server
|
|
54
|
-
- Client
|
|
55
|
-
- Isomorphic (Universal SSR)
|
|
56
|
-
- Serverless is a flawed paradigm for rendering
|
|
57
|
-
- Though it can be useful at times, owning your _own_ server (and CPU cycles) will always be more performant and cost effective at anything beyond a basic scale
|
|
58
|
-
- An inefficiency in serverless means an unbounded/infinite bill, on a server it only means degraded performance
|
|
59
|
-
- A server means your database can live _next_ to your rendering layer, which will always outperform _holistic_ edge rendering in generic real-world scenarios
|
|
60
|
-
- Your framework should never be smarter than you
|
|
61
|
-
- Good UX is invisible, good DX is transparent
|
|
62
|
-
- It's better to be understandable than magic, which means performance is fine tunable – rather than automatic
|
|
63
|
-
- The web constantly serializes and deserializes strings, the framework should provide typing and parsing to those edges
|
|
64
|
-
- Search Params
|
|
65
|
-
- Cookies
|
|
66
|
-
- Segment URL Params
|
|
67
|
-
- and more...
|
|
68
|
-
- A good web-framework scales horizontally across your surface API (routes)
|
|
69
|
-
- Adding more routes or components shouldn't affect performance on others
|
|
70
|
-
- A good web framework has finely-tuned control over static (build-time) and dynamic (run-time) rendering
|
|
71
|
-
- A good web framework has the ability to scale up and down functionally and with developer clarity, which means deploying a website that:
|
|
72
|
-
- Can ship zero client javascript
|
|
73
|
-
- Can ship static content
|
|
74
|
-
- And can scale up to a completely dynamic website */}
|
|
108
|
+
-----
|
|
75
109
|
|
|
76
|
-
|
|
110
|
+
These are the core tenants of Timber. It's the framework I wish existed. Thanks for taking the time to look into it.
|