@timber-js/app 0.2.0-alpha.71 → 0.2.0-alpha.72
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-Dg-ANYHb.js +421 -0
- package/dist/_chunks/actions-Dg-ANYHb.js.map +1 -0
- package/dist/_chunks/{als-registry-BJARkOcu.js → als-registry-HS0LGUl2.js} +1 -1
- package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
- package/dist/_chunks/{define-Dz1bqwaS.js → define-C77ScO0m.js} +14 -14
- package/dist/_chunks/define-C77ScO0m.js.map +1 -0
- package/dist/_chunks/{define-CGuYoRHU.js → define-CZqDwhSu.js} +15 -15
- package/dist/_chunks/define-CZqDwhSu.js.map +1 -0
- package/dist/_chunks/{define-cookie-B5mewxwM.js → define-cookie-C2IkoFGN.js} +9 -8
- package/dist/_chunks/{define-cookie-B5mewxwM.js.map → define-cookie-C2IkoFGN.js.map} +1 -1
- package/dist/_chunks/{format-Rn922VH2.js → dev-warnings-DpGRGoDi.js} +4 -26
- package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
- package/dist/_chunks/format-CYBGxKtc.js +14 -0
- package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
- package/dist/_chunks/{interception-CEdHHviP.js → interception-Dpn_UfAD.js} +2 -2
- package/dist/_chunks/{interception-CEdHHviP.js.map → interception-Dpn_UfAD.js.map} +1 -1
- package/dist/_chunks/{segment-context-hzuJ048X.js → merge-search-params-Cm_KIWDX.js} +2 -33
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
- package/dist/_chunks/{request-context-CywiO4jV.js → request-context-qMsWgy9C.js} +72 -36
- package/dist/_chunks/request-context-qMsWgy9C.js.map +1 -0
- package/dist/_chunks/{schema-bridge-C4SwjCQD.js → schema-bridge-C3xl_vfb.js} +1 -1
- package/dist/_chunks/{schema-bridge-C4SwjCQD.js.map → schema-bridge-C3xl_vfb.js.map} +1 -1
- package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
- package/dist/_chunks/ssr-data-DzuI0bIV.js +88 -0
- package/dist/_chunks/ssr-data-DzuI0bIV.js.map +1 -0
- package/dist/_chunks/{stale-reload-BLUC_Pl_.js → stale-reload-C2plcNtG.js} +1 -1
- package/dist/_chunks/{stale-reload-BLUC_Pl_.js.map → stale-reload-C2plcNtG.js.map} +1 -1
- package/dist/_chunks/{handler-store-BVePM7hp.js → tracing-CCYbKn5n.js} +60 -60
- package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
- package/dist/_chunks/use-params-B1AuhI1p.js +307 -0
- package/dist/_chunks/use-params-B1AuhI1p.js.map +1 -0
- package/dist/_chunks/{use-query-states-DAhgj8Gx.js → use-query-states-Lo_s_pw2.js} +4 -4
- package/dist/_chunks/use-query-states-Lo_s_pw2.js.map +1 -0
- package/dist/_chunks/{wrappers-LZbghvn0.js → wrappers-_DTmImGt.js} +1 -1
- package/dist/_chunks/{wrappers-LZbghvn0.js.map → wrappers-_DTmImGt.js.map} +1 -1
- package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +95 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/cache/index.d.ts +18 -4
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +78 -12
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/sizeof.d.ts +22 -0
- package/dist/cache/sizeof.d.ts.map +1 -0
- package/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -1
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +27 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +46 -0
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
- package/dist/client/browser-entry/index.d.ts +30 -0
- package/dist/client/browser-entry/index.d.ts.map +1 -0
- package/dist/client/browser-entry/post-hydration.d.ts +26 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +23 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +19 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/error-boundary.js +131 -1
- package/dist/client/error-boundary.js.map +1 -0
- package/dist/client/index.d.ts +4 -19
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +14 -1191
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +18 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +890 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/top-loader.d.ts +2 -2
- package/dist/client/use-link-status.d.ts +1 -1
- package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-router.d.ts +1 -1
- package/dist/codec.d.ts +10 -0
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/config-types.d.ts +210 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +0 -2
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +2 -3
- package/dist/index.d.ts +25 -288
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +261 -43
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +84 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +1 -1
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-browser-logs.d.ts +1 -1
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -1
- package/dist/plugins/dev-logs.d.ts +1 -1
- package/dist/plugins/dev-logs.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +1 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +4 -4
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/search-params/define.d.ts +6 -6
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.d.ts +1 -2
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +4 -4
- package/dist/search-params/registry.d.ts +1 -1
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/segment-params/define.d.ts +6 -6
- package/dist/segment-params/define.d.ts.map +1 -1
- package/dist/segment-params/index.d.ts +0 -1
- package/dist/segment-params/index.d.ts.map +1 -1
- package/dist/segment-params/index.js +3 -3
- package/dist/server/als-registry.d.ts +1 -1
- package/dist/server/dev-holding-server.d.ts +52 -0
- package/dist/server/dev-holding-server.d.ts.map +1 -0
- package/dist/server/dev-warnings.d.ts +1 -7
- package/dist/server/dev-warnings.d.ts.map +1 -1
- package/dist/server/index.d.ts +6 -45
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +7 -3272
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +46 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +2865 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +41 -17
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +45 -15
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +4 -4
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +2 -1
- package/dist/shims/navigation.d.ts.map +1 -1
- package/package.json +19 -13
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/cache/handler-store.ts +2 -2
- package/src/cache/index.ts +74 -15
- package/src/cache/sizeof.ts +31 -0
- package/src/cli.ts +6 -1
- package/src/client/browser-dev.ts +128 -1
- package/src/client/browser-entry/action-dispatch.ts +116 -0
- package/src/client/browser-entry/hmr.ts +81 -0
- package/src/client/browser-entry/hydrate.ts +145 -0
- package/src/client/browser-entry/index.ts +138 -0
- package/src/client/browser-entry/post-hydration.ts +119 -0
- package/src/client/browser-entry/router-init.ts +184 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +27 -0
- package/src/client/index.ts +10 -38
- package/src/client/internal.ts +57 -0
- package/src/client/navigation-context.ts +6 -2
- package/src/client/navigation-root.tsx +1 -1
- package/src/client/router-ref.ts +1 -1
- package/src/client/top-loader.tsx +2 -2
- package/src/client/use-link-status.ts +1 -1
- package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +5 -5
- package/src/client/use-query-states.ts +2 -2
- package/src/client/use-router.ts +1 -1
- package/src/codec.ts +15 -0
- package/src/config-types.ts +208 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +9 -7
- package/src/cookies/index.ts +6 -5
- package/src/index.ts +84 -416
- package/src/plugin-context.ts +200 -0
- package/src/plugins/adapter-build.ts +1 -1
- package/src/plugins/build-manifest.ts +1 -1
- package/src/plugins/build-report.ts +1 -1
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-browser-logs.ts +1 -1
- package/src/plugins/dev-logs.ts +1 -1
- package/src/plugins/dev-server.ts +16 -1
- package/src/plugins/entries.ts +2 -2
- package/src/plugins/fonts.ts +4 -3
- package/src/plugins/mdx.ts +1 -1
- package/src/plugins/routing.ts +1 -1
- package/src/plugins/shims.ts +53 -5
- package/src/plugins/static-build.ts +8 -6
- package/src/search-params/define.ts +22 -22
- package/src/search-params/index.ts +3 -3
- package/src/search-params/registry.ts +1 -1
- package/src/segment-params/define.ts +18 -18
- package/src/segment-params/index.ts +2 -1
- package/src/server/action-handler.ts +1 -1
- package/src/server/als-registry.ts +3 -3
- package/src/server/dev-holding-server.ts +185 -0
- package/src/server/dev-warnings.ts +2 -21
- package/src/server/html-injectors.ts +3 -3
- package/src/server/index.ts +25 -180
- package/src/server/internal.ts +169 -0
- package/src/server/pipeline.ts +12 -7
- package/src/server/primitives.ts +71 -30
- package/src/server/request-context.ts +77 -39
- package/src/server/route-element-builder.ts +1 -1
- package/src/server/rsc-entry/index.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +1 -1
- package/src/server/slot-resolver.ts +1 -1
- package/src/server/tracing.ts +6 -6
- package/src/server/tree-builder.ts +1 -1
- package/src/shims/headers.ts +5 -1
- package/src/shims/navigation.ts +5 -1
- package/dist/_chunks/als-registry-BJARkOcu.js.map +0 -1
- package/dist/_chunks/define-CGuYoRHU.js.map +0 -1
- package/dist/_chunks/define-Dz1bqwaS.js.map +0 -1
- package/dist/_chunks/error-boundary-D9hzsveV.js +0 -216
- package/dist/_chunks/error-boundary-D9hzsveV.js.map +0 -1
- package/dist/_chunks/format-Rn922VH2.js.map +0 -1
- package/dist/_chunks/handler-store-BVePM7hp.js.map +0 -1
- package/dist/_chunks/request-context-CywiO4jV.js.map +0 -1
- package/dist/_chunks/segment-context-hzuJ048X.js.map +0 -1
- package/dist/_chunks/use-query-states-DAhgj8Gx.js.map +0 -1
- package/dist/client/browser-entry.d.ts +0 -21
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/src/client/browser-entry.ts +0 -846
package/src/index.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @timber-js/app — Root entry point (public API).
|
|
3
|
+
*
|
|
4
|
+
* User-facing exports: timber(), defineConfig(), TimberUserConfig, Routes.
|
|
5
|
+
*
|
|
6
|
+
* Internal helpers (PluginContext, resolveAppDir, loadTimberConfigFile,
|
|
7
|
+
* warnConfigConflicts, resolveClientJavascript) live in plugin-context.ts
|
|
8
|
+
* and are NOT re-exported here. Sub-plugins import them via relative paths.
|
|
9
|
+
*
|
|
10
|
+
* Design doc: 18-build-system.md §"Plugin Architecture"
|
|
11
|
+
*/
|
|
12
|
+
|
|
1
13
|
import type { Plugin, PluginOption } from 'vite';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
14
|
import { join, resolve } from 'node:path';
|
|
4
15
|
import { createRequire } from 'node:module';
|
|
5
16
|
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
|
|
@@ -21,401 +32,59 @@ import { clientChunkGroup } from './plugins/client-chunks';
|
|
|
21
32
|
import { timberServerBundle } from './plugins/server-bundle';
|
|
22
33
|
import { timberAdapterBuild } from './plugins/adapter-build';
|
|
23
34
|
import { timberBuildReport } from './plugins/build-report';
|
|
24
|
-
import
|
|
25
|
-
import type { BuildManifest } from './server/build-manifest';
|
|
26
|
-
import type { StartupTimer } from './utils/startup-timer';
|
|
27
|
-
import { createStartupTimer, createNoopTimer } from './utils/startup-timer';
|
|
35
|
+
import { createNoopTimer } from './utils/startup-timer';
|
|
28
36
|
import { resolveEncryptionKeyExpression, shouldEnableEncryption } from './server/action-encryption';
|
|
37
|
+
import { createHoldingServer } from './server/dev-holding-server.js';
|
|
38
|
+
import type { TimberUserConfig } from './config-types.js';
|
|
39
|
+
import type { PluginContext } from './plugin-context.js';
|
|
40
|
+
import {
|
|
41
|
+
createPluginContext,
|
|
42
|
+
loadTimberConfigFile,
|
|
43
|
+
mergeFileConfig,
|
|
44
|
+
resolveAppDir,
|
|
45
|
+
resolveClientJavascript,
|
|
46
|
+
} from './plugin-context.js';
|
|
29
47
|
|
|
30
|
-
|
|
31
|
-
export interface ClientJavascriptConfig {
|
|
32
|
-
/** When true, no client JS bundles are emitted or referenced in HTML. */
|
|
33
|
-
disabled: boolean;
|
|
34
|
-
/**
|
|
35
|
-
* When `disabled` is true, still inject the Vite HMR client in dev mode
|
|
36
|
-
* so hot reloading works during development. Default: true.
|
|
37
|
-
*/
|
|
38
|
-
enableHMRInDev?: boolean;
|
|
39
|
-
}
|
|
48
|
+
// ── Public API ────────────────────────────────────────────────────────────
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
export interface ResolvedClientJavascript {
|
|
43
|
-
disabled: boolean;
|
|
44
|
-
enableHMRInDev: boolean;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface TimberUserConfig {
|
|
48
|
-
output?: 'server' | 'static';
|
|
49
|
-
/**
|
|
50
|
-
* Enable timber debug logging in production builds.
|
|
51
|
-
*
|
|
52
|
-
* When `true`, timber's own diagnostics (dev warnings, verbose logging)
|
|
53
|
-
* are active even in production mode. React stays in production mode —
|
|
54
|
-
* only timber's logs are affected.
|
|
55
|
-
*
|
|
56
|
-
* Can also be enabled at runtime via the `TIMBER_DEBUG` environment variable.
|
|
57
|
-
*
|
|
58
|
-
* Default: `false`.
|
|
59
|
-
*/
|
|
60
|
-
debug?: boolean;
|
|
61
|
-
/**
|
|
62
|
-
* Control client-side JavaScript output.
|
|
63
|
-
*
|
|
64
|
-
* Boolean shorthand:
|
|
65
|
-
* `clientJavascript: false` disables all client JS (equivalent to `{ disabled: true }`).
|
|
66
|
-
* `clientJavascript: true` enables client JS (the default).
|
|
67
|
-
*
|
|
68
|
-
* Object form:
|
|
69
|
-
* `clientJavascript: { disabled: true, enableHMRInDev: true }` disables client JS
|
|
70
|
-
* in production but preserves Vite HMR in dev mode.
|
|
71
|
-
*
|
|
72
|
-
* When `disabled` is true, `enableHMRInDev` defaults to `true`.
|
|
73
|
-
* Server-side JS still runs — this only affects what is sent to the browser.
|
|
74
|
-
*/
|
|
75
|
-
clientJavascript?: boolean | ClientJavascriptConfig;
|
|
76
|
-
adapter?: unknown;
|
|
77
|
-
cacheHandler?: unknown;
|
|
78
|
-
allowedOrigins?: string[];
|
|
79
|
-
csrf?: boolean;
|
|
80
|
-
limits?: {
|
|
81
|
-
actionBodySize?: string;
|
|
82
|
-
uploadBodySize?: string;
|
|
83
|
-
maxFields?: number;
|
|
84
|
-
};
|
|
85
|
-
pageExtensions?: string[];
|
|
86
|
-
/**
|
|
87
|
-
* Slow request threshold in milliseconds. Requests exceeding this emit
|
|
88
|
-
* a warning via the logger. Set to 0 to disable. Default: 3000.
|
|
89
|
-
*
|
|
90
|
-
* See design/17-logging.md §"slowRequestMs".
|
|
91
|
-
*/
|
|
92
|
-
slowRequestMs?: number;
|
|
93
|
-
/**
|
|
94
|
-
* Render timeout in milliseconds. If an SSR render or RSC stream read
|
|
95
|
-
* does not complete within this duration, the render is aborted and
|
|
96
|
-
* the connection is closed. Protects against hung fetches and Suspense
|
|
97
|
-
* components that never resolve.
|
|
98
|
-
*
|
|
99
|
-
* Set to 0 to disable (not recommended in production).
|
|
100
|
-
* Default: 30000 (30 seconds).
|
|
101
|
-
*
|
|
102
|
-
* See design/02-rendering-pipeline.md §"Streaming Constraints".
|
|
103
|
-
*/
|
|
104
|
-
renderTimeoutMs?: number;
|
|
105
|
-
/**
|
|
106
|
-
* Forward browser console output to the server terminal in dev mode.
|
|
107
|
-
*
|
|
108
|
-
* Sets the minimum log level to forward:
|
|
109
|
-
* - `'error'` — only `console.error`
|
|
110
|
-
* - `'warn'` — `console.error` + `console.warn` (default)
|
|
111
|
-
* - `'info'` — `console.error` + `console.warn` + `console.info`
|
|
112
|
-
* - `'none'` — disabled
|
|
113
|
-
*
|
|
114
|
-
* Does not intercept `console.log` or `console.debug` (too noisy).
|
|
115
|
-
* No effect in production builds.
|
|
116
|
-
*
|
|
117
|
-
* See TIM-513.
|
|
118
|
-
*/
|
|
119
|
-
devBrowserLogs?: 'error' | 'warn' | 'info' | 'none';
|
|
120
|
-
/** Dev-mode options. These have no effect in production builds. */
|
|
121
|
-
dev?: {
|
|
122
|
-
/** Threshold in ms to highlight slow phases in dev logging output. Default: 200. */
|
|
123
|
-
slowPhaseMs?: number;
|
|
124
|
-
};
|
|
125
|
-
/**
|
|
126
|
-
* Control Server-Timing header output.
|
|
127
|
-
*
|
|
128
|
-
* - `'detailed'` — per-phase breakdown (proxy, middleware, render). Useful
|
|
129
|
-
* for APM / network monitoring. Exposes phase names to clients.
|
|
130
|
-
* - `'total'` — single `total;dur=N` entry. Safe to expose, gives
|
|
131
|
-
* browser DevTools useful timing without internal details.
|
|
132
|
-
* - `false` — no Server-Timing header at all.
|
|
133
|
-
*
|
|
134
|
-
* Default: `'detailed'` in dev, `'total'` in production.
|
|
135
|
-
*
|
|
136
|
-
* This is separate from `debug` / `TIMBER_DEBUG` — it's an intentional
|
|
137
|
-
* decision to expose timing data to clients, not a side effect of debug
|
|
138
|
-
* logging.
|
|
139
|
-
*/
|
|
140
|
-
serverTiming?: 'detailed' | 'total' | false;
|
|
141
|
-
/**
|
|
142
|
-
* Override the app directory location. By default, timber auto-detects
|
|
143
|
-
* `app/` at the project root, falling back to `src/app/`.
|
|
144
|
-
*
|
|
145
|
-
* Set this to a relative path from the project root (e.g. `'src/app'`)
|
|
146
|
-
* to use a custom location.
|
|
147
|
-
*/
|
|
148
|
-
appDir?: string;
|
|
149
|
-
/** MDX compilation options passed to @mdx-js/rollup. See design/20-content-collections.md. */
|
|
150
|
-
mdx?: {
|
|
151
|
-
remarkPlugins?: unknown[];
|
|
152
|
-
rehypePlugins?: unknown[];
|
|
153
|
-
recmaPlugins?: unknown[];
|
|
154
|
-
remarkRehypeOptions?: Record<string, unknown>;
|
|
155
|
-
};
|
|
156
|
-
/**
|
|
157
|
-
* Built-in top-loader progress bar for client navigations.
|
|
158
|
-
* Shows an animated bar at the top of the viewport during RSC navigations.
|
|
159
|
-
* Enabled by default — set `enabled: false` to opt out.
|
|
160
|
-
*
|
|
161
|
-
* Users who want a fully custom progress indicator should disable this
|
|
162
|
-
* and use `useNavigationPending()` directly.
|
|
163
|
-
*
|
|
164
|
-
* See LOCAL-336 for design decisions.
|
|
165
|
-
*/
|
|
166
|
-
/**
|
|
167
|
-
* Server action bound args encryption configuration.
|
|
168
|
-
*
|
|
169
|
-
* The RSC plugin encrypts closure variables captured by 'use server' functions
|
|
170
|
-
* using AES-256-GCM so they are opaque and tamper-proof in the Flight payload.
|
|
171
|
-
* Encryption is always enabled in production.
|
|
172
|
-
*
|
|
173
|
-
* The encryption key is auto-generated at build time and embedded in the server bundle,
|
|
174
|
-
* so all instances running the same build share the same key automatically.
|
|
175
|
-
* For rolling/blue-green deployments where multiple builds coexist, set
|
|
176
|
-
* `TIMBER_ACTIONS_ENCRYPTION_KEY` env var to share a key across builds.
|
|
177
|
-
*
|
|
178
|
-
* See design/08-forms-and-actions.md §"Security"
|
|
179
|
-
*/
|
|
180
|
-
actionEncryption?: {
|
|
181
|
-
/**
|
|
182
|
-
* Disable encryption in dev mode for easier debugging of bound args.
|
|
183
|
-
* Has no effect in production — encryption is always enabled.
|
|
184
|
-
* Default: false (encryption is on in dev too).
|
|
185
|
-
*/
|
|
186
|
-
disableInDev?: boolean;
|
|
187
|
-
};
|
|
188
|
-
/**
|
|
189
|
-
* Enable the React Compiler (babel-plugin-react-compiler) for automatic
|
|
190
|
-
* memoization of components and hooks at build time.
|
|
191
|
-
*
|
|
192
|
-
* - `true` — enable with default options
|
|
193
|
-
* - `{ compilationMode, target }` — enable with custom options
|
|
194
|
-
* - `compilationMode: 'annotation'` — only compile files with `'use memo'`
|
|
195
|
-
* - `target: '18'` — target React 18 (uses react-compiler-runtime package)
|
|
196
|
-
* - `false` or omitted — disabled (default)
|
|
197
|
-
*
|
|
198
|
-
* Uses `@vitejs/plugin-react`'s built-in `reactCompilerPreset`, which:
|
|
199
|
-
* - Applies Babel only for the compiler pass (OXC handles JSX)
|
|
200
|
-
* - Automatically scopes to client environment only
|
|
201
|
-
* - Uses `react/compiler-runtime` built into React 19
|
|
202
|
-
*
|
|
203
|
-
* Requires `babel-plugin-react-compiler` as a peer dependency.
|
|
204
|
-
*/
|
|
205
|
-
reactCompiler?: boolean | { compilationMode?: string; target?: string };
|
|
206
|
-
/**
|
|
207
|
-
* Auto-generate sitemap.xml from the route tree.
|
|
208
|
-
*
|
|
209
|
-
* When enabled, timber walks the file-system route tree and produces a sitemap
|
|
210
|
-
* for all discoverable pages. Dynamic routes with `generateStaticParams()` are
|
|
211
|
-
* enumerated. Routes protected by `access.ts` are excluded by default.
|
|
212
|
-
*
|
|
213
|
-
* If a user-authored `sitemap.ts` or `sitemap.xml` exists at the app root,
|
|
214
|
-
* auto-generation is disabled — the user takes full control.
|
|
215
|
-
*
|
|
216
|
-
* Supports automatic pagination (sitemap index) for sites with > 50,000 URLs.
|
|
217
|
-
*
|
|
218
|
-
* See design/16-metadata.md §"Auto-generated Sitemap"
|
|
219
|
-
*/
|
|
220
|
-
sitemap?: {
|
|
221
|
-
/** Must be explicitly `true` to enable auto-generation. Default: false. */
|
|
222
|
-
enabled?: boolean;
|
|
223
|
-
/** Base URL for absolute URLs in the sitemap. Required when enabled. e.g., 'https://example.com' */
|
|
224
|
-
baseUrl?: string;
|
|
225
|
-
/** Default `<changefreq>` for all entries. Optional. */
|
|
226
|
-
defaultChangeFrequency?: string;
|
|
227
|
-
/** Default `<priority>` for all entries (0.0–1.0). Optional. */
|
|
228
|
-
defaultPriority?: number;
|
|
229
|
-
/** Include routes protected by `access.ts`. Default: false. */
|
|
230
|
-
includeProtected?: boolean;
|
|
231
|
-
};
|
|
232
|
-
topLoader?: {
|
|
233
|
-
/** Whether the top-loader is enabled. Default: true. */
|
|
234
|
-
enabled?: boolean;
|
|
235
|
-
/** Bar color. Default: '#2299DD'. */
|
|
236
|
-
color?: string;
|
|
237
|
-
/** Bar height in pixels. Default: 3. */
|
|
238
|
-
height?: number;
|
|
239
|
-
/** Show subtle glow/shadow effect. Default: true. */
|
|
240
|
-
shadow?: boolean;
|
|
241
|
-
/** Delay in ms before showing the bar (avoids flash on fast navs). Default: 0. */
|
|
242
|
-
delay?: number;
|
|
243
|
-
/** CSS z-index. Default: 1600. */
|
|
244
|
-
zIndex?: number;
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Resolve `clientJavascript` into a fully resolved config.
|
|
250
|
-
*/
|
|
251
|
-
export function resolveClientJavascript(config: TimberUserConfig): ResolvedClientJavascript {
|
|
252
|
-
if (config.clientJavascript !== undefined) {
|
|
253
|
-
if (typeof config.clientJavascript === 'boolean') {
|
|
254
|
-
// `clientJavascript: false` → disabled
|
|
255
|
-
// `clientJavascript: true` → enabled (default)
|
|
256
|
-
return {
|
|
257
|
-
disabled: !config.clientJavascript,
|
|
258
|
-
enableHMRInDev: !config.clientJavascript, // default true when disabled
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
// Object form
|
|
262
|
-
return {
|
|
263
|
-
disabled: config.clientJavascript.disabled,
|
|
264
|
-
enableHMRInDev: config.clientJavascript.enableHMRInDev ?? config.clientJavascript.disabled,
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Default: client JS enabled
|
|
269
|
-
return { disabled: false, enableHMRInDev: false };
|
|
270
|
-
}
|
|
50
|
+
export type { TimberUserConfig } from './config-types.js';
|
|
271
51
|
|
|
272
52
|
/**
|
|
273
|
-
*
|
|
53
|
+
* Route map interface — augmented by the generated timber-routes.d.ts.
|
|
274
54
|
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*/
|
|
279
|
-
export interface PluginContext {
|
|
280
|
-
config: TimberUserConfig;
|
|
281
|
-
/** Resolved client JavaScript configuration */
|
|
282
|
-
clientJavascript: ResolvedClientJavascript;
|
|
283
|
-
/** The scanned route tree (populated by timber-routing, consumed by timber-entries) */
|
|
284
|
-
routeTree: RouteTree | null;
|
|
285
|
-
/** Absolute path to the app/ directory */
|
|
286
|
-
appDir: string;
|
|
287
|
-
/** Absolute path to the project root */
|
|
288
|
-
root: string;
|
|
289
|
-
/** Whether the dev server is running (set by timber-root-sync in configResolved) */
|
|
290
|
-
dev: boolean;
|
|
291
|
-
/** CSS build manifest (populated by adapter after client build, null in dev) */
|
|
292
|
-
buildManifest: BuildManifest | null;
|
|
293
|
-
/** Per-build deployment ID for version skew detection (null in dev) */
|
|
294
|
-
deploymentId: string | null;
|
|
295
|
-
/** Startup timer for profiling cold start phases (active in dev, no-op in prod) */
|
|
296
|
-
timer: StartupTimer;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Resolve the app directory. Checks (in order):
|
|
301
|
-
* 1. Explicit `configAppDir` from timber.config.ts
|
|
302
|
-
* 2. `<root>/app`
|
|
303
|
-
* 3. `<root>/src/app`
|
|
55
|
+
* Each key is a route path pattern. Values have:
|
|
56
|
+
* segmentParams: shape of URL segment params (e.g. { id: string })
|
|
57
|
+
* searchParams: parsed type from search-params.ts, or {} if none
|
|
304
58
|
*
|
|
305
|
-
*
|
|
59
|
+
* This interface is empty by default and populated via codegen.
|
|
60
|
+
* See design/09-typescript.md §"Typed Routes".
|
|
306
61
|
*/
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const explicit = join(root, configAppDir);
|
|
310
|
-
if (!existsSync(explicit)) {
|
|
311
|
-
throw new Error(`[timber] Configured appDir "${configAppDir}" does not exist at ${explicit}`);
|
|
312
|
-
}
|
|
313
|
-
return explicit;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const rootApp = join(root, 'app');
|
|
317
|
-
if (existsSync(rootApp)) return rootApp;
|
|
318
|
-
|
|
319
|
-
const srcApp = join(root, 'src', 'app');
|
|
320
|
-
if (existsSync(srcApp)) return srcApp;
|
|
321
|
-
|
|
322
|
-
throw new Error(
|
|
323
|
-
`[timber] Could not find app directory. Expected "app/" or "src/app/" in ${root}. ` +
|
|
324
|
-
`You can set appDir in timber.config.ts to specify a custom location.`
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function createPluginContext(config?: TimberUserConfig, root?: string): PluginContext {
|
|
329
|
-
const projectRoot = root ?? process.cwd();
|
|
330
|
-
// Don't apply defaults here — they would override file-based config
|
|
331
|
-
// during mergeFileConfig (inline spreads over file). Defaults are
|
|
332
|
-
// applied after merge in timber(). See TIM-451.
|
|
333
|
-
const resolvedConfig: TimberUserConfig = { ...config };
|
|
334
|
-
// Timer starts as active — swapped to noop in configResolved for production builds
|
|
335
|
-
return {
|
|
336
|
-
config: resolvedConfig,
|
|
337
|
-
clientJavascript: resolveClientJavascript(resolvedConfig),
|
|
338
|
-
routeTree: null,
|
|
339
|
-
appDir: join(projectRoot, 'app'),
|
|
340
|
-
root: projectRoot,
|
|
341
|
-
dev: false,
|
|
342
|
-
buildManifest: null,
|
|
343
|
-
deploymentId: null,
|
|
344
|
-
timer: createStartupTimer(),
|
|
345
|
-
};
|
|
346
|
-
}
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
63
|
+
export interface Routes {}
|
|
347
64
|
|
|
348
65
|
/**
|
|
349
|
-
*
|
|
350
|
-
* Returns the config object or null if no config file is found.
|
|
66
|
+
* Type-safe helper for timber.config.ts files.
|
|
351
67
|
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const configPath = join(root, name);
|
|
361
|
-
if (existsSync(configPath)) {
|
|
362
|
-
const mod = req(configPath);
|
|
363
|
-
return (mod.default ?? mod) as TimberUserConfig;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return null;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Detect config keys set in both inline (vite.config.ts) and file (timber.config.ts)
|
|
371
|
-
* and warn the user. The `output` key is excluded because it defaults to 'server'
|
|
372
|
-
* in createPluginContext and would always appear as an inline key.
|
|
68
|
+
* A pass-through identity function that provides autocomplete and
|
|
69
|
+
* type checking for timber configuration. No runtime validation —
|
|
70
|
+
* purely a DX convenience (same pattern as Vite's defineConfig).
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* // timber.config.ts
|
|
75
|
+
* import { defineConfig } from '@timber-js/app';
|
|
373
76
|
*
|
|
374
|
-
*
|
|
77
|
+
* export default defineConfig({
|
|
78
|
+
* output: 'server',
|
|
79
|
+
* pageExtensions: ['tsx', 'ts', 'mdx'],
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
375
82
|
*/
|
|
376
|
-
export function
|
|
377
|
-
|
|
378
|
-
fileConfig: TimberUserConfig
|
|
379
|
-
): string[] {
|
|
380
|
-
const conflicts: string[] = [];
|
|
381
|
-
for (const key of Object.keys(fileConfig) as (keyof TimberUserConfig)[]) {
|
|
382
|
-
if (key in inline && inline[key] !== undefined) {
|
|
383
|
-
conflicts.push(key);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
if (conflicts.length > 0) {
|
|
387
|
-
console.warn(
|
|
388
|
-
`[timber] Config conflict: ${conflicts.map((k) => `"${k}"`).join(', ')} set in both ` +
|
|
389
|
-
`vite.config.ts (inline) and timber.config.ts. ` +
|
|
390
|
-
`Move all config to timber.config.ts to avoid confusion. ` +
|
|
391
|
-
`The inline value from vite.config.ts will be used.`
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
|
-
return conflicts;
|
|
83
|
+
export function defineConfig(config: TimberUserConfig): TimberUserConfig {
|
|
84
|
+
return config;
|
|
395
85
|
}
|
|
396
86
|
|
|
397
|
-
|
|
398
|
-
* Merge file-based config into ctx.config. Inline config (already in ctx.config)
|
|
399
|
-
* takes precedence — file config only fills in missing fields.
|
|
400
|
-
*/
|
|
401
|
-
function mergeFileConfig(ctx: PluginContext, fileConfig: TimberUserConfig): void {
|
|
402
|
-
const inline = ctx.config;
|
|
403
|
-
|
|
404
|
-
// Warn if the same key is set in both places
|
|
405
|
-
warnConfigConflicts(inline, fileConfig);
|
|
406
|
-
|
|
407
|
-
// For each top-level key, use inline value if present, otherwise file value
|
|
408
|
-
ctx.config = {
|
|
409
|
-
...fileConfig,
|
|
410
|
-
...inline,
|
|
411
|
-
// Deep merge for nested objects where both exist
|
|
412
|
-
...(fileConfig.limits && inline.limits
|
|
413
|
-
? { limits: { ...fileConfig.limits, ...inline.limits } }
|
|
414
|
-
: {}),
|
|
415
|
-
...(fileConfig.dev && inline.dev ? { dev: { ...fileConfig.dev, ...inline.dev } } : {}),
|
|
416
|
-
...(fileConfig.mdx && inline.mdx ? { mdx: { ...fileConfig.mdx, ...inline.mdx } } : {}),
|
|
417
|
-
};
|
|
418
|
-
}
|
|
87
|
+
// ── Private helpers ───────────────────────────────────────────────────────
|
|
419
88
|
|
|
420
89
|
/**
|
|
421
90
|
* Resolve the React Compiler plugin via @rolldown/plugin-babel.
|
|
@@ -507,6 +176,8 @@ function createRscOptions(
|
|
|
507
176
|
// The timber.cache() API (createCache) remains available for explicit caching.
|
|
508
177
|
// See design/06-caching.md.
|
|
509
178
|
|
|
179
|
+
// ── Main plugin factory ──────────────────────────────────────────────────
|
|
180
|
+
|
|
510
181
|
/**
|
|
511
182
|
* Create the timber Vite plugin array.
|
|
512
183
|
*
|
|
@@ -605,6 +276,38 @@ export function timber(config?: TimberUserConfig): PluginOption[] {
|
|
|
605
276
|
// We explicitly set `oxc.jsx.development: false` for builds so
|
|
606
277
|
// the client bundle always uses jsx/jsxs from react/jsx-runtime,
|
|
607
278
|
// regardless of the ambient NODE_ENV value.
|
|
279
|
+
// ── Start holding server for dev mode ───────────────────────
|
|
280
|
+
// Bind the port immediately so browsers see a loading page
|
|
281
|
+
// instead of ERR_CONNECTION_REFUSED during the ~6-8s startup.
|
|
282
|
+
// The holding server is closed in timber-dev-server's
|
|
283
|
+
// configureServer hook (the last plugin), right before Vite
|
|
284
|
+
// calls server.listen().
|
|
285
|
+
// See design/21-dev-server.md §"Startup Holding Server", TIM-665.
|
|
286
|
+
if (command === 'serve') {
|
|
287
|
+
const port = (userConfig.server?.port as number) ?? 5173;
|
|
288
|
+
try {
|
|
289
|
+
ctx.holdingServer = createHoldingServer();
|
|
290
|
+
// listen() is async but we fire-and-forget — the server
|
|
291
|
+
// starts binding immediately and will be ready well before
|
|
292
|
+
// any browser request arrives. We can't await here because
|
|
293
|
+
// config() must return synchronously.
|
|
294
|
+
ctx.holdingServer.listen(port).then(
|
|
295
|
+
(boundPort) => {
|
|
296
|
+
const url = `http://localhost:${boundPort}`;
|
|
297
|
+
console.log(
|
|
298
|
+
`\n \x1b[2m🪵 timber.js dev server starting at\x1b[0m \x1b[36m${url}\x1b[0m\n`
|
|
299
|
+
);
|
|
300
|
+
},
|
|
301
|
+
() => {
|
|
302
|
+
// Port already in use — skip gracefully.
|
|
303
|
+
ctx.holdingServer = null;
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
} catch {
|
|
307
|
+
ctx.holdingServer = null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
608
311
|
if (command === 'build') {
|
|
609
312
|
return {
|
|
610
313
|
oxc: {
|
|
@@ -691,39 +394,4 @@ export function timber(config?: TimberUserConfig): PluginOption[] {
|
|
|
691
394
|
];
|
|
692
395
|
}
|
|
693
396
|
|
|
694
|
-
/**
|
|
695
|
-
* Route map interface — augmented by the generated timber-routes.d.ts.
|
|
696
|
-
*
|
|
697
|
-
* Each key is a route path pattern. Values have:
|
|
698
|
-
* segmentParams: shape of URL segment params (e.g. { id: string })
|
|
699
|
-
* searchParams: parsed type from search-params.ts, or {} if none
|
|
700
|
-
*
|
|
701
|
-
* This interface is empty by default and populated via codegen.
|
|
702
|
-
* See design/09-typescript.md §"Typed Routes".
|
|
703
|
-
*/
|
|
704
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
705
|
-
export interface Routes {}
|
|
706
|
-
|
|
707
|
-
/**
|
|
708
|
-
* Type-safe helper for timber.config.ts files.
|
|
709
|
-
*
|
|
710
|
-
* A pass-through identity function that provides autocomplete and
|
|
711
|
-
* type checking for timber configuration. No runtime validation —
|
|
712
|
-
* purely a DX convenience (same pattern as Vite's defineConfig).
|
|
713
|
-
*
|
|
714
|
-
* @example
|
|
715
|
-
* ```ts
|
|
716
|
-
* // timber.config.ts
|
|
717
|
-
* import { defineConfig } from '@timber-js/app';
|
|
718
|
-
*
|
|
719
|
-
* export default defineConfig({
|
|
720
|
-
* output: 'server',
|
|
721
|
-
* pageExtensions: ['tsx', 'ts', 'mdx'],
|
|
722
|
-
* });
|
|
723
|
-
* ```
|
|
724
|
-
*/
|
|
725
|
-
export function defineConfig(config: TimberUserConfig): TimberUserConfig {
|
|
726
|
-
return config;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
397
|
export default timber;
|