@timber-js/app 0.2.0-alpha.146 → 0.2.0-alpha.148
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-OIZ8siQu.js → actions-a0RczDnB.js} +8 -34
- package/dist/_chunks/{actions-OIZ8siQu.js.map → actions-a0RczDnB.js.map} +1 -1
- package/dist/_chunks/cache-api-Co-yI-gP.js +424 -0
- package/dist/_chunks/cache-api-Co-yI-gP.js.map +1 -0
- package/dist/_chunks/{metadata-routes-BjepjefT.js → canonicalize-P41GR6tY.js} +65 -2
- package/dist/_chunks/canonicalize-P41GR6tY.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync-D2IpXicg.js → cli-schema-sync-DJDdyEae.js} +157 -313
- package/dist/_chunks/cli-schema-sync-DJDdyEae.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-D_IhHEUW.js +2 -0
- package/dist/_chunks/{define-DMVhsipD.js → define-Bssfp6ot.js} +3 -33
- package/dist/_chunks/define-Bssfp6ot.js.map +1 -0
- package/dist/_chunks/{define-C3RvHQPK.js → define-CFmvb4Bt.js} +15 -7
- package/dist/_chunks/define-CFmvb4Bt.js.map +1 -0
- package/dist/_chunks/{href-validation-DyZIzfMJ.js → href-validation-FiA_rToW.js} +2 -1
- package/dist/_chunks/{href-validation-DyZIzfMJ.js.map → href-validation-FiA_rToW.js.map} +1 -1
- package/dist/_chunks/{tracing-M_zKubhk.js → logger-CM0clugc.js} +394 -107
- package/dist/_chunks/logger-CM0clugc.js.map +1 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -1
- package/dist/_chunks/plugin-context-DurqFBuY.js +2 -0
- package/dist/_chunks/plugin-context-GfDWsdd2.js +268 -0
- package/dist/_chunks/plugin-context-GfDWsdd2.js.map +1 -0
- package/dist/_chunks/{resolve-schema-Dj8tQloi.js → resolve-schema-3iUvBV5T.js} +3 -30
- package/dist/_chunks/resolve-schema-3iUvBV5T.js.map +1 -0
- package/dist/_chunks/{schema-bridge-DK_89h8O.js → schema-bridge-BY3QLBL7.js} +35 -2
- package/dist/_chunks/schema-bridge-BY3QLBL7.js.map +1 -0
- package/dist/_chunks/tree-match-D2l830j2.js +102 -0
- package/dist/_chunks/tree-match-D2l830j2.js.map +1 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -1
- package/dist/_chunks/{walkers-7FBPM-hX.js → walkers-DvWDj453.js} +154 -88
- package/dist/_chunks/walkers-DvWDj453.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +36 -14
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
- package/dist/adapters/compress-module.d.ts +5 -4
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +1 -3
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +14 -134
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/cache-api.d.ts.map +1 -1
- package/dist/cache/index.d.ts +3 -1
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +20 -235
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/invalidation-epoch.d.ts +43 -0
- package/dist/cache/invalidation-epoch.d.ts.map +1 -0
- package/dist/cache/redis-handler.d.ts +13 -0
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/timber-cache.d.ts +17 -9
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cli-schema-sync.d.ts +21 -1
- package/dist/cli-schema-sync.d.ts.map +1 -1
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +26 -31
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-entry/hmr.d.ts.map +1 -1
- package/dist/client/browser-entry/hydrate.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/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +13 -4
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +8 -1
- package/dist/client/error-reconstituter.d.ts.map +1 -1
- package/dist/client/history.d.ts +10 -17
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.js +30 -33
- package/dist/client/internal.js.map +1 -1
- package/dist/client/navigation-api.d.ts +9 -2
- package/dist/client/navigation-api.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +0 -11
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +0 -5
- package/dist/client/navigation-root.d.ts.map +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +10 -5
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +2 -4
- package/dist/cookies/index.js.map +1 -1
- package/dist/dev-tools/dev-page-shell.d.ts +1 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
- package/dist/dev-tools/hydration-overlay.d.ts +11 -0
- package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +1 -2
- package/dist/dev-tools/index.d.ts.map +1 -1
- package/dist/fonts/ast-walk.d.ts +68 -0
- package/dist/fonts/ast-walk.d.ts.map +1 -0
- package/dist/fonts/ast.d.ts +23 -11
- package/dist/fonts/ast.d.ts.map +1 -1
- package/dist/fonts/bundle.d.ts +3 -1
- package/dist/fonts/bundle.d.ts.map +1 -1
- package/dist/fonts/dev-middleware.d.ts +1 -1
- package/dist/fonts/dev-middleware.d.ts.map +1 -1
- package/dist/fonts/fallbacks.d.ts +0 -7
- package/dist/fonts/fallbacks.d.ts.map +1 -1
- package/dist/fonts/google.d.ts +4 -2
- package/dist/fonts/google.d.ts.map +1 -1
- package/dist/fonts/local.d.ts +3 -3
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/paths.d.ts +43 -0
- package/dist/fonts/paths.d.ts.map +1 -0
- package/dist/fonts/pipeline.d.ts +7 -21
- package/dist/fonts/pipeline.d.ts.map +1 -1
- package/dist/fonts/transform.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +1 -18
- package/dist/fonts/virtual-modules.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +609 -406
- package/dist/index.js.map +1 -1
- package/dist/params/index.js +1 -1
- package/dist/params/resolve-schema.d.ts.map +1 -1
- package/dist/plugin-context.d.ts +28 -5
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/cache.d.ts +13 -5
- package/dist/plugins/cache.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +1 -2
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/routing/codegen-types.d.ts +4 -0
- package/dist/routing/codegen-types.d.ts.map +1 -1
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/file-cache.d.ts +8 -0
- package/dist/routing/file-cache.d.ts.map +1 -0
- package/dist/routing/index.js +2 -2
- package/dist/routing/interception.d.ts +0 -5
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/manifest-codegen.d.ts +32 -0
- package/dist/routing/manifest-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +15 -0
- package/dist/schema-bridge.d.ts.map +1 -1
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.js +7 -3
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/wrappers.d.ts.map +1 -1
- package/dist/segment-params/define.d.ts.map +1 -1
- package/dist/segment-params/index.js +1 -1
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/actions.d.ts +0 -14
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +0 -29
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/canonicalize.d.ts +10 -0
- package/dist/server/canonicalize.d.ts.map +1 -1
- package/dist/server/deny-boundary.d.ts +27 -2
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +8 -0
- package/dist/server/html-injector-core.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/internal.d.ts +1 -5
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +238 -349
- package/dist/server/internal.js.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +0 -11
- package/dist/server/node-stream-transforms.d.ts.map +1 -1
- package/dist/server/render-utils.d.ts +25 -0
- package/dist/server/render-utils.d.ts.map +1 -0
- package/dist/server/route-element-builder.d.ts +11 -25
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +2 -18
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- 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/rsc-payload.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +6 -0
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/utils/mdx-file.d.ts +15 -0
- package/dist/server/utils/mdx-file.d.ts.map +1 -0
- package/dist/shared/href-validation.d.ts.map +1 -1
- package/dist/shims/image.d.ts +15 -15
- package/package.json +3 -3
- package/src/adapters/cloudflare-kv-cache.ts +56 -19
- package/src/adapters/compress-module.ts +27 -118
- package/src/adapters/nitro.ts +3 -41
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/cache/cache-api.ts +9 -1
- package/src/cache/index.ts +5 -2
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/redis-handler.ts +33 -2
- package/src/cache/timber-cache.ts +109 -53
- package/src/cli-schema-sync.ts +123 -30
- package/src/cli.ts +33 -37
- package/src/client/browser-entry/hmr.ts +0 -11
- package/src/client/browser-entry/hydrate.ts +39 -5
- package/src/client/browser-entry/post-hydration.ts +6 -15
- package/src/client/browser-entry/router-init.ts +98 -3
- package/src/client/error-boundary.tsx +14 -0
- package/src/client/error-reconstituter.tsx +15 -1
- package/src/client/history.ts +10 -24
- package/src/client/navigation-api.ts +14 -9
- package/src/client/navigation-context.ts +1 -21
- package/src/client/navigation-root.tsx +0 -8
- package/src/client/router.ts +18 -8
- package/src/client/rsc-fetch.ts +7 -2
- package/src/client/use-search-params.ts +10 -5
- package/src/config-validation.ts +33 -25
- package/src/cookies/define-cookie.ts +2 -18
- package/src/dev-tools/dev-page-shell.ts +6 -2
- package/src/dev-tools/hydration-overlay.ts +158 -0
- package/src/dev-tools/index.ts +3 -16
- package/src/fonts/ast-walk.ts +235 -0
- package/src/fonts/ast.ts +91 -249
- package/src/fonts/bundle.ts +16 -9
- package/src/fonts/dev-middleware.ts +16 -5
- package/src/fonts/fallbacks.ts +0 -23
- package/src/fonts/google.ts +7 -3
- package/src/fonts/local.ts +7 -6
- package/src/fonts/paths.ts +58 -0
- package/src/fonts/pipeline.ts +27 -48
- package/src/fonts/transform.ts +27 -0
- package/src/fonts/virtual-modules.ts +1 -57
- package/src/index.ts +5 -11
- package/src/params/resolve-schema.ts +2 -34
- package/src/plugin-context.ts +95 -17
- package/src/plugins/cache.ts +64 -17
- package/src/plugins/dev-server.ts +61 -9
- package/src/plugins/fonts.ts +21 -6
- package/src/plugins/routing.ts +5 -348
- package/src/routing/codegen-types.ts +4 -0
- package/src/routing/codegen.ts +66 -8
- package/src/routing/convention-lint.ts +4 -3
- package/src/routing/file-cache.ts +23 -0
- package/src/routing/interception.ts +2 -21
- package/src/routing/manifest-codegen.ts +290 -0
- package/src/routing/scanner.ts +85 -80
- package/src/routing/schema-validation.ts +2 -2
- package/src/schema-bridge.ts +63 -2
- package/src/search-params/define.ts +34 -2
- package/src/search-params/wrappers.ts +21 -3
- package/src/segment-params/define.ts +2 -62
- package/src/server/access-gate.tsx +8 -0
- package/src/server/actions.ts +8 -31
- package/src/server/build-manifest.ts +0 -56
- package/src/server/canonicalize.ts +6 -3
- package/src/server/deny-boundary.ts +106 -13
- package/src/server/deny-renderer.ts +46 -10
- package/src/server/error-boundary-wrapper.ts +1 -14
- package/src/server/html-injector-core.ts +19 -0
- package/src/server/html-injectors.ts +14 -4
- package/src/server/internal.ts +1 -18
- package/src/server/node-stream-transforms.ts +5 -72
- package/src/server/render-utils.ts +31 -0
- package/src/server/route-element-builder.ts +77 -47
- package/src/server/route-matcher.ts +22 -6
- package/src/server/rsc-entry/error-renderer.ts +2 -12
- package/src/server/rsc-entry/helpers.ts +6 -34
- package/src/server/rsc-entry/index.ts +11 -0
- package/src/server/rsc-entry/render-route.ts +7 -9
- package/src/server/rsc-entry/rsc-payload.ts +2 -1
- package/src/server/rsc-entry/ssr-renderer.ts +2 -2
- package/src/server/ssr-render.ts +1 -11
- package/src/server/status-code-resolver.ts +3 -2
- package/src/server/tree-match.ts +15 -5
- package/src/server/utils/mdx-file.ts +22 -0
- package/src/shared/href-validation.ts +8 -0
- package/dist/_chunks/cli-schema-sync-D2IpXicg.js.map +0 -1
- package/dist/_chunks/cli-schema-sync-DH-M8Poy.js +0 -2
- package/dist/_chunks/define-C3RvHQPK.js.map +0 -1
- package/dist/_chunks/define-DMVhsipD.js.map +0 -1
- package/dist/_chunks/handler-store-BVDgyTh7.js +0 -78
- package/dist/_chunks/handler-store-BVDgyTh7.js.map +0 -1
- package/dist/_chunks/logger-Dt-jQaBO.js +0 -291
- package/dist/_chunks/logger-Dt-jQaBO.js.map +0 -1
- package/dist/_chunks/metadata-routes-BjepjefT.js.map +0 -1
- package/dist/_chunks/resolve-schema-Dj8tQloi.js.map +0 -1
- package/dist/_chunks/schema-bridge-DK_89h8O.js.map +0 -1
- package/dist/_chunks/tracing-M_zKubhk.js.map +0 -1
- package/dist/_chunks/walkers-7FBPM-hX.js.map +0 -1
- package/dist/_chunks/warnings-CNPXaypM.js +0 -125
- package/dist/_chunks/warnings-CNPXaypM.js.map +0 -1
- package/dist/client/link-pending-store.d.ts +0 -65
- package/dist/client/link-pending-store.d.ts.map +0 -1
- package/dist/client/nav-link-store.d.ts +0 -27
- package/dist/client/nav-link-store.d.ts.map +0 -1
- package/dist/dev-tools/warnings.d.ts +0 -109
- package/dist/dev-tools/warnings.d.ts.map +0 -1
- package/dist/server/flush.d.ts +0 -74
- package/dist/server/flush.d.ts.map +0 -1
- package/src/client/link-pending-store.ts +0 -116
- package/src/client/nav-link-store.ts +0 -37
- package/src/dev-tools/warnings.ts +0 -238
- package/src/server/flush.ts +0 -183
package/src/plugins/cache.ts
CHANGED
|
@@ -2,13 +2,21 @@
|
|
|
2
2
|
* timber-cache-transform — Vite plugin that injects stable callsite IDs
|
|
3
3
|
* into `cache()` calls imported from `@timber-js/app/cache`.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Detected callsite forms (TIM-1054):
|
|
6
|
+
* - named imports, including aliases: `import { cache as c }` + `c(fn, opts)`
|
|
7
|
+
* - namespace imports: `import * as ns` + `ns.cache(fn, opts)`
|
|
8
|
+
* Forms a per-module transform cannot trace — local variable aliases
|
|
9
|
+
* (`const c = cache`), user re-export wrapper modules, computed access
|
|
10
|
+
* (`ns['cache']`) — fall back to the runtime fnId derived from
|
|
11
|
+
* fnv1a(fn.toString()) (see cache/timber-cache.ts), which is deterministic
|
|
12
|
+
* across instances and cold starts of the same build. Without either
|
|
13
|
+
* mechanism, an ordinal counter would collide across instances with a shared
|
|
14
|
+
* CacheHandler (Redis/KV) — cache key poisoning, serving one route's cached
|
|
15
|
+
* data to another.
|
|
9
16
|
*
|
|
10
17
|
* The plugin transforms:
|
|
11
|
-
* cache(fn, opts)
|
|
18
|
+
* cache(fn, opts) → cache(fn, opts, "stable-id")
|
|
19
|
+
* ns.cache(fn, opts) → ns.cache(fn, opts, "stable-id")
|
|
12
20
|
*
|
|
13
21
|
* where stable-id =
|
|
14
22
|
* fnv1a(relPath + ":cache:" + fnv1a(stmtText) + ":" + fnv1a(callSpanText) + ":" + occurrence)
|
|
@@ -81,29 +89,72 @@ interface CallExpressionNode extends PositionedNode {
|
|
|
81
89
|
arguments: PositionedNode[];
|
|
82
90
|
}
|
|
83
91
|
|
|
92
|
+
interface MemberExpressionNode extends PositionedNode {
|
|
93
|
+
type: 'MemberExpression';
|
|
94
|
+
object: PositionedNode;
|
|
95
|
+
property: PositionedNode;
|
|
96
|
+
computed: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
interface ProgramNode extends PositionedNode {
|
|
85
100
|
type: 'Program';
|
|
86
101
|
body: PositionedNode[];
|
|
87
102
|
}
|
|
88
103
|
|
|
104
|
+
interface CacheBindings {
|
|
105
|
+
/** Local names bound to `cache` via named imports (`import { cache as c }`). */
|
|
106
|
+
named: Set<string>;
|
|
107
|
+
/** Local names of namespace imports (`import * as ns`) of a cache module. */
|
|
108
|
+
namespaces: Set<string>;
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
/**
|
|
90
|
-
* Find the local binding name(s) for `cache` imported from the cache module
|
|
112
|
+
* Find the local binding name(s) for `cache` imported from the cache module —
|
|
113
|
+
* both named imports and namespace imports (TIM-1054).
|
|
91
114
|
*/
|
|
92
|
-
function findCacheBindings(program: ProgramNode):
|
|
93
|
-
const
|
|
115
|
+
function findCacheBindings(program: ProgramNode): CacheBindings {
|
|
116
|
+
const named = new Set<string>();
|
|
117
|
+
const namespaces = new Set<string>();
|
|
94
118
|
for (const stmt of program.body) {
|
|
95
119
|
if (stmt.type !== 'ImportDeclaration') continue;
|
|
96
120
|
const decl = stmt as unknown as ImportDeclarationNode;
|
|
97
121
|
if (!CACHE_MODULE_SOURCES.has(decl.source.value)) continue;
|
|
98
122
|
for (const spec of decl.specifiers) {
|
|
123
|
+
if (spec.type === 'ImportNamespaceSpecifier') {
|
|
124
|
+
namespaces.add(spec.local.name);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
99
127
|
if (spec.type !== 'ImportSpecifier') continue;
|
|
100
128
|
const importedName = spec.imported?.name ?? spec.local.name;
|
|
101
129
|
if (importedName === 'cache') {
|
|
102
|
-
|
|
130
|
+
named.add(spec.local.name);
|
|
103
131
|
}
|
|
104
132
|
}
|
|
105
133
|
}
|
|
106
|
-
return
|
|
134
|
+
return { named, namespaces };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Is this callee a reference to the imported `cache` function — either a bare
|
|
139
|
+
* identifier bound by a named import, or `ns.cache` on a namespace import?
|
|
140
|
+
* Computed access (`ns['cache']`) is deliberately not matched; it falls back
|
|
141
|
+
* to the runtime fnId derivation.
|
|
142
|
+
*/
|
|
143
|
+
function isCacheCallee(callee: PositionedNode, bindings: CacheBindings): boolean {
|
|
144
|
+
if (callee.type === 'Identifier') {
|
|
145
|
+
return bindings.named.has((callee as IdentifierNode).name);
|
|
146
|
+
}
|
|
147
|
+
if (callee.type === 'MemberExpression') {
|
|
148
|
+
const member = callee as unknown as MemberExpressionNode;
|
|
149
|
+
return (
|
|
150
|
+
!member.computed &&
|
|
151
|
+
member.object.type === 'Identifier' &&
|
|
152
|
+
bindings.namespaces.has((member.object as IdentifierNode).name) &&
|
|
153
|
+
member.property.type === 'Identifier' &&
|
|
154
|
+
(member.property as IdentifierNode).name === 'cache'
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
107
158
|
}
|
|
108
159
|
|
|
109
160
|
/**
|
|
@@ -114,16 +165,12 @@ function findCacheBindings(program: ProgramNode): Set<string> {
|
|
|
114
165
|
*/
|
|
115
166
|
function findCacheCallSites(
|
|
116
167
|
node: PositionedNode,
|
|
117
|
-
cacheBindings:
|
|
168
|
+
cacheBindings: CacheBindings,
|
|
118
169
|
results: CallExpressionNode[]
|
|
119
170
|
): void {
|
|
120
171
|
if (node.type === 'CallExpression') {
|
|
121
172
|
const call = node as unknown as CallExpressionNode;
|
|
122
|
-
if (
|
|
123
|
-
call.callee.type === 'Identifier' &&
|
|
124
|
-
cacheBindings.has((call.callee as IdentifierNode).name) &&
|
|
125
|
-
call.arguments.length === 2
|
|
126
|
-
) {
|
|
173
|
+
if (call.arguments.length === 2 && isCacheCallee(call.callee, cacheBindings)) {
|
|
127
174
|
results.push(call);
|
|
128
175
|
}
|
|
129
176
|
}
|
|
@@ -188,7 +235,7 @@ export function timberCacheTransform(ctx: PluginContext): Plugin {
|
|
|
188
235
|
}
|
|
189
236
|
|
|
190
237
|
const cacheBindings = findCacheBindings(program);
|
|
191
|
-
if (cacheBindings.size === 0) return;
|
|
238
|
+
if (cacheBindings.named.size === 0 && cacheBindings.namespaces.size === 0) return;
|
|
192
239
|
|
|
193
240
|
// Collect call sites per top-level statement so each call carries its
|
|
194
241
|
// enclosing statement's source text into the ID hash.
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
import type { Plugin, ViteDevServer, DevEnvironment } from 'vite';
|
|
16
16
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
17
17
|
import type { TLSSocket } from 'node:tls';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
18
19
|
import { join } from 'node:path';
|
|
19
20
|
import type { PluginContext } from '../plugin-context.js';
|
|
20
|
-
import { setViteServer } from '../dev-tools/warnings.js';
|
|
21
21
|
import {
|
|
22
22
|
sendErrorToOverlay,
|
|
23
23
|
classifyErrorPhase,
|
|
@@ -30,6 +30,9 @@ import { extractHmrOptions, type DevErrorHmrOptions } from '../dev-tools/dev-pag
|
|
|
30
30
|
import { addVirtualModuleContext } from '../config-validation.js';
|
|
31
31
|
import { compressResponse } from '../server/compress.js';
|
|
32
32
|
import { isMetadataRouteServePath } from '../server/metadata-routes.js';
|
|
33
|
+
import { canonicalize } from '../server/canonicalize.js';
|
|
34
|
+
import { matchUrlParts } from '../server/tree-match.js';
|
|
35
|
+
import type { RouteTree } from '../routing/types.js';
|
|
33
36
|
|
|
34
37
|
// ─── Constants ────────────────────────────────────────────────────────────
|
|
35
38
|
|
|
@@ -93,10 +96,6 @@ export function timberDevServer(ctx: PluginContext): Plugin {
|
|
|
93
96
|
const configPaths = CONFIG_FILE_NAMES.map((name) => join(ctx.root, name));
|
|
94
97
|
server.watcher.add(configPaths);
|
|
95
98
|
|
|
96
|
-
// Register Vite server for browser console warning forwarding.
|
|
97
|
-
// See 21-dev-server.md §Dev-Mode Warnings.
|
|
98
|
-
setViteServer(server);
|
|
99
|
-
|
|
100
99
|
// Listen for client-side errors forwarded from the browser.
|
|
101
100
|
// The browser entry sends 'timber:client-error' events via HMR
|
|
102
101
|
// for uncaught errors and unhandled rejections. We echo them back
|
|
@@ -104,7 +103,7 @@ export function timberDevServer(ctx: PluginContext): Plugin {
|
|
|
104
103
|
listenForClientErrors(server, ctx.root);
|
|
105
104
|
|
|
106
105
|
// Pre-hook — registers middleware before Vite's internals
|
|
107
|
-
server.middlewares.use(createTimberMiddleware(server, ctx
|
|
106
|
+
server.middlewares.use(createTimberMiddleware(server, ctx));
|
|
108
107
|
|
|
109
108
|
// Wrap server.listen() to close the holding server immediately
|
|
110
109
|
// before Vite binds the port — no gap where nothing is listening.
|
|
@@ -146,7 +145,8 @@ export function timberDevServer(ctx: PluginContext): Plugin {
|
|
|
146
145
|
* For non-route requests (assets, Vite internals, HMR), the middleware
|
|
147
146
|
* calls next() to let Vite handle them.
|
|
148
147
|
*/
|
|
149
|
-
function createTimberMiddleware(server: ViteDevServer,
|
|
148
|
+
function createTimberMiddleware(server: ViteDevServer, ctx: PluginContext) {
|
|
149
|
+
const projectRoot = ctx.root;
|
|
150
150
|
// Extract HMR connection options once so the error page can construct
|
|
151
151
|
// a correct WebSocket URL (TIM-789).
|
|
152
152
|
const hmrOptions = extractHmrOptions(server.config);
|
|
@@ -165,8 +165,16 @@ function createTimberMiddleware(server: ViteDevServer, projectRoot: string) {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
// Pass through static asset requests — but not metadata routes like
|
|
168
|
-
// /favicon.ico that match asset extensions but are handled by timber
|
|
169
|
-
|
|
168
|
+
// /favicon.ico that match asset extensions but are handled by timber,
|
|
169
|
+
// and not registered routes like app/feed.json/route.ts whose URL ends
|
|
170
|
+
// in an asset extension. Production serves these through the RSC
|
|
171
|
+
// handler, so letting them fall through to Vite would 404 in dev only
|
|
172
|
+
// (TIM-1038).
|
|
173
|
+
if (
|
|
174
|
+
isAssetRequest(url) &&
|
|
175
|
+
!isMetadataRouteServePath(url) &&
|
|
176
|
+
!isRouteOwnedAsset(ctx.routeTree, server, url)
|
|
177
|
+
) {
|
|
170
178
|
next();
|
|
171
179
|
return;
|
|
172
180
|
}
|
|
@@ -513,6 +521,50 @@ function isAssetRequest(url: string): boolean {
|
|
|
513
521
|
return ASSET_EXTENSIONS.test(url);
|
|
514
522
|
}
|
|
515
523
|
|
|
524
|
+
/**
|
|
525
|
+
* Check whether an asset-extension URL belongs to a scanned route rather
|
|
526
|
+
* than a static file.
|
|
527
|
+
*
|
|
528
|
+
* Route handlers may live at paths ending in asset-like extensions
|
|
529
|
+
* (app/feed.json/route.ts → /feed.json), which the asset bypass would
|
|
530
|
+
* otherwise hand to Vite — 404ing in dev while working in production.
|
|
531
|
+
* Uses the same canonicalization and tree walker as the runtime matcher
|
|
532
|
+
* so dev classification agrees with what the pipeline would match.
|
|
533
|
+
*
|
|
534
|
+
* A file that actually exists on disk wins over the route match: the
|
|
535
|
+
* production server serves public/ statics before the RSC handler (see
|
|
536
|
+
* adapters/nitro.ts), and Vite serves root-relative source files (e.g.
|
|
537
|
+
* /app/global.css) in dev. Without this, a broad catch-all route like
|
|
538
|
+
* app/[...slug] would shadow every static asset. Joining the canonical
|
|
539
|
+
* pathname is traversal-safe — canonicalize() resolves `..` segments and
|
|
540
|
+
* rejects root escapes and encoded separators.
|
|
541
|
+
*
|
|
542
|
+
* Reads ctx.routeTree per request — the routing plugin rescans it on
|
|
543
|
+
* file add/unlink/change, so newly created routes are picked up live.
|
|
544
|
+
*/
|
|
545
|
+
function isRouteOwnedAsset(
|
|
546
|
+
routeTree: RouteTree | null,
|
|
547
|
+
server: ViteDevServer,
|
|
548
|
+
url: string
|
|
549
|
+
): boolean {
|
|
550
|
+
if (!routeTree) return false;
|
|
551
|
+
const rawPathname = url.split('?')[0];
|
|
552
|
+
const result = canonicalize(rawPathname);
|
|
553
|
+
// Malformed URLs can't match a route — let Vite handle them as before.
|
|
554
|
+
if (!result.ok) return false;
|
|
555
|
+
const parts = result.pathname === '/' ? [] : result.pathname.slice(1).split('/');
|
|
556
|
+
if (matchUrlParts(routeTree.root, parts) === null) return false;
|
|
557
|
+
|
|
558
|
+
// Real static files win over the route match (dev/prod parity: the
|
|
559
|
+
// production server tries public/ before the RSC handler).
|
|
560
|
+
const relativePath = result.pathname.slice(1);
|
|
561
|
+
const { publicDir, root } = server.config;
|
|
562
|
+
if (publicDir && existsSync(join(publicDir, relativePath))) return false;
|
|
563
|
+
if (existsSync(join(root, relativePath))) return false;
|
|
564
|
+
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
|
|
516
568
|
// ─── Client Error Listener ─────────────────────────────────────────────
|
|
517
569
|
|
|
518
570
|
interface ClientErrorPayload {
|
package/src/plugins/fonts.ts
CHANGED
|
@@ -18,13 +18,14 @@
|
|
|
18
18
|
* Design doc: 24-fonts.md
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import type { Plugin, ViteDevServer } from 'vite';
|
|
21
|
+
import type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';
|
|
22
22
|
import type { PluginContext } from '../plugin-context.js';
|
|
23
23
|
import {
|
|
24
24
|
downloadAndCacheFonts,
|
|
25
25
|
generateProductionFontFaces,
|
|
26
26
|
resolveDevFontFaces,
|
|
27
27
|
} from '../fonts/google.js';
|
|
28
|
+
import { fontUrlPrefix } from '../fonts/paths.js';
|
|
28
29
|
import { FontPipeline } from '../fonts/pipeline.js';
|
|
29
30
|
import { runFontsTransform } from '../fonts/transform.js';
|
|
30
31
|
import { installFontDevMiddleware } from '../fonts/dev-middleware.js';
|
|
@@ -45,7 +46,7 @@ import {
|
|
|
45
46
|
// updating every caller. New helpers should be added to the per-concern
|
|
46
47
|
// module first and re-exported here only if external code needs them.
|
|
47
48
|
|
|
48
|
-
export { FontPipeline
|
|
49
|
+
export { FontPipeline } from '../fonts/pipeline.js';
|
|
49
50
|
export {
|
|
50
51
|
generateFontId,
|
|
51
52
|
extractFontConfig,
|
|
@@ -54,17 +55,27 @@ export {
|
|
|
54
55
|
parseGoogleFontFamilies,
|
|
55
56
|
parseLocalFontImportName,
|
|
56
57
|
} from '../fonts/transform.js';
|
|
57
|
-
export { generateFontCss, generateAllFontCss } from '../fonts/virtual-modules.js';
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Create the timber-fonts Vite plugin.
|
|
61
61
|
*/
|
|
62
62
|
export function timberFonts(ctx: PluginContext): Plugin {
|
|
63
63
|
const pipeline = new FontPipeline({ hashOnRegister: !ctx.dev });
|
|
64
|
+
let resolvedBase = '/';
|
|
64
65
|
|
|
65
66
|
return {
|
|
66
67
|
name: 'timber-fonts',
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Capture Vite's resolved `base` so every font URL the pipeline emits
|
|
71
|
+
* (@font-face src, manifest hrefs, dev middleware matching) carries
|
|
72
|
+
* the prefix. Emitted file locations are unaffected — only URLs.
|
|
73
|
+
*/
|
|
74
|
+
configResolved(config: ResolvedConfig) {
|
|
75
|
+
resolvedBase = config.base;
|
|
76
|
+
pipeline.setBase(config.base);
|
|
77
|
+
},
|
|
78
|
+
|
|
68
79
|
/**
|
|
69
80
|
* `enforce: 'pre'` is load-bearing for the font CSS pipeline (TIM-828).
|
|
70
81
|
*
|
|
@@ -181,7 +192,7 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
181
192
|
* this middleware.
|
|
182
193
|
*/
|
|
183
194
|
configureServer(server: ViteDevServer) {
|
|
184
|
-
installFontDevMiddleware(server, pipeline);
|
|
195
|
+
installFontDevMiddleware(server, pipeline, resolvedBase);
|
|
185
196
|
},
|
|
186
197
|
|
|
187
198
|
/**
|
|
@@ -208,10 +219,14 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
208
219
|
// same `CachedFont` objects; the bundle emitter dedupes by
|
|
209
220
|
// `hashedFilename` so each binary is written to disk exactly once.
|
|
210
221
|
const cachedByFamily = groupCachedFontsByFamily(cachedFonts);
|
|
222
|
+
const urlPrefix = fontUrlPrefix(resolvedBase);
|
|
211
223
|
for (const font of googleFonts) {
|
|
212
224
|
const familyCached = cachedByFamily.get(font.family.toLowerCase()) ?? [];
|
|
213
225
|
pipeline.attachCachedFiles(font.id, familyCached);
|
|
214
|
-
pipeline.attachFaces(
|
|
226
|
+
pipeline.attachFaces(
|
|
227
|
+
font.id,
|
|
228
|
+
generateProductionFontFaces(familyCached, font.display, urlPrefix)
|
|
229
|
+
);
|
|
215
230
|
}
|
|
216
231
|
},
|
|
217
232
|
|
|
@@ -239,7 +254,7 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
239
254
|
(msg) => this.warn(msg)
|
|
240
255
|
);
|
|
241
256
|
if (!ctx.buildManifest) return;
|
|
242
|
-
writeFontManifest(pipeline, ctx.buildManifest);
|
|
257
|
+
writeFontManifest(pipeline, ctx.buildManifest, resolvedBase);
|
|
243
258
|
},
|
|
244
259
|
};
|
|
245
260
|
}
|