@timber-js/app 0.2.0-alpha.100 → 0.2.0-alpha.102

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.
Files changed (109) hide show
  1. package/dist/_chunks/{actions-CQ8Z8VGL.js → actions-n9qTlpmY.js} +7 -10
  2. package/dist/_chunks/actions-n9qTlpmY.js.map +1 -0
  3. package/dist/_chunks/{build-output-helper-DXnW0qjz.js → build-output-helper-5TK2Emwp.js} +1 -1
  4. package/dist/_chunks/{build-output-helper-DXnW0qjz.js.map → build-output-helper-5TK2Emwp.js.map} +1 -1
  5. package/dist/_chunks/{define-CfBPoJb0.js → define-Btmz9B20.js} +3 -3
  6. package/dist/_chunks/{define-CfBPoJb0.js.map → define-Btmz9B20.js.map} +1 -1
  7. package/dist/_chunks/{define-B-Q_UMOD.js → define-Dn98bPbb.js} +3 -3
  8. package/dist/_chunks/{define-B-Q_UMOD.js.map → define-Dn98bPbb.js.map} +1 -1
  9. package/dist/_chunks/{format-Bcn-Iv1x.js → format-CYBGxKtc.js} +1 -1
  10. package/dist/_chunks/{format-Bcn-Iv1x.js.map → format-CYBGxKtc.js.map} +1 -1
  11. package/dist/_chunks/{handler-store-B-lqaGyh.js → handler-store-B_df5Npe.js} +1 -1
  12. package/dist/_chunks/{handler-store-B-lqaGyh.js.map → handler-store-B_df5Npe.js.map} +1 -1
  13. package/dist/_chunks/{logger-0m8MsKdc.js → logger-DDmK5skc.js} +2 -2
  14. package/dist/_chunks/{logger-0m8MsKdc.js.map → logger-DDmK5skc.js.map} +1 -1
  15. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
  16. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
  17. package/dist/_chunks/{metadata-routes-BU684ls2.js → metadata-routes-Cjmvi3rQ.js} +1 -1
  18. package/dist/_chunks/{metadata-routes-BU684ls2.js.map → metadata-routes-Cjmvi3rQ.js.map} +1 -1
  19. package/dist/_chunks/{navigation-root-BCYczjml.js → navigation-root-2ypaZQDx.js} +2 -2
  20. package/dist/_chunks/{navigation-root-BCYczjml.js.map → navigation-root-2ypaZQDx.js.map} +1 -1
  21. package/dist/_chunks/{registry-I2ss-lvy.js → registry-DB93kT5c.js} +1 -1
  22. package/dist/_chunks/{registry-I2ss-lvy.js.map → registry-DB93kT5c.js.map} +1 -1
  23. package/dist/_chunks/{router-ref-h3-UaCQv.js → router-ref-TkUdmqtM.js} +2 -2
  24. package/dist/_chunks/{router-ref-h3-UaCQv.js.map → router-ref-TkUdmqtM.js.map} +1 -1
  25. package/dist/_chunks/{schema-bridge-Cxu4l-7p.js → schema-bridge-C3xl_vfb.js} +1 -1
  26. package/dist/_chunks/{schema-bridge-Cxu4l-7p.js.map → schema-bridge-C3xl_vfb.js.map} +1 -1
  27. package/dist/_chunks/{segment-classify-BjfuctV2.js → segment-classify-CnfLLvir.js} +1 -1
  28. package/dist/_chunks/{segment-classify-BjfuctV2.js.map → segment-classify-CnfLLvir.js.map} +1 -1
  29. package/dist/_chunks/{segment-context-Dx_OizxD.js → segment-context-Dc-GbSTe.js} +1 -1
  30. package/dist/_chunks/{segment-context-Dx_OizxD.js.map → segment-context-Dc-GbSTe.js.map} +1 -1
  31. package/dist/_chunks/{ssr-data-B4CdH7rE.js → ssr-data-DzuI0bIV.js} +1 -1
  32. package/dist/_chunks/{ssr-data-B4CdH7rE.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
  33. package/dist/_chunks/{stale-reload-Bab885FO.js → stale-reload-D6FlD3xn.js} +1 -1
  34. package/dist/_chunks/{stale-reload-Bab885FO.js.map → stale-reload-D6FlD3xn.js.map} +1 -1
  35. package/dist/_chunks/{tracing-C8V-YGsP.js → tracing-DvKLzCFa.js} +1 -1
  36. package/dist/_chunks/{tracing-C8V-YGsP.js.map → tracing-DvKLzCFa.js.map} +1 -1
  37. package/dist/_chunks/{use-query-states-B2XTqxDR.js → use-query-states-B-cLl8mx.js} +2 -2
  38. package/dist/_chunks/{use-query-states-B2XTqxDR.js.map → use-query-states-B-cLl8mx.js.map} +1 -1
  39. package/dist/_chunks/{use-segment-params-BkpKAQ7D.js → use-segment-params-07V1TIxL.js} +3 -3
  40. package/dist/_chunks/{use-segment-params-BkpKAQ7D.js.map → use-segment-params-07V1TIxL.js.map} +1 -1
  41. package/dist/_chunks/{merge-search-params-BphMdht_.js → validation-DfyuMoK2.js} +2 -40
  42. package/dist/_chunks/validation-DfyuMoK2.js.map +1 -0
  43. package/dist/_chunks/{walkers-Tg0Alwcg.js → walkers-DQn5NNrf.js} +4 -4
  44. package/dist/_chunks/{walkers-Tg0Alwcg.js.map → walkers-DQn5NNrf.js.map} +1 -1
  45. package/dist/_chunks/{warnings-Cg47l5sk.js → warnings-B30wpfaS.js} +2 -2
  46. package/dist/_chunks/{warnings-Cg47l5sk.js.map → warnings-B30wpfaS.js.map} +1 -1
  47. package/dist/adapters/cloudflare.js +1 -1
  48. package/dist/adapters/nitro.js +1 -1
  49. package/dist/cache/index.js +3 -3
  50. package/dist/client/error-boundary.js +2 -2
  51. package/dist/client/index.js +10 -117
  52. package/dist/client/index.js.map +1 -1
  53. package/dist/client/internal.d.ts +1 -1
  54. package/dist/client/internal.d.ts.map +1 -1
  55. package/dist/client/internal.js +8 -8
  56. package/dist/client/use-cookie.d.ts +4 -0
  57. package/dist/client/use-cookie.d.ts.map +1 -1
  58. package/dist/codec.js +1 -1
  59. package/dist/cookies/define-cookie.d.ts +5 -45
  60. package/dist/cookies/define-cookie.d.ts.map +1 -1
  61. package/dist/cookies/index.js +252 -1
  62. package/dist/cookies/index.js.map +1 -1
  63. package/dist/fonts/ast.d.ts +98 -6
  64. package/dist/fonts/ast.d.ts.map +1 -1
  65. package/dist/fonts/local.d.ts +1 -1
  66. package/dist/fonts/transform.d.ts +15 -1
  67. package/dist/fonts/transform.d.ts.map +1 -1
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +1586 -11611
  70. package/dist/index.js.map +1 -1
  71. package/dist/plugins/dev-server.d.ts.map +1 -1
  72. package/dist/plugins/routing.d.ts.map +1 -1
  73. package/dist/plugins/static-build.d.ts +2 -23
  74. package/dist/plugins/static-build.d.ts.map +1 -1
  75. package/dist/routing/index.js +2 -2
  76. package/dist/search-params/index.js +3 -3
  77. package/dist/segment-params/index.js +1 -1
  78. package/dist/server/index.js +3 -3
  79. package/dist/server/internal.js +7 -7
  80. package/dist/server/request-context.d.ts.map +1 -1
  81. package/package.json +8 -6
  82. package/src/cli.ts +0 -0
  83. package/src/client/index.ts +0 -9
  84. package/src/client/internal.ts +1 -1
  85. package/src/client/use-cookie.ts +2 -2
  86. package/src/cookies/define-cookie.ts +100 -166
  87. package/src/fonts/ast.ts +488 -16
  88. package/src/fonts/local.ts +1 -1
  89. package/src/fonts/transform.ts +147 -236
  90. package/src/index.ts +14 -2
  91. package/src/plugins/dev-server.ts +8 -9
  92. package/src/plugins/routing.ts +1 -12
  93. package/src/plugins/static-build.ts +3 -83
  94. package/src/server/request-context.ts +1 -8
  95. package/LICENSE +0 -8
  96. package/dist/_chunks/actions-CQ8Z8VGL.js.map +0 -1
  97. package/dist/_chunks/chunk-BYIpzuS7.js +0 -39
  98. package/dist/_chunks/define-cookie-BjpIt4UC.js +0 -194
  99. package/dist/_chunks/define-cookie-BjpIt4UC.js.map +0 -1
  100. package/dist/_chunks/merge-search-params-BphMdht_.js.map +0 -1
  101. package/dist/plugins/server-action-exports.d.ts +0 -26
  102. package/dist/plugins/server-action-exports.d.ts.map +0 -1
  103. package/dist/routing/status-file-lint.d.ts +0 -34
  104. package/dist/routing/status-file-lint.d.ts.map +0 -1
  105. package/dist/utils/directive-parser.d.ts +0 -28
  106. package/dist/utils/directive-parser.d.ts.map +0 -1
  107. package/src/plugins/server-action-exports.ts +0 -220
  108. package/src/routing/status-file-lint.ts +0 -115
  109. package/src/utils/directive-parser.ts +0 -140
@@ -1,4 +1,255 @@
1
- import { i as defineCookie } from "../_chunks/define-cookie-BjpIt4UC.js";
1
+ import { n as fromSchema } from "../_chunks/schema-bridge-C3xl_vfb.js";
2
+ import { t as assertValidCookieName } from "../_chunks/validation-DfyuMoK2.js";
3
+ import { n as getSsrData } from "../_chunks/ssr-data-DzuI0bIV.js";
4
+ import { useSyncExternalStore } from "react";
5
+ import { getCookieJar } from "@timber-js/app/server";
6
+ //#region src/client/use-cookie.ts
7
+ /**
8
+ * useCookie — reactive client-side cookie hook.
9
+ *
10
+ * Uses useSyncExternalStore for SSR-safe, reactive cookie access.
11
+ * All components reading the same cookie name re-render on change.
12
+ * No cross-tab sync (intentional — see design/29-cookies.md).
13
+ *
14
+ * See design/29-cookies.md §"useCookie(name) Hook"
15
+ */
16
+ /** Per-name subscriber sets. */
17
+ var listeners = /* @__PURE__ */ new Map();
18
+ /** Parse a cookie name from document.cookie. */
19
+ function getCookieValue(name) {
20
+ if (typeof document === "undefined") return void 0;
21
+ const match = document.cookie.match(new RegExp("(?:^|;\\s*)" + name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\s*=\\s*([^;]*)"));
22
+ return match ? decodeURIComponent(match[1]) : void 0;
23
+ }
24
+ /** Serialize options into a cookie string suffix. */
25
+ function serializeOptions(options) {
26
+ if (!options) return "; Path=/; SameSite=Lax";
27
+ const parts = [];
28
+ parts.push(`Path=${options.path ?? "/"}`);
29
+ if (options.domain) parts.push(`Domain=${options.domain}`);
30
+ if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
31
+ if (options.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
32
+ const sameSite = options.sameSite ?? "lax";
33
+ parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
34
+ if (options.secure) parts.push("Secure");
35
+ return "; " + parts.join("; ");
36
+ }
37
+ /** Notify all subscribers for a given cookie name. */
38
+ function notify(name) {
39
+ const subs = listeners.get(name);
40
+ if (subs) for (const fn of subs) fn();
41
+ }
42
+ /**
43
+ * Notify useCookie subscribers that a cookie value changed.
44
+ * Called by defineCookie's imperative client .set()/.delete() methods
45
+ * so mounted useCookie() consumers re-render.
46
+ *
47
+ * @internal — framework use only
48
+ */
49
+ function notifyCookieChange(name) {
50
+ notify(name);
51
+ }
52
+ /**
53
+ * Reactive hook for reading/writing a client-side cookie.
54
+ *
55
+ * Returns `[value, setCookie, deleteCookie]`:
56
+ * - `value`: current cookie value (string | undefined)
57
+ * - `setCookie`: sets the cookie and triggers re-renders
58
+ * - `deleteCookie`: deletes the cookie and triggers re-renders
59
+ *
60
+ * @param name - Cookie name.
61
+ * @param defaultOptions - Default options for setCookie calls.
62
+ */
63
+ function useCookie(name, defaultOptions) {
64
+ const subscribe = (callback) => {
65
+ let subs = listeners.get(name);
66
+ if (!subs) {
67
+ subs = /* @__PURE__ */ new Set();
68
+ listeners.set(name, subs);
69
+ }
70
+ subs.add(callback);
71
+ return () => {
72
+ subs.delete(callback);
73
+ if (subs.size === 0) listeners.delete(name);
74
+ };
75
+ };
76
+ const getSnapshot = () => getCookieValue(name);
77
+ const getServerSnapshot = () => getSsrData()?.cookies.get(name);
78
+ const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
79
+ assertValidCookieName(name);
80
+ const setCookie = (newValue, options) => {
81
+ if (typeof newValue !== "string") throw new Error(`[timber] useCookie(${JSON.stringify(name)}): value must be a string, got ${typeof newValue}.\n To store a JSON-serializable value, use defineCookie + jsonCookieCodec from\n '@timber-js/app/cookies' and call its useCookie() hook instead.`);
82
+ const merged = {
83
+ ...defaultOptions,
84
+ ...options
85
+ };
86
+ document.cookie = `${name}=${encodeURIComponent(newValue)}${serializeOptions(merged)}`;
87
+ notify(name);
88
+ };
89
+ const deleteCookie = () => {
90
+ const path = defaultOptions?.path ?? "/";
91
+ const domain = defaultOptions?.domain;
92
+ let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;
93
+ if (domain) cookieStr += `; Domain=${domain}`;
94
+ document.cookie = cookieStr;
95
+ notify(name);
96
+ };
97
+ return [
98
+ value,
99
+ setCookie,
100
+ deleteCookie
101
+ ];
102
+ }
103
+ //#endregion
104
+ //#region src/cookies/define-cookie.ts
105
+ /**
106
+ * Try to get the server cookie jar. Returns null if we're in the client
107
+ * environment (stub throws) or if there's no request context.
108
+ *
109
+ * On the server, getCookieJar() throws "outside of a request context" if
110
+ * called without an ALS store — this is a real error and is re-thrown.
111
+ * The client stub throws a different message — that's caught and returns null.
112
+ */
113
+ function tryGetServerCookieJar() {
114
+ try {
115
+ return getCookieJar();
116
+ } catch (e) {
117
+ if (e instanceof Error && e.message.includes("outside of a request context")) throw e;
118
+ return null;
119
+ }
120
+ }
121
+ /** Write a cookie via document.cookie and notify useCookie subscribers. */
122
+ function setClientCookie(name, value, options) {
123
+ const parts = [`${name}=${encodeURIComponent(value)}`];
124
+ const path = options?.path ?? "/";
125
+ parts.push(`Path=${path}`);
126
+ if (options?.domain) parts.push(`Domain=${options.domain}`);
127
+ if (options?.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
128
+ if (options?.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
129
+ const sameSite = options?.sameSite ?? "lax";
130
+ parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
131
+ if (options?.secure) parts.push("Secure");
132
+ document.cookie = parts.join("; ");
133
+ notifyCookieChange(name);
134
+ }
135
+ /** Delete a cookie via document.cookie and notify useCookie subscribers. */
136
+ function deleteClientCookie(name, options) {
137
+ const path = options?.path ?? "/";
138
+ const domain = options?.domain;
139
+ let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;
140
+ if (domain) cookieStr += `; Domain=${domain}`;
141
+ document.cookie = cookieStr;
142
+ notifyCookieChange(name);
143
+ }
144
+ function resolveCodec(codecOrSchema) {
145
+ if (typeof codecOrSchema.parse === "function" && typeof codecOrSchema.serialize === "function") return codecOrSchema;
146
+ if (typeof codecOrSchema === "object" && codecOrSchema !== null && "~standard" in codecOrSchema) return fromSchema(codecOrSchema);
147
+ throw new Error("[timber] defineCookie: codec must be a Codec<T> (with parse/serialize methods) or a Standard Schema object (Zod, Valibot, ArkType).");
148
+ }
149
+ /**
150
+ * Define a typed cookie.
151
+ *
152
+ * ```ts
153
+ * import { defineCookie } from '@timber-js/app/cookies';
154
+ * import { z } from 'zod/v4';
155
+ *
156
+ * // httpOnly: false — client methods available
157
+ * export const themeCookie = defineCookie('theme', {
158
+ * codec: z.enum(['light', 'dark', 'system']).default('system'),
159
+ * httpOnly: false,
160
+ * maxAge: 60 * 60 * 24 * 365,
161
+ * });
162
+ *
163
+ * // Server or client
164
+ * const theme = themeCookie.get();
165
+ * themeCookie.set('dark');
166
+ *
167
+ * // Client hook
168
+ * const [theme, setTheme] = themeCookie.useCookie();
169
+ *
170
+ * // httpOnly: true (default) — server-only, no client methods
171
+ * export const sessionCookie = defineCookie('session', {
172
+ * codec: z.string(),
173
+ * });
174
+ * sessionCookie.get(); // works on server
175
+ * sessionCookie.useCookie(); // TS error — httpOnly cookie
176
+ * ```
177
+ */
178
+ function defineCookie(name, options) {
179
+ const { codec: codecOrSchema, ...cookieOpts } = options;
180
+ const codec = resolveCodec(codecOrSchema);
181
+ const resolvedOptions = { ...cookieOpts };
182
+ const isHttpOnly = options.httpOnly !== false;
183
+ function getClientOpts() {
184
+ return {
185
+ path: resolvedOptions.path,
186
+ domain: resolvedOptions.domain,
187
+ maxAge: resolvedOptions.maxAge,
188
+ expires: resolvedOptions.expires,
189
+ sameSite: resolvedOptions.sameSite,
190
+ secure: resolvedOptions.secure
191
+ };
192
+ }
193
+ const base = {
194
+ name,
195
+ options: resolvedOptions,
196
+ codec,
197
+ get() {
198
+ const serverJar = tryGetServerCookieJar();
199
+ if (serverJar) return codec.parse(serverJar.get(name));
200
+ if (isHttpOnly) throw new Error(`[timber] defineCookie('${name}').get() cannot be used with httpOnly cookies — the browser cannot access them. Set httpOnly: false to enable client access.`);
201
+ const raw = getCookieValue(name);
202
+ return codec.parse(raw);
203
+ },
204
+ set(value) {
205
+ const serverJar = tryGetServerCookieJar();
206
+ if (serverJar) {
207
+ const serialized = codec.serialize(value);
208
+ if (serialized === null) serverJar.delete(name, {
209
+ path: resolvedOptions.path,
210
+ domain: resolvedOptions.domain
211
+ });
212
+ else serverJar.set(name, serialized, resolvedOptions);
213
+ return;
214
+ }
215
+ if (isHttpOnly) throw new Error(`[timber] defineCookie('${name}').set() cannot be used with httpOnly cookies — the browser cannot access them. Set httpOnly: false to enable client access.`);
216
+ const serialized = codec.serialize(value);
217
+ if (serialized === null) deleteClientCookie(name, getClientOpts());
218
+ else setClientCookie(name, serialized, getClientOpts());
219
+ },
220
+ delete() {
221
+ const serverJar = tryGetServerCookieJar();
222
+ if (serverJar) {
223
+ serverJar.delete(name, {
224
+ path: resolvedOptions.path,
225
+ domain: resolvedOptions.domain
226
+ });
227
+ return;
228
+ }
229
+ if (isHttpOnly) throw new Error(`[timber] defineCookie('${name}').delete() cannot be used with httpOnly cookies — the browser cannot access them. Set httpOnly: false to enable client access.`);
230
+ deleteClientCookie(name, getClientOpts());
231
+ }
232
+ };
233
+ if (isHttpOnly) return base;
234
+ return {
235
+ ...base,
236
+ useCookie() {
237
+ const [raw, setRaw, deleteRaw] = useCookie(name, getClientOpts());
238
+ const parsed = codec.parse(raw);
239
+ const setTyped = (value) => {
240
+ const serialized = codec.serialize(value);
241
+ if (serialized === null) deleteRaw();
242
+ else setRaw(serialized);
243
+ };
244
+ return [
245
+ parsed,
246
+ setTyped,
247
+ deleteRaw
248
+ ];
249
+ }
250
+ };
251
+ }
252
+ //#endregion
2
253
  //#region src/cookies/json-cookie.ts
3
254
  /**
4
255
  * Build a CookieCodec that JSON-encodes the value. The framework's
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/cookies/json-cookie.ts"],"sourcesContent":["/**\n * jsonCookieCodec — Codec helper for storing JSON-serializable values in\n * cookies.\n *\n * The codec is intentionally minimal: `JSON.stringify` on serialize,\n * `JSON.parse` on parse. The framework handles the URL encoding /\n * decoding around it (see design/29-cookies.md §\"Encoding Contract\"):\n *\n * defineCookie.setCookie(value)\n * → codec.serialize: JSON.stringify → '{\"a\":1}'\n * → cookies().set: encodeURIComponent → '%7B%22a%22%3A1%7D'\n * → wire: Set-Cookie: prefs=%7B%22a%22%3A1%7D\n *\n * defineCookie.getCookie()\n * → wire: Cookie: prefs=%7B%22a%22%3A1%7D\n * → parseCookieHeader: decodeURIComponent → '{\"a\":1}'\n * → codec.parse: JSON.parse → { a: 1 }\n *\n * The same chain works on the client: `useCookie` auto-encodes on writes\n * and auto-decodes on reads, so `jsonCookieCodec` composes with both the\n * server `defineCookie` methods and the client `useCookie` hook with no\n * environment-specific branches.\n *\n * Parsing is total: any non-JSON value (or `undefined`) returns the\n * supplied default. This matches the \"never crash on user-controlled\n * cookie input\" semantics that `fromSchema` uses for typed search params.\n *\n * ```ts\n * import { defineCookie, jsonCookieCodec } from '@timber-js/app/cookies';\n *\n * interface Prefs { lang: string; fontSize: number }\n *\n * export const prefsCookie = defineCookie('prefs', {\n * codec: jsonCookieCodec<Prefs>({ lang: 'en', fontSize: 16 }),\n * httpOnly: false,\n * maxAge: 60 * 60 * 24 * 365,\n * });\n *\n * await prefsCookie.setCookie({ lang: 'fr', fontSize: 18 });\n * ```\n */\n\nimport type { Codec } from '../codec.js';\n\n/**\n * Build a CookieCodec that JSON-encodes the value. The framework's\n * cookie write path then URL-encodes the JSON string into a valid\n * `cookie-octet` form, and the read path reverses both transforms.\n *\n * @param defaultValue - Returned by `parse` when the cookie is missing\n * or the stored value cannot be JSON-parsed. Optional — if omitted,\n * `parse` returns `undefined` on missing/malformed input.\n *\n * The default is **deep-cloned** on every fallback return via\n * `structuredClone`, so mutating the parsed result in one request\n * cannot leak into later requests that fall back to the same\n * default. This matters for long-lived server processes where a\n * codec is defined once at module load and shared across all\n * requests — without the clone, a user doing\n * `const prefs = prefsCookie.get(); prefs.lang = 'fr'` on a missing\n * cookie would mutate the module-level default and poison every\n * later fallback. See the \"shared mutable default\" regression test\n * in `tests/define-cookie.test.ts`.\n */\nexport function jsonCookieCodec<T>(defaultValue?: T): Codec<T> {\n // Resolve the fallback at call time, not capture time, so every\n // fallback return produces a fresh deep copy. structuredClone handles\n // nested objects, arrays, dates, maps, sets — everything\n // JSON-serializable plus more. For primitives and undefined,\n // structuredClone is effectively a no-op.\n const cloneDefault = (): T => {\n if (defaultValue === undefined || defaultValue === null) {\n return defaultValue as T;\n }\n // structuredClone is a Node built-in since Node 17, available in\n // all supported runtimes.\n return structuredClone(defaultValue);\n };\n\n return {\n parse(value: string | string[] | undefined): T {\n if (value === undefined || value === '') {\n return cloneDefault();\n }\n // Cookies are single-valued by name; defensively pick the last\n // entry if a Codec consumer somehow passes an array.\n const raw = Array.isArray(value) ? value[value.length - 1] : value;\n if (raw === undefined || raw === '') {\n return cloneDefault();\n }\n try {\n return JSON.parse(raw) as T;\n } catch {\n return cloneDefault();\n }\n },\n\n serialize(value: T): string | null {\n if (value === null || value === undefined) {\n return null;\n }\n return JSON.stringify(value);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,gBAAmB,cAA4B;CAM7D,MAAM,qBAAwB;AAC5B,MAAI,iBAAiB,KAAA,KAAa,iBAAiB,KACjD,QAAO;AAIT,SAAO,gBAAgB,aAAa;;AAGtC,QAAO;EACL,MAAM,OAAyC;AAC7C,OAAI,UAAU,KAAA,KAAa,UAAU,GACnC,QAAO,cAAc;GAIvB,MAAM,MAAM,MAAM,QAAQ,MAAM,GAAG,MAAM,MAAM,SAAS,KAAK;AAC7D,OAAI,QAAQ,KAAA,KAAa,QAAQ,GAC/B,QAAO,cAAc;AAEvB,OAAI;AACF,WAAO,KAAK,MAAM,IAAI;WAChB;AACN,WAAO,cAAc;;;EAIzB,UAAU,OAAyB;AACjC,OAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B,QAAO;AAET,UAAO,KAAK,UAAU,MAAM;;EAE/B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/client/use-cookie.ts","../../src/cookies/define-cookie.ts","../../src/cookies/json-cookie.ts"],"sourcesContent":["/**\n * useCookie — reactive client-side cookie hook.\n *\n * Uses useSyncExternalStore for SSR-safe, reactive cookie access.\n * All components reading the same cookie name re-render on change.\n * No cross-tab sync (intentional — see design/29-cookies.md).\n *\n * See design/29-cookies.md §\"useCookie(name) Hook\"\n */\n\nimport { useSyncExternalStore } from 'react';\nimport { getSsrData } from './ssr-data.js';\nimport { assertValidCookieName } from '../cookies/validation.js';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\nexport interface ClientCookieOptions {\n /** URL path scope. Default: '/'. */\n path?: string;\n /** Domain scope. Default: omitted (current domain). */\n domain?: string;\n /** Max age in seconds. */\n maxAge?: number;\n /** Expiration date. */\n expires?: Date;\n /** Cross-site policy. Default: 'lax'. */\n sameSite?: 'strict' | 'lax' | 'none';\n /** Only send over HTTPS. Default: true in production. */\n secure?: boolean;\n}\n\nexport type CookieSetter = (value: string, options?: ClientCookieOptions) => void;\n\n// ─── Module-Level Cookie Store ────────────────────────────────────────────\n\ntype Listener = () => void;\n\n/** Per-name subscriber sets. */\nconst listeners = new Map<string, Set<Listener>>();\n\n/** Parse a cookie name from document.cookie. */\nexport function getCookieValue(name: string): string | undefined {\n if (typeof document === 'undefined') return undefined;\n const match = document.cookie.match(\n new RegExp('(?:^|;\\\\s*)' + name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') + '\\\\s*=\\\\s*([^;]*)')\n );\n return match ? decodeURIComponent(match[1]) : undefined;\n}\n\n/** Serialize options into a cookie string suffix. */\nexport function serializeOptions(options?: ClientCookieOptions): string {\n if (!options) return '; Path=/; SameSite=Lax';\n const parts: string[] = [];\n parts.push(`Path=${options.path ?? '/'}`);\n if (options.domain) parts.push(`Domain=${options.domain}`);\n if (options.maxAge !== undefined) parts.push(`Max-Age=${options.maxAge}`);\n if (options.expires) parts.push(`Expires=${options.expires.toUTCString()}`);\n const sameSite = options.sameSite ?? 'lax';\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);\n if (options.secure) parts.push('Secure');\n return '; ' + parts.join('; ');\n}\n\n/** Notify all subscribers for a given cookie name. */\nfunction notify(name: string): void {\n const subs = listeners.get(name);\n if (subs) {\n for (const fn of subs) fn();\n }\n}\n\n/**\n * Notify useCookie subscribers that a cookie value changed.\n * Called by defineCookie's imperative client .set()/.delete() methods\n * so mounted useCookie() consumers re-render.\n *\n * @internal — framework use only\n */\nexport function notifyCookieChange(name: string): void {\n notify(name);\n}\n\n// ─── Hook ─────────────────────────────────────────────────────────────────\n\n/**\n * Reactive hook for reading/writing a client-side cookie.\n *\n * Returns `[value, setCookie, deleteCookie]`:\n * - `value`: current cookie value (string | undefined)\n * - `setCookie`: sets the cookie and triggers re-renders\n * - `deleteCookie`: deletes the cookie and triggers re-renders\n *\n * @param name - Cookie name.\n * @param defaultOptions - Default options for setCookie calls.\n */\nexport function useCookie(\n name: string,\n defaultOptions?: ClientCookieOptions\n): [value: string | undefined, setCookie: CookieSetter, deleteCookie: () => void] {\n const subscribe = (callback: Listener): (() => void) => {\n let subs = listeners.get(name);\n if (!subs) {\n subs = new Set();\n listeners.set(name, subs);\n }\n subs.add(callback);\n return () => {\n subs!.delete(callback);\n if (subs!.size === 0) listeners.delete(name);\n };\n };\n\n const getSnapshot = (): string | undefined => getCookieValue(name);\n const getServerSnapshot = (): string | undefined => getSsrData()?.cookies.get(name);\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n\n // Validate the name once per hook instance — names are typically\n // stable string literals, so this catches the bug at first render\n // rather than on every write. Throws via `assertValidCookieName` with\n // a precise error if the name violates RFC 7230 token rules.\n assertValidCookieName(name);\n\n const setCookie: CookieSetter = (newValue: string, options?: ClientCookieOptions) => {\n if (typeof newValue !== 'string') {\n throw new Error(\n `[timber] useCookie(${JSON.stringify(name)}): value must be a string, got ${typeof newValue}.\\n` +\n ` To store a JSON-serializable value, use defineCookie + jsonCookieCodec from\\n` +\n ` '@timber-js/app/cookies' and call its useCookie() hook instead.`\n );\n }\n const merged = { ...defaultOptions, ...options };\n // Auto-encode mirrors the server's `cookies().set()` contract:\n // values are URL-encoded on write, URL-decoded on read, so the\n // logical bytes round-trip losslessly. See design/29-cookies.md\n // §\"Encoding Contract\".\n document.cookie = `${name}=${encodeURIComponent(newValue)}${serializeOptions(merged)}`;\n notify(name);\n };\n\n const deleteCookie = (): void => {\n const path = defaultOptions?.path ?? '/';\n const domain = defaultOptions?.domain;\n let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;\n if (domain) cookieStr += `; Domain=${domain}`;\n document.cookie = cookieStr;\n notify(name);\n };\n\n return [value, setCookie, deleteCookie];\n}\n","/**\n * defineCookie — typed cookie definitions.\n *\n * Bundles name + codec + options into a reusable CookieDefinition<T>\n * with sync .get(), .set(), .delete() isomorphic methods (server + client)\n * and a .useCookie() client hook.\n *\n * Environment detection is call-time: on the server, getCookieJar() is\n * used directly (ALS-backed). On the client, document.cookie helpers\n * and the useCookie hook are used. No registration pattern — imports\n * resolve via the shims plugin (client bundle gets a stub for\n * @timber-js/app/server).\n *\n * Standard Schema objects (Zod, Valibot, ArkType) are auto-detected in\n * the codec option — no explicit fromSchema() wrapper needed.\n *\n * See design/29-cookies.md §\"Typed Cookies with Schema Validation\"\n */\n\nimport type { CookieOptions } from '../server/cookie-context.js';\nimport type { ClientCookieOptions } from '../client/use-cookie.js';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\nimport type { Codec } from '../codec.js';\nimport type { StandardSchemaV1 } from '../schema-bridge.js';\n\n/**\n * A codec that converts between string cookie values and typed values.\n * Type alias for the shared Codec<T> protocol.\n */\nexport type CookieCodec<T> = Codec<T>;\n\n/** Options for defineCookie: codec + CookieOptions merged. */\nexport interface DefineCookieOptions<T, HttpOnly extends boolean = boolean> extends CookieOptions {\n /**\n * Codec for parsing/serializing the cookie value.\n * Accepts a Codec<T> or a Standard Schema object (Zod, Valibot, ArkType)\n * which is auto-wrapped via fromSchema.\n */\n codec: CookieCodec<T> | StandardSchemaV1<T>;\n /**\n * Prevent client-side JS access. Default: true.\n * When true (or omitted), client methods (useCookie, get/set/delete on\n * client) are omitted from the return type and throw at runtime.\n */\n httpOnly?: HttpOnly;\n}\n\n/**\n * Server-only cookie definition. Returned when httpOnly is true or omitted.\n * Client methods are absent from the type — accessing them is a TS error.\n */\nexport interface ServerOnlyCookieDefinition<T> {\n readonly name: string;\n readonly options: CookieOptions;\n readonly codec: CookieCodec<T>;\n\n /** Read the typed value. Sync, isomorphic (server + client). */\n get(): T;\n /** Set the typed value. Sync, isomorphic (server + client). */\n set(value: T): void;\n /** Delete the cookie. Sync, isomorphic (server + client). */\n delete(): void;\n}\n\n/**\n * Full cookie definition with client methods. Returned when httpOnly: false.\n */\nexport interface CookieDefinition<T> extends ServerOnlyCookieDefinition<T> {\n /** Client: React hook for reading/writing this cookie. Returns [value, setter, deleter]. */\n useCookie(): [T, (value: T) => void, () => void];\n}\n\n// ─── Direct Imports (no registration) ─────────────────────────────────────\n//\n// Server: getCookieJar is imported from @timber-js/app/server. In the client\n// bundle, the shims plugin replaces @timber-js/app/server with a stub module\n// where getCookieJar throws on call. We detect the environment at call time\n// by trying getCookieJar() — if it throws the stub error, we fall through\n// to the client path.\n//\n// Client: useCookie, getCookieValue, notifyCookieChange\n// are imported from use-cookie.ts. These are safe in all environments (no\n// node:async_hooks dependency).\n//\n// Schema: fromSchema is a pure function — safe in all environments.\n\nimport { getCookieJar } from '@timber-js/app/server';\nimport { fromSchema } from '../schema-bridge.js';\nimport {\n useCookie as useRawCookie,\n notifyCookieChange,\n getCookieValue,\n} from '../client/use-cookie.js';\n\n// ─── Environment Detection ────────────────────────────────────────────────\n\n/**\n * Try to get the server cookie jar. Returns null if we're in the client\n * environment (stub throws) or if there's no request context.\n *\n * On the server, getCookieJar() throws \"outside of a request context\" if\n * called without an ALS store — this is a real error and is re-thrown.\n * The client stub throws a different message — that's caught and returns null.\n */\nfunction tryGetServerCookieJar(): ReturnType<typeof getCookieJar> | null {\n try {\n return getCookieJar();\n } catch (e) {\n // Server-side \"no request context\" error — re-throw as a real bug.\n if (e instanceof Error && e.message.includes('outside of a request context')) {\n throw e;\n }\n // Client stub error or other — fall through to client path.\n return null;\n }\n}\n\n// ─── Client Cookie Helpers ────────────────────────────────────────────────\n\n/** Write a cookie via document.cookie and notify useCookie subscribers. */\nfunction setClientCookie(name: string, value: string, options?: ClientCookieOptions): void {\n const parts: string[] = [`${name}=${encodeURIComponent(value)}`];\n const path = options?.path ?? '/';\n parts.push(`Path=${path}`);\n if (options?.domain) parts.push(`Domain=${options.domain}`);\n if (options?.maxAge !== undefined) parts.push(`Max-Age=${options.maxAge}`);\n if (options?.expires) parts.push(`Expires=${options.expires.toUTCString()}`);\n const sameSite = options?.sameSite ?? 'lax';\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);\n if (options?.secure) parts.push('Secure');\n document.cookie = parts.join('; ');\n notifyCookieChange(name);\n}\n\n/** Delete a cookie via document.cookie and notify useCookie subscribers. */\nfunction deleteClientCookie(name: string, options?: ClientCookieOptions): void {\n const path = options?.path ?? '/';\n const domain = options?.domain;\n let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;\n if (domain) cookieStr += `; Domain=${domain}`;\n document.cookie = cookieStr;\n notifyCookieChange(name);\n}\n\n// ─── Standard Schema Auto-Detection ───────────────────────────────────────\n\nfunction resolveCodec<T>(codecOrSchema: CookieCodec<T> | StandardSchemaV1<T>): CookieCodec<T> {\n // If it has parse + serialize, it's already a Codec\n if (\n typeof (codecOrSchema as Codec<T>).parse === 'function' &&\n typeof (codecOrSchema as Codec<T>).serialize === 'function'\n ) {\n return codecOrSchema as CookieCodec<T>;\n }\n\n // Auto-detect Standard Schema\n if (typeof codecOrSchema === 'object' && codecOrSchema !== null && '~standard' in codecOrSchema) {\n return fromSchema(codecOrSchema as StandardSchemaV1<unknown>) as CookieCodec<T>;\n }\n\n throw new Error(\n '[timber] defineCookie: codec must be a Codec<T> (with parse/serialize methods) ' +\n 'or a Standard Schema object (Zod, Valibot, ArkType).'\n );\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────\n\n/**\n * Define a typed cookie.\n *\n * ```ts\n * import { defineCookie } from '@timber-js/app/cookies';\n * import { z } from 'zod/v4';\n *\n * // httpOnly: false — client methods available\n * export const themeCookie = defineCookie('theme', {\n * codec: z.enum(['light', 'dark', 'system']).default('system'),\n * httpOnly: false,\n * maxAge: 60 * 60 * 24 * 365,\n * });\n *\n * // Server or client\n * const theme = themeCookie.get();\n * themeCookie.set('dark');\n *\n * // Client hook\n * const [theme, setTheme] = themeCookie.useCookie();\n *\n * // httpOnly: true (default) — server-only, no client methods\n * export const sessionCookie = defineCookie('session', {\n * codec: z.string(),\n * });\n * sessionCookie.get(); // works on server\n * sessionCookie.useCookie(); // TS error — httpOnly cookie\n * ```\n */\nexport function defineCookie<T, HttpOnly extends boolean = true>(\n name: string,\n options: DefineCookieOptions<T, HttpOnly>\n): HttpOnly extends false ? CookieDefinition<T> : ServerOnlyCookieDefinition<T> {\n const { codec: codecOrSchema, ...cookieOpts } = options;\n const codec = resolveCodec(codecOrSchema);\n const resolvedOptions: CookieOptions = { ...cookieOpts };\n const isHttpOnly = options.httpOnly !== false; // default true\n\n function getClientOpts(): ClientCookieOptions {\n return {\n path: resolvedOptions.path,\n domain: resolvedOptions.domain,\n maxAge: resolvedOptions.maxAge,\n expires: resolvedOptions.expires,\n sameSite: resolvedOptions.sameSite,\n secure: resolvedOptions.secure,\n };\n }\n\n const base: ServerOnlyCookieDefinition<T> = {\n name,\n options: resolvedOptions,\n codec,\n\n get(): T {\n const serverJar = tryGetServerCookieJar();\n if (serverJar) {\n return codec.parse(serverJar.get(name));\n }\n // Client path\n if (isHttpOnly) {\n throw new Error(\n `[timber] defineCookie('${name}').get() cannot be used with httpOnly cookies — ` +\n `the browser cannot access them. Set httpOnly: false to enable client access.`\n );\n }\n const raw = getCookieValue(name);\n return codec.parse(raw);\n },\n\n set(value: T): void {\n const serverJar = tryGetServerCookieJar();\n if (serverJar) {\n const serialized = codec.serialize(value);\n if (serialized === null) {\n serverJar.delete(name, {\n path: resolvedOptions.path,\n domain: resolvedOptions.domain,\n });\n } else {\n serverJar.set(name, serialized, resolvedOptions);\n }\n return;\n }\n // Client path\n if (isHttpOnly) {\n throw new Error(\n `[timber] defineCookie('${name}').set() cannot be used with httpOnly cookies — ` +\n `the browser cannot access them. Set httpOnly: false to enable client access.`\n );\n }\n const serialized = codec.serialize(value);\n if (serialized === null) {\n deleteClientCookie(name, getClientOpts());\n } else {\n setClientCookie(name, serialized, getClientOpts());\n }\n },\n\n delete(): void {\n const serverJar = tryGetServerCookieJar();\n if (serverJar) {\n serverJar.delete(name, {\n path: resolvedOptions.path,\n domain: resolvedOptions.domain,\n });\n return;\n }\n // Client path\n if (isHttpOnly) {\n throw new Error(\n `[timber] defineCookie('${name}').delete() cannot be used with httpOnly cookies — ` +\n `the browser cannot access them. Set httpOnly: false to enable client access.`\n );\n }\n deleteClientCookie(name, getClientOpts());\n },\n };\n\n if (isHttpOnly) {\n return base as HttpOnly extends false ? CookieDefinition<T> : ServerOnlyCookieDefinition<T>;\n }\n\n // httpOnly: false — add useCookie client hook\n const full: CookieDefinition<T> = {\n ...base,\n\n useCookie(): [T, (value: T) => void, () => void] {\n const clientOpts = getClientOpts();\n const [raw, setRaw, deleteRaw] = useRawCookie(name, clientOpts);\n const parsed = codec.parse(raw);\n\n const setTyped = (value: T): void => {\n const serialized = codec.serialize(value);\n if (serialized === null) {\n deleteRaw();\n } else {\n setRaw(serialized);\n }\n };\n\n return [parsed, setTyped, deleteRaw];\n },\n };\n\n return full as HttpOnly extends false ? CookieDefinition<T> : ServerOnlyCookieDefinition<T>;\n}\n","/**\n * jsonCookieCodec — Codec helper for storing JSON-serializable values in\n * cookies.\n *\n * The codec is intentionally minimal: `JSON.stringify` on serialize,\n * `JSON.parse` on parse. The framework handles the URL encoding /\n * decoding around it (see design/29-cookies.md §\"Encoding Contract\"):\n *\n * defineCookie.setCookie(value)\n * → codec.serialize: JSON.stringify → '{\"a\":1}'\n * → cookies().set: encodeURIComponent → '%7B%22a%22%3A1%7D'\n * → wire: Set-Cookie: prefs=%7B%22a%22%3A1%7D\n *\n * defineCookie.getCookie()\n * → wire: Cookie: prefs=%7B%22a%22%3A1%7D\n * → parseCookieHeader: decodeURIComponent → '{\"a\":1}'\n * → codec.parse: JSON.parse → { a: 1 }\n *\n * The same chain works on the client: `useCookie` auto-encodes on writes\n * and auto-decodes on reads, so `jsonCookieCodec` composes with both the\n * server `defineCookie` methods and the client `useCookie` hook with no\n * environment-specific branches.\n *\n * Parsing is total: any non-JSON value (or `undefined`) returns the\n * supplied default. This matches the \"never crash on user-controlled\n * cookie input\" semantics that `fromSchema` uses for typed search params.\n *\n * ```ts\n * import { defineCookie, jsonCookieCodec } from '@timber-js/app/cookies';\n *\n * interface Prefs { lang: string; fontSize: number }\n *\n * export const prefsCookie = defineCookie('prefs', {\n * codec: jsonCookieCodec<Prefs>({ lang: 'en', fontSize: 16 }),\n * httpOnly: false,\n * maxAge: 60 * 60 * 24 * 365,\n * });\n *\n * await prefsCookie.setCookie({ lang: 'fr', fontSize: 18 });\n * ```\n */\n\nimport type { Codec } from '../codec.js';\n\n/**\n * Build a CookieCodec that JSON-encodes the value. The framework's\n * cookie write path then URL-encodes the JSON string into a valid\n * `cookie-octet` form, and the read path reverses both transforms.\n *\n * @param defaultValue - Returned by `parse` when the cookie is missing\n * or the stored value cannot be JSON-parsed. Optional — if omitted,\n * `parse` returns `undefined` on missing/malformed input.\n *\n * The default is **deep-cloned** on every fallback return via\n * `structuredClone`, so mutating the parsed result in one request\n * cannot leak into later requests that fall back to the same\n * default. This matters for long-lived server processes where a\n * codec is defined once at module load and shared across all\n * requests — without the clone, a user doing\n * `const prefs = prefsCookie.get(); prefs.lang = 'fr'` on a missing\n * cookie would mutate the module-level default and poison every\n * later fallback. See the \"shared mutable default\" regression test\n * in `tests/define-cookie.test.ts`.\n */\nexport function jsonCookieCodec<T>(defaultValue?: T): Codec<T> {\n // Resolve the fallback at call time, not capture time, so every\n // fallback return produces a fresh deep copy. structuredClone handles\n // nested objects, arrays, dates, maps, sets — everything\n // JSON-serializable plus more. For primitives and undefined,\n // structuredClone is effectively a no-op.\n const cloneDefault = (): T => {\n if (defaultValue === undefined || defaultValue === null) {\n return defaultValue as T;\n }\n // structuredClone is a Node built-in since Node 17, available in\n // all supported runtimes.\n return structuredClone(defaultValue);\n };\n\n return {\n parse(value: string | string[] | undefined): T {\n if (value === undefined || value === '') {\n return cloneDefault();\n }\n // Cookies are single-valued by name; defensively pick the last\n // entry if a Codec consumer somehow passes an array.\n const raw = Array.isArray(value) ? value[value.length - 1] : value;\n if (raw === undefined || raw === '') {\n return cloneDefault();\n }\n try {\n return JSON.parse(raw) as T;\n } catch {\n return cloneDefault();\n }\n },\n\n serialize(value: T): string | null {\n if (value === null || value === undefined) {\n return null;\n }\n return JSON.stringify(value);\n },\n };\n}\n"],"mappings":"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"}
@@ -1,15 +1,26 @@
1
1
  /**
2
- * Acorn-based AST utilities for extracting static font configs from source code.
2
+ * AST utilities for extracting static font configs from source code.
3
+ * Uses OXC via Vite's `parseAst` — handles JS/JSX/TS/TSX natively.
3
4
  *
4
- * Replaces the fragile regex-based extraction in fonts.ts and local.ts.
5
- * Uses acorn (already a Vite dependency) for robust parsing that handles
6
- * comments, trailing commas, multi-line configs, and other edge cases
7
- * the regex approach missed.
5
+ * Provides two tiers of API:
6
+ *
7
+ * 1. **Source-text helpers** (`extractFontConfigAst`, `extractLocalFontConfigAst`,
8
+ * `detectDynamicFontCallAst`) — parse a snippet and return extracted config.
9
+ * Still used by tests and callers that have only a string.
10
+ *
11
+ * 2. **AST-node helpers** (`extractGoogleFontConfigFromNode`,
12
+ * `extractLocalFontConfigFromNode`, `findFontCallSites`) — operate on
13
+ * nodes from an already-parsed Program so the transform hook can share
14
+ * one parse with all analysis steps.
8
15
  *
9
16
  * Design doc: 24-fonts.md §"Step 1: Static Analysis"
10
17
  */
11
18
  import type { GoogleFontConfig } from './types.js';
12
19
  import type { LocalFontConfig } from './types.js';
20
+ interface AstNode {
21
+ type: string;
22
+ [key: string]: unknown;
23
+ }
13
24
  /**
14
25
  * Extract a GoogleFontConfig from the source text of a font function call's
15
26
  * object argument.
@@ -31,8 +42,89 @@ export declare function extractLocalFontConfigAst(callSource: string): LocalFont
31
42
  * Detect if source code contains dynamic/computed font function calls
32
43
  * that cannot be statically analyzed.
33
44
  *
34
- * Uses acorn to parse the full source and inspect CallExpression nodes.
45
+ * Uses OXC (via vite.parseAst) to parse the full source and inspect CallExpression nodes.
35
46
  * Returns the offending expression string if found, null if all calls are static.
36
47
  */
37
48
  export declare function detectDynamicFontCallAst(source: string, importedNames: string[]): string | null;
49
+ /**
50
+ * Extract a GoogleFontConfig from an ObjectExpression AST node.
51
+ *
52
+ * This is the node-level equivalent of `extractFontConfigAst` — it skips
53
+ * the parse step because the caller already has a parsed Program.
54
+ */
55
+ export declare function extractGoogleFontConfigFromNode(node: AstNode): GoogleFontConfig | null;
56
+ /**
57
+ * Extract a LocalFontConfig from an ObjectExpression AST node.
58
+ */
59
+ export declare function extractLocalFontConfigFromNode(node: AstNode): LocalFontConfig | null;
60
+ /** A font import binding discovered from an ImportDeclaration. */
61
+ export interface FontBinding {
62
+ /** The local name used in the module (after `as`, if present). */
63
+ localName: string;
64
+ /**
65
+ * The original exported name (before `as`). For Google fonts this is
66
+ * the PascalCase_With_Underscores name that maps to the family. For
67
+ * local fonts (`default` import), this is `'default'`.
68
+ */
69
+ importedName: string;
70
+ /** `'google'` or `'local'`. */
71
+ provider: 'google' | 'local';
72
+ /** The AST node of the ImportDeclaration (for removal via magic-string). */
73
+ importNode: AstNode & {
74
+ start: number;
75
+ end: number;
76
+ };
77
+ }
78
+ /** A font function call site discovered from a CallExpression. */
79
+ export interface FontCallSite {
80
+ /** The binding that this call references. */
81
+ binding: FontBinding;
82
+ /**
83
+ * The variable name this call is assigned to, if the call appears in a
84
+ * VariableDeclarator. `null` for bare expression statements.
85
+ */
86
+ assignedName: string | null;
87
+ /** The first argument AST node (expected to be an ObjectExpression). */
88
+ configNode: AstNode;
89
+ /**
90
+ * The outermost AST node to replace. For a VariableDeclaration with a
91
+ * single declarator this is the full declaration; for a bare expression
92
+ * statement it is the ExpressionStatement. The transform replaces
93
+ * `source[replaceStart..replaceEnd]`.
94
+ */
95
+ replaceStart: number;
96
+ replaceEnd: number;
97
+ /** Line number (1-based) of the call for error messages. */
98
+ line: number;
99
+ /** Column (0-based) of the call for error messages. */
100
+ column: number;
101
+ }
102
+ /** Result of `findFontCallSites` — everything the transform needs. */
103
+ export interface FontAnalysis {
104
+ bindings: FontBinding[];
105
+ callSites: FontCallSite[];
106
+ /** Import nodes that should be removed (deduplicated). */
107
+ importNodesToRemove: Array<{
108
+ start: number;
109
+ end: number;
110
+ }>;
111
+ /** First dynamic call expression text, or `null`. */
112
+ dynamicCall: string | null;
113
+ /**
114
+ * Font calls found in nested scopes (functions, if-blocks, etc.).
115
+ * These are errors — font calls must be module-level.
116
+ */
117
+ nestedCalls: Array<{
118
+ name: string;
119
+ line: number;
120
+ column: number;
121
+ }>;
122
+ }
123
+ /**
124
+ * Parse a full source file and find all font imports and call sites.
125
+ *
126
+ * Returns `null` if the source has no font-related imports.
127
+ */
128
+ export declare function findFontCallSites(source: string): FontAnalysis | null;
129
+ export {};
38
130
  //# sourceMappingURL=ast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/fonts/ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAC;AA0HhE;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CA4DhF;AAiCD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA4CpF;AAID;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAiB/F"}
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/fonts/ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAC;AAIhE,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAiID;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CA4DhF;AAiCD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA4CpF;AAID;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAc/F;AAmDD;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAGtF;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAGpF;AA8GD,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC7B,4EAA4E;IAC5E,UAAU,EAAE,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,OAAO,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wEAAwE;IACxE,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,0DAA0D;IAC1D,mBAAmB,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,qDAAqD;IACrD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AA8CD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA+HrE"}
@@ -71,7 +71,7 @@ export declare function processLocalFont(config: LocalFontConfig, importerPath:
71
71
  *
72
72
  * Returns null if the call cannot be statically analyzed.
73
73
  *
74
- * Uses acorn AST parsing for robust handling of comments, trailing commas,
74
+ * Uses OXC (via vite.parseAst) AST parsing for robust handling of comments, trailing commas,
75
75
  * and multi-line configs.
76
76
  */
77
77
  export declare function extractLocalFontConfig(callSource: string): LocalFontConfig | null;
@@ -7,8 +7,12 @@
7
7
  * call sites to static `FontResult` literals so the runtime never has to
8
8
  * evaluate the font function.
9
9
  *
10
+ * Uses a single OXC (via vite.parseAst) parse of the source file (via `findFontCallSites`)
11
+ * and magic-string for precise source rewrites with source maps.
12
+ *
10
13
  * Design doc: 24-fonts.md
11
14
  */
15
+ import MagicString from 'magic-string';
12
16
  import type { GoogleFontConfig } from './types.js';
13
17
  import type { FontPipeline } from './pipeline.js';
14
18
  /**
@@ -56,9 +60,19 @@ export declare function parseGoogleFontFamilies(source: string): Map<string, str
56
60
  export declare function parseLocalFontImportName(source: string): string | null;
57
61
  /** Type for the Vite plugin's `this.error` callback. */
58
62
  type EmitError = (msg: string) => never;
63
+ /**
64
+ * Run the timber-fonts transform pass on a single source file.
65
+ *
66
+ * Parses the source once with OXC (via vite.parseAst), walks the AST to find font imports
67
+ * and call sites, then uses magic-string to rewrite call sites to static
68
+ * `FontResult` literals and strip the import declarations. Returns a
69
+ * source map alongside the transformed code.
70
+ *
71
+ * Returns `null` if the file does not import from any font virtual module.
72
+ */
59
73
  export declare function runFontsTransform(code: string, id: string, pipeline: FontPipeline, emitError: EmitError): {
60
74
  code: string;
61
- map: null;
75
+ map: ReturnType<MagicString['generateMap']>;
62
76
  } | null;
63
77
  export {};
64
78
  //# sourceMappingURL=transform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/fonts/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAQlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA+BlD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAM/E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB/D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB3E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKtE;AASD,wDAAwD;AACxD,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,KAAK,CAAC;AAyLxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CAqDpC"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/fonts/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAUlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAsBlD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAM/E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAE5F;AAOD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAU3E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKtE;AASD,wDAAwD;AACxD,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,KAAK,CAAC;AA4BxC;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAA;CAAE,GAAG,IAAI,CAsItE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,MAAM,CAAC;AA0BjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAc1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQ1D,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElG;;;;;;;;;GASG;AAEH,MAAM,WAAW,MAAM;CAAG;AAE1B;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAEvE;AAgGD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,YAAY,EAAE,CA+ShE;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,MAAM,CAAC;AAyBjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAc1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQ1D,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElG;;;;;;;;;GASG;AAEH,MAAM,WAAW,MAAM;CAAG;AAE1B;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAEvE;AAgGD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,YAAY,EAAE,CA4ThE;AAED,eAAe,MAAM,CAAC"}