@timber-js/app 0.2.0-alpha.157 → 0.2.0-alpha.159
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-CqE7SW7E.js → actions-CBbP1hHO.js} +22 -6
- package/dist/_chunks/actions-CBbP1hHO.js.map +1 -0
- package/dist/_chunks/{build-output-helper-C8q4Zpf5.js → build-output-helper-DF5uScqS.js} +4 -1
- package/dist/_chunks/{build-output-helper-C8q4Zpf5.js.map → build-output-helper-DF5uScqS.js.map} +1 -1
- package/dist/_chunks/cache-api-DsWEYwVZ.js +1120 -0
- package/dist/_chunks/cache-api-DsWEYwVZ.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync-DcmQrzJG.js → cli-schema-sync-Bivx4Rn7.js} +4 -3
- package/dist/_chunks/{cli-schema-sync-DcmQrzJG.js.map → cli-schema-sync-Bivx4Rn7.js.map} +1 -1
- package/dist/_chunks/dist-BA3u1z3W.js +423 -0
- package/dist/_chunks/dist-BA3u1z3W.js.map +1 -0
- package/dist/_chunks/{logger-C5v1IMuh.js → logger-CrRmZMlo.js} +81 -56
- package/dist/_chunks/logger-CrRmZMlo.js.map +1 -0
- package/dist/_chunks/{plugin-context-DUl3dnCF.js → plugin-context-DeAxFRMq.js} +3 -36
- package/dist/_chunks/plugin-context-DeAxFRMq.js.map +1 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js +35 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +1 -0
- package/dist/_chunks/{walkers-D5jCGPum.js → walkers-DXbJkeCY.js} +217 -19
- package/dist/_chunks/walkers-DXbJkeCY.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -1
- package/dist/adapters/cloudflare.d.ts +28 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +143 -9
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/nitro.js +1 -1
- package/dist/cache/cache-api.d.ts +2 -0
- package/dist/cache/cache-api.d.ts.map +1 -1
- package/dist/cache/handler-store.d.ts +2 -0
- package/dist/cache/handler-store.d.ts.map +1 -1
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -186
- package/dist/cache/redis-handler.d.ts +17 -5
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +1 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/store.d.ts +53 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
- package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.js +29 -0
- package/dist/cache/stores/cloudflare-kv.js.map +1 -0
- package/dist/cache/stores/memory.d.ts +42 -0
- package/dist/cache/stores/memory.d.ts.map +1 -0
- package/dist/cache/stores/memory.js +90 -0
- package/dist/cache/stores/memory.js.map +1 -0
- package/dist/cache/stores/redis.d.ts +69 -0
- package/dist/cache/stores/redis.d.ts.map +1 -0
- package/dist/cache/stores/redis.js +35 -0
- package/dist/cache/stores/redis.js.map +1 -0
- package/dist/cache/stores/vercel.d.ts +36 -0
- package/dist/cache/stores/vercel.d.ts.map +1 -0
- package/dist/cache/stores/vercel.js +33 -0
- package/dist/cache/stores/vercel.js.map +1 -0
- package/dist/cache/tag-aware-handler.d.ts +51 -0
- package/dist/cache/tag-aware-handler.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cdn/cloudflare-purge.d.ts +23 -0
- package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
- package/dist/cdn/fastly-purge.d.ts +25 -0
- package/dist/cdn/fastly-purge.d.ts.map +1 -0
- package/dist/cdn/headers.d.ts +82 -0
- package/dist/cdn/headers.d.ts.map +1 -0
- package/dist/cdn/index.d.ts +5 -0
- package/dist/cdn/index.d.ts.map +1 -0
- package/dist/cdn/purge-store.d.ts +23 -0
- package/dist/cdn/purge-store.d.ts.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/history.d.ts +0 -3
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.js +0 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.js +11 -86
- package/dist/client/internal.js.map +1 -1
- package/dist/client/navigation-api.d.ts +1 -3
- package/dist/client/navigation-api.d.ts.map +1 -1
- package/dist/client/router.d.ts +1 -4
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +1 -11
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -3
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/config-types.d.ts +3 -1
- package/dist/config-types.d.ts.map +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/cookies/index.js +15 -11
- package/dist/cookies/index.js.map +1 -1
- package/dist/dev-tools/browser-logs.d.ts +28 -72
- package/dist/dev-tools/browser-logs.d.ts.map +1 -1
- package/dist/dev-tools/index.d.ts +1 -1
- package/dist/dev-tools/index.d.ts.map +1 -1
- package/dist/dev-tools/logger.d.ts.map +1 -1
- package/dist/dev-tools/terminal.d.ts.map +1 -1
- package/dist/fonts/transform.d.ts +4 -0
- package/dist/fonts/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1269 -359
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +36 -0
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +21 -0
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/cache.d.ts +5 -14
- package/dist/plugins/cache.d.ts.map +1 -1
- package/dist/plugins/callsite-ast.d.ts +95 -0
- package/dist/plugins/callsite-ast.d.ts.map +1 -0
- package/dist/plugins/callsite-jsx.d.ts +35 -0
- package/dist/plugins/callsite-jsx.d.ts.map +1 -0
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/prebuilt-capture.d.ts +60 -0
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -0
- package/dist/plugins/prebuilt.d.ts +82 -0
- package/dist/plugins/prebuilt.d.ts.map +1 -0
- package/dist/plugins/prerender-sugar.d.ts +42 -0
- package/dist/plugins/prerender-sugar.d.ts.map +1 -0
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/export-detect.d.ts +56 -0
- package/dist/routing/export-detect.d.ts.map +1 -0
- package/dist/routing/index.js +2 -2
- package/dist/routing/manifest-codegen.d.ts.map +1 -1
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +0 -3
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +7 -0
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/cookie-parsing.d.ts +15 -1
- package/dist/server/cookie-parsing.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +12 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +1 -0
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/internal.d.ts +6 -1
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +563 -74
- package/dist/server/internal.js.map +1 -1
- package/dist/server/prebuilt/cache-key.d.ts +58 -0
- package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +57 -0
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
- package/dist/server/prebuilt/overlay.d.ts +100 -0
- package/dist/server/prebuilt/overlay.d.ts.map +1 -0
- package/dist/server/prebuilt/payload-source.d.ts +75 -0
- package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
- package/dist/server/prebuilt/synthetic-store.d.ts +64 -0
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts +110 -0
- package/dist/server/prebuilt-builder.d.ts.map +1 -0
- package/dist/server/prebuilt-runtime.d.ts +101 -0
- package/dist/server/prebuilt-runtime.d.ts.map +1 -0
- package/dist/server/route-element-builder.d.ts +10 -8
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +0 -5
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +10 -0
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -4
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/sitemap-generator.d.ts +6 -6
- package/dist/server/sitemap-generator.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +37 -3
- package/dist/server/tracing.d.ts.map +1 -1
- package/docs/api/32-api-cache.mdx +10 -4
- package/docs/learn/00-introduction.mdx +8 -13
- package/docs/learn/02-pages-and-layouts.mdx +9 -0
- package/docs/learn/06-forms-and-actions.mdx +0 -4
- package/docs/learn/07-typed-routes.mdx +127 -0
- package/docs/learn/09-caching.mdx +12 -1
- package/docs/learn/10-middleware.mdx +1 -0
- package/docs/learn/11-error-handling.mdx +9 -0
- package/docs/learn/13-configuration.mdx +28 -0
- package/docs/learn/14-deploying.mdx +52 -0
- package/docs/more/06-instrumentation.mdx +27 -1
- package/docs/more/07-security.mdx +8 -2
- package/docs/more/08-developer-experience.mdx +134 -0
- package/package.json +31 -2
- package/src/adapters/build-output-helper.ts +10 -0
- package/src/adapters/cloudflare.ts +178 -4
- package/src/cache/cache-api.ts +60 -0
- package/src/cache/handler-store.ts +8 -0
- package/src/cache/index.ts +4 -0
- package/src/cache/redis-handler.ts +25 -13
- package/src/cache/singleflight.ts +11 -11
- package/src/cache/store.ts +71 -0
- package/src/cache/stores/cloudflare-kv.ts +52 -0
- package/src/cache/stores/memory.ts +125 -0
- package/src/cache/stores/redis.ts +97 -0
- package/src/cache/stores/vercel.ts +59 -0
- package/src/cache/tag-aware-handler.ts +233 -0
- package/src/cache/timber-cache.ts +17 -7
- package/src/cdn/cloudflare-purge.ts +50 -0
- package/src/cdn/fastly-purge.ts +63 -0
- package/src/cdn/headers.ts +127 -0
- package/src/cdn/index.ts +16 -0
- package/src/cdn/purge-store.ts +34 -0
- package/src/client/browser-entry/action-dispatch.ts +1 -10
- package/src/client/browser-entry/post-hydration.ts +0 -1
- package/src/client/browser-entry/router-init.ts +0 -5
- package/src/client/history.ts +0 -4
- package/src/client/navigation-api.ts +5 -11
- package/src/client/router.ts +9 -43
- package/src/client/rsc-fetch.ts +5 -27
- package/src/client/segment-cache.ts +1 -4
- package/src/client/use-cookie.ts +18 -12
- package/src/config-types.ts +3 -1
- package/src/config-validation.ts +1 -0
- package/src/dev-tools/browser-logs.ts +37 -273
- package/src/dev-tools/index.ts +2 -2
- package/src/dev-tools/instrumentation.ts +1 -1
- package/src/dev-tools/logger.ts +33 -51
- package/src/dev-tools/terminal.ts +21 -22
- package/src/fonts/transform.ts +4 -43
- package/src/index.ts +16 -3
- package/src/plugin-context.ts +36 -0
- package/src/plugins/build-report.ts +133 -1
- package/src/plugins/cache.ts +32 -131
- package/src/plugins/callsite-ast.ts +167 -0
- package/src/plugins/callsite-jsx.ts +243 -0
- package/src/plugins/entries.ts +23 -4
- package/src/plugins/fonts.ts +16 -2
- package/src/plugins/prebuilt-capture.ts +208 -0
- package/src/plugins/prebuilt.ts +673 -0
- package/src/plugins/prerender-sugar.ts +329 -0
- package/src/plugins/server-bundle.ts +12 -0
- package/src/plugins/shims.ts +9 -0
- package/src/plugins/static-build.ts +0 -1
- package/src/routing/codegen.ts +1 -21
- package/src/routing/convention-lint.ts +85 -49
- package/src/routing/export-detect.ts +304 -0
- package/src/routing/manifest-codegen.ts +2 -11
- package/src/rsc-runtime/rsc.ts +7 -0
- package/src/server/action-handler.ts +11 -27
- package/src/server/actions.ts +3 -4
- package/src/server/als-registry.ts +7 -0
- package/src/server/cookie-parsing.ts +75 -59
- package/src/server/deny-renderer.ts +7 -15
- package/src/server/form-data.ts +23 -7
- package/src/server/html-injectors.ts +11 -3
- package/src/server/internal.ts +17 -1
- package/src/server/prebuilt/cache-key.ts +224 -0
- package/src/server/prebuilt/capture-state.ts +89 -0
- package/src/server/prebuilt/manifest-tag-index.ts +46 -0
- package/src/server/prebuilt/overlay.ts +256 -0
- package/src/server/prebuilt/payload-source.ts +192 -0
- package/src/server/prebuilt/synthetic-store.ts +108 -0
- package/src/server/prebuilt-builder.ts +640 -0
- package/src/server/prebuilt-runtime.ts +706 -0
- package/src/server/route-element-builder.ts +40 -12
- package/src/server/rsc-entry/helpers.ts +0 -17
- package/src/server/rsc-entry/index.ts +83 -0
- package/src/server/rsc-entry/render-route.ts +6 -33
- package/src/server/rsc-entry/revalidate-renderer.ts +16 -11
- package/src/server/rsc-entry/rsc-payload.ts +5 -11
- package/src/server/sitemap-generator.ts +16 -10
- package/src/server/tracing.ts +88 -3
- package/dist/_chunks/actions-CqE7SW7E.js.map +0 -1
- package/dist/_chunks/cache-api-Cbyh3RW4.js +0 -401
- package/dist/_chunks/cache-api-Cbyh3RW4.js.map +0 -1
- package/dist/_chunks/logger-C5v1IMuh.js.map +0 -1
- package/dist/_chunks/plugin-context-DUl3dnCF.js.map +0 -1
- package/dist/_chunks/validation-CnKhGJsp.js +0 -113
- package/dist/_chunks/validation-CnKhGJsp.js.map +0 -1
- package/dist/_chunks/walkers-D5jCGPum.js.map +0 -1
- package/dist/cache/index.js.map +0 -1
- package/dist/client/head.d.ts +0 -16
- package/dist/client/head.d.ts.map +0 -1
- package/dist/client/navigation-api-types.d.ts +0 -90
- package/dist/client/navigation-api-types.d.ts.map +0 -1
- package/dist/server/client-module-map.d.ts +0 -47
- package/dist/server/client-module-map.d.ts.map +0 -1
- package/dist/shared/head-header.d.ts +0 -54
- package/dist/shared/head-header.d.ts.map +0 -1
- package/src/client/head.ts +0 -61
- package/src/client/navigation-api-types.ts +0 -112
- package/src/server/client-module-map.ts +0 -58
- package/src/shared/head-header.ts +0 -69
|
@@ -17,6 +17,16 @@
|
|
|
17
17
|
import type { RouteMatch } from './pipeline.js';
|
|
18
18
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
19
19
|
import type { InterceptionContext } from './pipeline.js';
|
|
20
|
+
import type { HeadElement } from './metadata.js';
|
|
21
|
+
/**
|
|
22
|
+
* Convert HeadElement descriptors to React elements for Float hoisting.
|
|
23
|
+
*
|
|
24
|
+
* React 19 Float hoists <title>, <meta>, and <link> rendered anywhere in
|
|
25
|
+
* the tree into <head> during SSR, and manages them in document.head
|
|
26
|
+
* during client-side rendering. This replaces the X-Timber-Head header
|
|
27
|
+
* side-channel and the imperative client DOM applier.
|
|
28
|
+
*/
|
|
29
|
+
export declare function headElementsToReact(elements: HeadElement[]): React.ReactElement;
|
|
20
30
|
/**
|
|
21
31
|
* Detect whether a component is a React client reference.
|
|
22
32
|
* Client references have $$typeof set to Symbol.for('react.client.reference')
|
|
@@ -34,12 +44,6 @@ export declare function isClientReference(component: unknown): boolean;
|
|
|
34
44
|
export declare class ParamCoercionError extends Error {
|
|
35
45
|
constructor(message: string);
|
|
36
46
|
}
|
|
37
|
-
/** Head element for client-side metadata updates. */
|
|
38
|
-
export interface HeadElement {
|
|
39
|
-
tag: string;
|
|
40
|
-
content?: string;
|
|
41
|
-
attrs?: Record<string, string | null>;
|
|
42
|
-
}
|
|
43
47
|
/** Layout entry with component and segment. */
|
|
44
48
|
export interface LayoutComponentEntry {
|
|
45
49
|
component: (...args: unknown[]) => unknown;
|
|
@@ -49,8 +53,6 @@ export interface LayoutComponentEntry {
|
|
|
49
53
|
export interface RouteElementResult {
|
|
50
54
|
/** The React element tree (page wrapped in layouts, access gates, error boundaries). */
|
|
51
55
|
element: React.ReactElement;
|
|
52
|
-
/** Resolved head elements for metadata. */
|
|
53
|
-
headElements: HeadElement[];
|
|
54
56
|
/** Layout components loaded along the segment chain. */
|
|
55
57
|
layoutComponents: LayoutComponentEntry[];
|
|
56
58
|
/** Segments from the route match. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-element-builder.d.ts","sourceRoot":"","sources":["../../src/server/route-element-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AA0B9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"route-element-builder.d.ts","sourceRoot":"","sources":["../../src/server/route-element-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AA0B9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,YAAY,CAW/E;AAwCD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAM7D;AAID;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAID,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;IAC5B,wDAAwD;IACxD,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,qCAAqC;IACrC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AA8DD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,mBAAmB,EAClC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,EACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,kBAAkB,CAAC,CAqf7B"}
|
|
@@ -93,9 +93,4 @@ export declare function isRscPayloadRequest(req: Request): boolean;
|
|
|
93
93
|
export { buildRedirectResponse } from '../pipeline-helpers.js';
|
|
94
94
|
export { isAbortError } from '../render-utils.js';
|
|
95
95
|
export { escapeHtml } from '../utils/escape-html.js';
|
|
96
|
-
/**
|
|
97
|
-
* Parse a Cookie header string into a name→value Map.
|
|
98
|
-
* Used to populate NavContext.cookies for SSR hooks (useCookie).
|
|
99
|
-
*/
|
|
100
|
-
export declare function parseCookiesFromHeader(header: string): Map<string, string>;
|
|
101
96
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,CAQ/F;AAID;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,yDAAyD;IACzD,gBAAgB,IAAI,MAAM,CAAC;IAC3B,yEAAyE;IACzE,aAAa,IAAI,mBAAmB,EAAE,CAAC;CACxC;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkCnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8ClE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IACtB,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,GACD,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA8B/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGzD;AAMD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,CAQ/F;AAID;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,yDAAyD;IACzD,gBAAgB,IAAI,MAAM,CAAC;IAC3B,yEAAyE;IACzE,aAAa,IAAI,mBAAmB,EAAE,CAAC;CACxC;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkCnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8ClE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IACtB,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,GACD,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA8B/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGzD;AAMD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -13,6 +13,16 @@ import type { PipelineConfig } from '../pipeline.js';
|
|
|
13
13
|
export declare function setDevSourceMapHandler(handler: (error: Error) => void): void;
|
|
14
14
|
export { runWithEarlyHintsSender } from '../early-hints-sender.js';
|
|
15
15
|
export { runWithWaitUntil } from '../waituntil-bridge.js';
|
|
16
|
+
/**
|
|
17
|
+
* Post-build flight capture entry point (TIM-1119). The capture pass must
|
|
18
|
+
* run inside the built RSC bundle — the prebuilt component registry, the
|
|
19
|
+
* ALS instances, and the flight renderer are module instances in THIS
|
|
20
|
+
* bundle's graph; an outside import of the framework package would get
|
|
21
|
+
* fresh, empty copies. The timber-prebuilt plugin imports the built
|
|
22
|
+
* `rsc/index.js` after the 5-step build and calls this export.
|
|
23
|
+
* See design/44-render-at-build-time.md §Build Phase.
|
|
24
|
+
*/
|
|
25
|
+
export declare function __timber_capturePrebuilt(options: import('../prebuilt-builder.js').CaptureOptions): Promise<import('../prebuilt-builder.js').CaptureSummary>;
|
|
16
26
|
declare const _handler: (req: Request) => Promise<Response>;
|
|
17
27
|
/**
|
|
18
28
|
* The pipeline configuration object. Exported so the dev server can set
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAuBA,OAAO,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAuBA,OAAO,uCAAuC,CAAC;AAuB/C,OAAO,KAAK,EAAuB,cAAc,EAAc,MAAM,gBAAgB,CAAC;AAuCtF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;AAgbD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,wBAAwB,EAAE,cAAc,GACvD,OAAO,CAAC,OAAO,wBAAwB,EAAE,cAAc,CAAC,CAE1D;AAED,QAAA,MAAiB,QAAQ,qCAGxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,gBAAkB,CAAC;AAE9C,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-route.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/render-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"render-route.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/render-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAW1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAa/D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,mBAAmB,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAClE;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,IAAI,EAAE,eAAe,EACrB,YAAY,CAAC,EAAE,mBAAmB,GACjC,OAAO,CAAC,QAAQ,CAAC,CA+MnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revalidate-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/revalidate-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;
|
|
1
|
+
{"version":3,"file":"revalidate-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/revalidate-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK/D,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,eAAe,CAAC;AAE5E,OAAO,EAA0B,KAAK,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEnG;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,0DAA0D;AAC1D,KAAK,cAAc,GACf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAiCpE;AAwBD,wDAAwD;AACxD,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,YAAY,CAAC;IACzB,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,sBAAsB,GAC3B,CAAC,GAAG,EAAE,OAAO,KAAK,kBAAkB,CA4KtC"}
|
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
* returned directly without SSR HTML rendering. The client decodes it via
|
|
6
6
|
* `createFromFetch` and renders into the hydrated React root.
|
|
7
7
|
*
|
|
8
|
-
* Design docs: 19-client-navigation.md §"RSC Payload Handling"
|
|
9
|
-
* 16-metadata.md §"Head Elements"
|
|
8
|
+
* Design docs: 19-client-navigation.md §"RSC Payload Handling"
|
|
10
9
|
*/
|
|
11
10
|
import type { RouteMatch } from '../pipeline.js';
|
|
12
|
-
import type {
|
|
11
|
+
import type { LayoutComponentEntry } from '../route-element-builder.js';
|
|
13
12
|
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
14
13
|
import type { RenderSignals } from './rsc-stream.js';
|
|
15
14
|
/**
|
|
@@ -21,5 +20,5 @@ import type { RenderSignals } from './rsc-stream.js';
|
|
|
21
20
|
* initial component tree, allowing onError to capture DenySignal/
|
|
22
21
|
* RedirectSignal before we commit the response. See TIM-344.
|
|
23
22
|
*/
|
|
24
|
-
export declare function buildRscPayloadResponse(req: Request, rscStream: ReadableStream<Uint8Array>, signals: RenderSignals, segments: ManifestSegmentNode[], layoutComponents: LayoutComponentEntry[],
|
|
23
|
+
export declare function buildRscPayloadResponse(req: Request, rscStream: ReadableStream<Uint8Array>, signals: RenderSignals, segments: ManifestSegmentNode[], layoutComponents: LayoutComponentEntry[], match: RouteMatch, responseHeaders: Headers, skippedSegments?: string[]): Promise<Response>;
|
|
25
24
|
//# sourceMappingURL=rsc-payload.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ/D,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,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,CAmKnB"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Features:
|
|
8
8
|
* - Collects all static page routes automatically
|
|
9
|
-
* - Calls `
|
|
9
|
+
* - Calls `generateStaticSegmentParams()` on dynamic routes to enumerate URLs
|
|
10
10
|
* - Skips API routes (route.ts), layout-only segments, slots, intercepting routes
|
|
11
11
|
* - Skips auth-protected routes (access.ts in segment chain) by default
|
|
12
12
|
* - Automatic pagination: sitemap index when > 50,000 URLs
|
|
@@ -35,12 +35,12 @@ export interface SitemapEntry {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* A route discovered during tree walk that may need async resolution
|
|
38
|
-
* (dynamic routes with
|
|
38
|
+
* (dynamic routes with generateStaticSegmentParams).
|
|
39
39
|
*/
|
|
40
40
|
export interface SitemapRoute {
|
|
41
41
|
/** The URL path pattern (e.g., '/products/[id]'). */
|
|
42
42
|
urlPath: string;
|
|
43
|
-
/** Whether this route has dynamic segments that need
|
|
43
|
+
/** Whether this route has dynamic segments that need generateStaticSegmentParams. */
|
|
44
44
|
isDynamic: boolean;
|
|
45
45
|
/** Loader for the page module (from route manifest). */
|
|
46
46
|
pageLoader?: {
|
|
@@ -71,7 +71,7 @@ export declare const URLS_PER_SITEMAP = 50000;
|
|
|
71
71
|
* Walk the route tree and collect all routes eligible for the sitemap.
|
|
72
72
|
*
|
|
73
73
|
* Pure synchronous function — no module loading. Returns routes that may
|
|
74
|
-
* need async resolution (dynamic routes with
|
|
74
|
+
* need async resolution (dynamic routes with generateStaticSegmentParams).
|
|
75
75
|
*
|
|
76
76
|
* @param root - The root segment node from the route tree
|
|
77
77
|
* @param config - Sitemap configuration
|
|
@@ -88,7 +88,7 @@ export declare function hasDynamicSegments(urlPath: string): boolean;
|
|
|
88
88
|
* Resolve sitemap routes into concrete URLs.
|
|
89
89
|
*
|
|
90
90
|
* For static routes, the URL is derived directly from the path.
|
|
91
|
-
* For dynamic routes, calls `
|
|
91
|
+
* For dynamic routes, calls `generateStaticSegmentParams()` from the page module.
|
|
92
92
|
*
|
|
93
93
|
* @param routes - Routes collected by collectSitemapRoutes
|
|
94
94
|
* @param config - Sitemap configuration
|
|
@@ -115,7 +115,7 @@ export declare function resolvePathWithParams(urlPath: string, params: Record<st
|
|
|
115
115
|
*
|
|
116
116
|
* @param root - The root segment node from the route tree
|
|
117
117
|
* @param config - Sitemap configuration
|
|
118
|
-
* @param loadModule - Optional async function to load page modules (for
|
|
118
|
+
* @param loadModule - Optional async function to load page modules (for generateStaticSegmentParams)
|
|
119
119
|
* @returns The sitemap result (single or index with pages)
|
|
120
120
|
*/
|
|
121
121
|
export declare function generateSitemap(root: SegmentNode, config: SitemapConfig, loadModule?: ModuleLoader): Promise<SitemapResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap-generator.d.ts","sourceRoot":"","sources":["../../src/server/sitemap-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,
|
|
1
|
+
{"version":3,"file":"sitemap-generator.d.ts","sourceRoot":"","sources":["../../src/server/sitemap-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACjE;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE;IAClC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvC,oCAAoC;AACpC,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAIpE,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAIvC;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,GAAG,YAAY,EAAE,CAI7F;AAwDD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,EAAE,aAAa,EACrB,UAAU,CAAC,EAAE,YAAY,GACxB,OAAO,CAAC,YAAY,EAAE,CAAC,CAqDzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACxC,MAAM,GAAG,IAAI,CA0Cf;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,EACrB,UAAU,CAAC,EAAE,YAAY,GACxB,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAGzD"}
|
package/dist/server/tracing.d.ts
CHANGED
|
@@ -60,19 +60,53 @@ export declare function getTraceStore(): TraceStore | undefined;
|
|
|
60
60
|
* registers. Only called in dev mode — zero overhead in production.
|
|
61
61
|
*/
|
|
62
62
|
export declare function initDevTracing(config: import('../dev-tools/logger.js').DevLoggerConfig): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* A native platform span. Mirrors the subset of the Cloudflare Workers
|
|
65
|
+
* `Span` API that timber uses. See design/17-logging.md §"Cloudflare Native
|
|
66
|
+
* Spans" and TIM-1135.
|
|
67
|
+
*/
|
|
68
|
+
export interface PlatformSpan {
|
|
69
|
+
setAttribute(key: string, value: string | number | boolean): void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Adapter-provided native tracer. Callback-scoped like Cloudflare's
|
|
73
|
+
* `tracing.enterSpan()` — the span starts when the callback is invoked and
|
|
74
|
+
* ends when it returns or its promise settles. Nesting follows the
|
|
75
|
+
* platform's async context.
|
|
76
|
+
*
|
|
77
|
+
* When registered, withSpan() wraps every framework span in a native span
|
|
78
|
+
* *in addition to* the OTEL emission — dual emission, so external OTEL
|
|
79
|
+
* collectors keep working alongside the platform's native trace view.
|
|
80
|
+
*
|
|
81
|
+
* Register via setPlatformTracer(), or by writing the
|
|
82
|
+
* Symbol.for('timber:platform-tracer') key on globalThis from
|
|
83
|
+
* adapter-generated entry code (what the Cloudflare _worker.js does).
|
|
84
|
+
*/
|
|
85
|
+
export interface PlatformTracer {
|
|
86
|
+
enterSpan<T>(name: string, fn: (span: PlatformSpan) => T): T;
|
|
87
|
+
}
|
|
88
|
+
/** Register (or clear) the native platform tracer for this runtime. */
|
|
89
|
+
export declare function setPlatformTracer(tracer: PlatformTracer | undefined): void;
|
|
90
|
+
/** The registered native platform tracer, if any. */
|
|
91
|
+
export declare function getPlatformTracer(): PlatformTracer | undefined;
|
|
63
92
|
/**
|
|
64
93
|
* Get the timber.js OTEL tracer. Returns null if @opentelemetry/api is not available.
|
|
65
94
|
*/
|
|
66
95
|
export declare function getTracer(): Promise<import('@opentelemetry/api').Tracer | null>;
|
|
67
96
|
/**
|
|
68
|
-
* Run a function within
|
|
69
|
-
*
|
|
97
|
+
* Run a function within a framework span. Composes two emission channels:
|
|
98
|
+
*
|
|
99
|
+
* - **Native platform span** — when an adapter registered a PlatformTracer
|
|
100
|
+
* (Cloudflare Workers), the fn is wrapped in platformTracer.enterSpan()
|
|
101
|
+
* so it appears in the platform's native trace view.
|
|
102
|
+
* - **OTEL span** — when an OTEL SDK is active, the fn also runs inside an
|
|
103
|
+
* OTEL span (dual emission). No SDK and no platform tracer = zero overhead.
|
|
70
104
|
*
|
|
71
105
|
* Automatically:
|
|
72
106
|
* - Creates the span as a child of the current context
|
|
73
107
|
* - Updates the ALS span ID for log–trace correlation
|
|
74
108
|
* - Ends the span when the function completes
|
|
75
|
-
* - Records exceptions on error
|
|
109
|
+
* - Records exceptions on error (OTEL channel)
|
|
76
110
|
*/
|
|
77
111
|
export declare function withSpan<T>(name: string, attributes: Record<string, string | number | boolean>, fn: () => T | Promise<T>): Promise<T>;
|
|
78
112
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/server/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG9D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,MAAM,CASnC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAKhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,SAAS,CAEtD;AAcD;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,wBAAwB,EAAE,eAAe,GACvD,OAAO,CAAC,IAAI,CAAC,CA4Cf;AA4BD;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC,CAUrF;AAED
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/server/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG9D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,MAAM,CASnC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAKhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,SAAS,CAEtD;AAcD;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,wBAAwB,EAAE,eAAe,GACvD,OAAO,CAAC,IAAI,CAAC,CA4Cf;AAID;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;CACnE;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,CAAC,GAAG,CAAC,CAAC;CAC9D;AAOD,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,CAE1E;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AA4BD;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC,CAUrF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EACrD,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAkCD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAC/B,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GACrD,IAAI,CASN;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAc/F"}
|
|
@@ -93,7 +93,8 @@ Redis-backed cache handler. Takes a client wrapped to timber's `RedisClient` con
|
|
|
93
93
|
interface RedisClient {
|
|
94
94
|
get(key: string): Promise<string | null>;
|
|
95
95
|
set(key: string, value: string, ttlSeconds: number): Promise<unknown>;
|
|
96
|
-
|
|
96
|
+
expireNX(key: string, seconds: number): Promise<unknown>;
|
|
97
|
+
expireGT(key: string, seconds: number): Promise<unknown>;
|
|
97
98
|
del(key: string): Promise<unknown>; // single key
|
|
98
99
|
sadd(key: string, ...members: string[]): Promise<unknown>;
|
|
99
100
|
srem(key: string, ...members: string[]): Promise<unknown>;
|
|
@@ -102,6 +103,8 @@ interface RedisClient {
|
|
|
102
103
|
}
|
|
103
104
|
```
|
|
104
105
|
|
|
106
|
+
`expireNX` and `expireGT` map to Redis 7.0's `EXPIRE key seconds NX|GT` subcommands. `NX` sets the TTL only if none exists, `GT` extends only if greater. Both are used internally for atomic tag set TTL management. Separate methods ensure adapters cannot silently drop the mode. Requires **Redis 7.0+**.
|
|
107
|
+
|
|
105
108
|
This is deliberately not the native shape of any client library — ioredis, node-redis, and @upstash/redis disagree on TTL argument shapes and method casing, and a contract that pattern-matches one client lets another silently write keys with no expiry. Wrap your client with one of these adapters:
|
|
106
109
|
|
|
107
110
|
```ts title="ioredis"
|
|
@@ -112,7 +115,8 @@ const redis = new Redis(process.env.REDIS_URL!);
|
|
|
112
115
|
const handler = new RedisCacheHandler({
|
|
113
116
|
get: (k) => redis.get(k),
|
|
114
117
|
set: (k, v, ttl) => redis.set(k, v, 'EX', ttl),
|
|
115
|
-
|
|
118
|
+
expireNX: (k, s) => redis.expire(k, s, 'NX'),
|
|
119
|
+
expireGT: (k, s) => redis.expire(k, s, 'GT'),
|
|
116
120
|
del: (k) => redis.del(k),
|
|
117
121
|
sadd: (k, ...m) => redis.sadd(k, ...m),
|
|
118
122
|
srem: (k, ...m) => redis.srem(k, ...m),
|
|
@@ -130,7 +134,8 @@ await redis.connect();
|
|
|
130
134
|
const handler = new RedisCacheHandler({
|
|
131
135
|
get: (k) => redis.get(k),
|
|
132
136
|
set: (k, v, ttl) => redis.set(k, v, { EX: ttl }),
|
|
133
|
-
|
|
137
|
+
expireNX: (k, s) => redis.expire(k, s, 'NX'),
|
|
138
|
+
expireGT: (k, s) => redis.expire(k, s, 'GT'),
|
|
134
139
|
del: (k) => redis.del(k),
|
|
135
140
|
sadd: (k, ...m) => redis.sAdd(k, m),
|
|
136
141
|
srem: (k, ...m) => redis.sRem(k, m),
|
|
@@ -153,7 +158,8 @@ const redis = new Redis({
|
|
|
153
158
|
const handler = new RedisCacheHandler({
|
|
154
159
|
get: (k) => redis.get(k),
|
|
155
160
|
set: (k, v, ttl) => redis.set(k, v, { ex: ttl }),
|
|
156
|
-
|
|
161
|
+
expireNX: (k, s) => redis.expire(k, s, 'NX'),
|
|
162
|
+
expireGT: (k, s) => redis.expire(k, s, 'GT'),
|
|
157
163
|
del: (k) => redis.del(k),
|
|
158
164
|
sadd: (k, ...m) => redis.sadd(k, m[0], ...m.slice(1)),
|
|
159
165
|
srem: (k, ...m) => redis.srem(k, m[0], ...m.slice(1)),
|
|
@@ -31,26 +31,21 @@ All web frameworks are created out of some basic philosophies of how its creator
|
|
|
31
31
|
|
|
32
32
|
Here's ours:
|
|
33
33
|
|
|
34
|
-
A good web architecture
|
|
34
|
+
A good web architecture _embraces_ the complexity of building websites. Since building a website is inherently complex, a framework that embraces that complexity will inevitably feel overwhelming at first. But I'd implore you to imagine it as a toolbelt that gives you access to each tool in the toolkit. As you understand the tools, the toolbelt falls into place.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
So while a beginner could pick up this framework, and it could incrementally teach them each component of building a powerful website, this framework is _not_ designed to be the simplest mental model. This is a framework for the frontend professional. Or a team building a complex and powerful web experience.
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
------
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
* the distinction between build-time and request-time
|
|
42
|
-
* static routes and dynamic routes co-existing
|
|
43
|
-
* zero-javascript websites and fully static js-only SPAs
|
|
44
|
-
* how to build a composable architecture that still feels like it sits on web standards
|
|
40
|
+
This all sounds like a lot. I'm not here to say it isn't. But if you're building a serious website, if you work on a team of experienced engineers, an architecture that sits across these complexities and doesn't abstract them gives you the power to define your boundaries: server and client, static and dynamic, client js and not.
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
To learn the inherent complexity of these ideas, you internalize an architecture that can scale up and down. One that gives you access to both UX and DX that is unparalleled and not limited. Timber does not dumb down our abstractions to make it easier to _understand_, because that comes at the cost of optionality.
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
Other frameworks that have pursued this have either abstracted away too much, leaned on too much magic, or ignored web standards. Timber is _not_ smarter than you. It doesn't try to be. You can write an inefficient website in Timber, and it won't stop you. But it also won't project onto you _how_ to build a website. It just gives you the foundation to control it yourself.
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
The good news is, you don't have to understand this all immediately. You can layer on your understanding one by one. And I promise, in the long-term it will click. But you may have to touch it yourself for it to click.
|
|
46
|
+
Again, if you're new to building websites, this is a tall task.
|
|
53
47
|
|
|
48
|
+
But the good news is, you don't have to understand this all immediately. You can layer on your understanding one by one. And I promise, in the long-term it will click. But you may have to touch it yourself one by one.
|
|
54
49
|
|
|
55
50
|
{/* Here are our basic philosophies:
|
|
56
51
|
|
|
@@ -135,4 +135,13 @@ app/
|
|
|
135
135
|
page.tsx # /
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
+
## Deterministic Route Discovery
|
|
139
|
+
|
|
140
|
+
timber produces build errors for ambiguous route configurations:
|
|
141
|
+
|
|
142
|
+
- **Duplicate convention files** — `page.tsx` and `page.jsx` in the same directory is an error, not a silent winner-by-filesystem-order
|
|
143
|
+
- **Route group collisions** — two route groups in the same slot that both define a page for the same URL path are caught at build time
|
|
144
|
+
|
|
145
|
+
This behavior is deterministic regardless of filesystem `readdir` order. In Next.js, the result of these ambiguities depends on the OS and filesystem, which can produce different behavior between local development and CI.
|
|
146
|
+
|
|
138
147
|
For dynamic segments, advanced routing patterns (parallel routes, intercepting routes, catch-all segments), and API routes, see [Advanced Routing](/docs/advanced-routing).
|
|
@@ -100,10 +100,6 @@ errors.getFieldError('title'); // string | null (first error for field)
|
|
|
100
100
|
| `revalidatePath('/path')` | Current page needs fresh data |
|
|
101
101
|
| `useOptimistic` | Instant UI update, action confirms in background |
|
|
102
102
|
|
|
103
|
-
## Middleware Runs on Actions
|
|
104
|
-
|
|
105
|
-
Route middleware (`middleware.ts`) runs on every server action POST by default, just like page renders. Auth, rate limiting, and header injection in `middleware.ts` apply to actions automatically.
|
|
106
|
-
|
|
107
103
|
## Forms Without JavaScript
|
|
108
104
|
|
|
109
105
|
When JavaScript is disabled and a server action returns validation errors, timber re-renders the page instead of redirecting. The errors and submitted values are available via `getFormFlash()`:
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Typed Routes'
|
|
3
|
+
description: 'Build-time route types — <Link> validates href, params are inferred from the file tree.'
|
|
4
|
+
slug: 'typed-routes'
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Typed Routes
|
|
8
|
+
|
|
9
|
+
timber.js generates route types at build time. `<Link>` type-checks `href` against your actual route tree. Segment params are inferred from directory names. Search params are typed when you define them.
|
|
10
|
+
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
13
|
+
When you run `timber dev` or `timber build`, the framework scans your `app/` directory and generates a route map in `.timber/routes.d.ts`:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// .timber/routes.d.ts (generated, gitignored)
|
|
17
|
+
export interface TimberSegmentParams {
|
|
18
|
+
'/': {};
|
|
19
|
+
'/products/[id]': { id: number };
|
|
20
|
+
'/blog/[...slug]': { slug: string[] };
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Types reference your `app/schema.ts` codecs directly, so they stay in sync automatically.
|
|
25
|
+
|
|
26
|
+
## Typed `<Link>`
|
|
27
|
+
|
|
28
|
+
`<Link>` validates `href` against the route map. Invalid routes are caught at build time:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { Link } from '@timber-js/app/client';
|
|
32
|
+
|
|
33
|
+
<Link href="/about">About</Link> // ✓ known route
|
|
34
|
+
<Link href="/nonexistent">Bad</Link> // ✗ TypeScript error
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For dynamic routes, pass `segmentParams`:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { Link } from '@timber-js/app/client';
|
|
41
|
+
|
|
42
|
+
<Link href="/products/[id]" segmentParams={{ id: 42 }}>
|
|
43
|
+
Product
|
|
44
|
+
</Link>
|
|
45
|
+
// → <a href="/products/42">Product</a>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or use an interpolated href directly:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<Link href={`/products/${id}`}>Product</Link>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Both forms are type-safe. With the pattern form (`/products/[id]`), `segmentParams` is required and typed. With the interpolated form, `segmentParams` is forbidden.
|
|
55
|
+
|
|
56
|
+
## Typed Segment Params
|
|
57
|
+
|
|
58
|
+
Each route directory gets a generated `$segment` module. Import `SEGMENT_PATH` for type-safe param access:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
// app/products/[id]/page.tsx
|
|
62
|
+
import { SEGMENT_PATH } from './$segment';
|
|
63
|
+
import { getSegmentParams } from '@timber-js/app/server';
|
|
64
|
+
|
|
65
|
+
export default async function ProductPage() {
|
|
66
|
+
const { id } = getSegmentParams(SEGMENT_PATH);
|
|
67
|
+
// id is typed from your schema codec (e.g., number for codec.integer)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Without `SEGMENT_PATH`, params are untyped — all optional strings.
|
|
72
|
+
|
|
73
|
+
### tsconfig.json
|
|
74
|
+
|
|
75
|
+
Add `rootDirs` so TypeScript can resolve `$segment` imports:
|
|
76
|
+
|
|
77
|
+
```jsonc
|
|
78
|
+
{
|
|
79
|
+
"compilerOptions": {
|
|
80
|
+
"rootDirs": [".", ".timber/types"]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Typed Search Params
|
|
86
|
+
|
|
87
|
+
When a `params.ts` file exports `searchParams`, search params are fully typed throughout the stack:
|
|
88
|
+
|
|
89
|
+
```ts title="app/products/params.ts"
|
|
90
|
+
import { defineSearchParams, withDefault, withUrlKey } from '@timber-js/app/search-params';
|
|
91
|
+
import { parseAsInteger, parseAsString, parseAsStringEnum } from 'nuqs';
|
|
92
|
+
import { z } from 'zod/v4';
|
|
93
|
+
|
|
94
|
+
export const searchParams = defineSearchParams({
|
|
95
|
+
page: withDefault(parseAsInteger, 1),
|
|
96
|
+
q: withUrlKey(parseAsString, 'search'),
|
|
97
|
+
category: z.string().nullable().default(null),
|
|
98
|
+
sort: withDefault(parseAsStringEnum(['price-asc', 'price-desc', 'newest']), 'newest'),
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```tsx title="app/products/page.tsx"
|
|
103
|
+
import { searchParams } from './params';
|
|
104
|
+
|
|
105
|
+
export default async function ProductsPage() {
|
|
106
|
+
const { page, q, category, sort } = await searchParams.get();
|
|
107
|
+
// page: number, q: string | null, category: string | null, sort: 'price-asc' | ...
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`<Link>` validates `searchParams` against the route's definition too:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<Link
|
|
115
|
+
href="/products/[id]"
|
|
116
|
+
segmentParams={{ id }}
|
|
117
|
+
searchParams={{ sort: 'newest', q: 'boots' }}
|
|
118
|
+
/>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
See [Typed Params](/docs/typed-params) for the full search params API.
|
|
122
|
+
|
|
123
|
+
## Codegen
|
|
124
|
+
|
|
125
|
+
Types are generated during `timber dev` (on startup and when routes change) and `timber build`. The generated `.timber/routes.d.ts` is gitignored — it's a build artifact. Run `timber dev` once to get types for your editor.
|
|
126
|
+
|
|
127
|
+
For the full type definitions and context types (`RouteContext`, `MiddlewareContext`, `AccessContext`), see the [TypeScript API Reference](/docs/api-typescript).
|
|
@@ -70,7 +70,18 @@ const getUser = cache(
|
|
|
70
70
|
|
|
71
71
|
## Cache Keys
|
|
72
72
|
|
|
73
|
-
Without an explicit `key`, the cache key is derived from the call site plus a deterministic serialization of the arguments.
|
|
73
|
+
Without an explicit `key`, the cache key is derived from the call site plus a deterministic serialization of the arguments.
|
|
74
|
+
|
|
75
|
+
### Content-Derived Cache Identities
|
|
76
|
+
|
|
77
|
+
The call-site identity is content-based — derived from the source code of the `cache()` call, not its position in the file. This means:
|
|
78
|
+
|
|
79
|
+
- **Unchanged code = cache survives deploys.** If you redeploy without changing a cached function, its entries remain valid on persistent handlers like Redis or KV.
|
|
80
|
+
- **Changed code = automatic invalidation.** Editing the wrapped function or its options changes the cache identity, which invalidates old entries without manual cache busting.
|
|
81
|
+
|
|
82
|
+
This works for namespace imports, re-exports, and other patterns where the call site isn't trivially traceable. For callsites that can't be statically traced, a deterministic source-hash runtime fallback ensures cache identities never collide across instances.
|
|
83
|
+
|
|
84
|
+
Object key order doesn't matter — `{ a: 1, b: 2 }` and `{ b: 2, a: 1 }` produce the same key. `Date`, `URL`, and anything with a `toJSON()` method serialize the way `JSON.stringify` would; `Map` and `Set` are serialized by their entries.
|
|
74
85
|
|
|
75
86
|
Arguments that can't be serialized faithfully — functions, symbols, or class instances whose data lives behind getters with no `toJSON()` — throw a `TypeError` instead of silently colliding. If you hit this, pass an explicit `key`:
|
|
76
87
|
|
|
@@ -129,6 +129,15 @@ export default function ErrorPage({
|
|
|
129
129
|
|
|
130
130
|
The HTTP status stays correct either way — `deny(404)` falling through to `error.tsx` still responds with a 404, never a 500.
|
|
131
131
|
|
|
132
|
+
## Connection Abort Suppression
|
|
133
|
+
|
|
134
|
+
When a user refreshes the page or navigates away while Suspense boundaries are still streaming, the aborted connection would normally cause errors in both the RSC and SSR streams. timber detects these aborts and suppresses them at multiple layers:
|
|
135
|
+
|
|
136
|
+
- **Server-side:** The request's `AbortSignal` is passed to React's `renderToReadableStream`. React stops rendering on abort without firing `onError`. SSR detects the abort and closes the stream silently.
|
|
137
|
+
- **Client-side:** The error boundary checks for page unload (`beforeunload`/`pagehide`) and suppresses error boundary activation. The client router silently discards `AbortError` from aborted fetches.
|
|
138
|
+
|
|
139
|
+
A page refresh during streaming never shows a flash of an error boundary. This is a common issue in Next.js where mid-stream refreshes can briefly display error UI.
|
|
140
|
+
|
|
132
141
|
## Structured Error Data
|
|
133
142
|
|
|
134
143
|
`deny()` accepts optional JSON-serializable data that is passed to the error page via `dangerouslyPassData`:
|
|
@@ -92,6 +92,34 @@ export default {
|
|
|
92
92
|
|
|
93
93
|
The default is in-memory. See [Caching](/docs/caching) for Redis, KV, and custom handlers.
|
|
94
94
|
|
|
95
|
+
## `clientJavascript`
|
|
96
|
+
|
|
97
|
+
Control whether client-side JavaScript is included in the build. Useful for static content sites, documentation, and marketing pages that don't need interactivity.
|
|
98
|
+
|
|
99
|
+
```ts title="timber.config.ts"
|
|
100
|
+
// Disable all client JS
|
|
101
|
+
export default {
|
|
102
|
+
output: 'static',
|
|
103
|
+
clientJavascript: false,
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```ts title="timber.config.ts"
|
|
108
|
+
// No client JS in production, but keep HMR in dev
|
|
109
|
+
export default {
|
|
110
|
+
output: 'static',
|
|
111
|
+
clientJavascript: { disabled: true, enableHMRInDev: true },
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
| Value | Behavior |
|
|
116
|
+
| ------------------------------------------ | ----------------------------------------------------------- |
|
|
117
|
+
| `true` (default) | Client JS enabled — hydration, SPA navigation, etc. |
|
|
118
|
+
| `false` | All client JS disabled. No hydration, no SPA navigation. |
|
|
119
|
+
| `{ disabled: true, enableHMRInDev: true }` | No client JS in production, but HMR still works in dev. |
|
|
120
|
+
|
|
121
|
+
Server actions still work — HTML forms submit natively via POST without JavaScript.
|
|
122
|
+
|
|
95
123
|
## All Options
|
|
96
124
|
|
|
97
125
|
| Option | Type | Default | Description |
|