@timber-js/app 0.2.0-alpha.101 → 0.2.0-alpha.103

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 (80) hide show
  1. package/dist/_chunks/{actions-BsfxK6yu.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-k32T6NL2.js → define-Btmz9B20.js} +3 -3
  6. package/dist/_chunks/{define-k32T6NL2.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-yx917rG0.js → navigation-root-2ypaZQDx.js} +2 -2
  20. package/dist/_chunks/{navigation-root-yx917rG0.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-DlsOX1YS.js → use-segment-params-07V1TIxL.js} +3 -3
  40. package/dist/_chunks/{use-segment-params-DlsOX1YS.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.js +7 -7
  54. package/dist/client/use-cookie.d.ts +4 -0
  55. package/dist/client/use-cookie.d.ts.map +1 -1
  56. package/dist/codec.js +1 -1
  57. package/dist/cookies/define-cookie.d.ts +5 -45
  58. package/dist/cookies/define-cookie.d.ts.map +1 -1
  59. package/dist/cookies/index.js +252 -1
  60. package/dist/cookies/index.js.map +1 -1
  61. package/dist/fonts/ast.d.ts.map +1 -1
  62. package/dist/index.js +89 -45
  63. package/dist/index.js.map +1 -1
  64. package/dist/routing/index.js +2 -2
  65. package/dist/search-params/index.js +3 -3
  66. package/dist/segment-params/index.js +1 -1
  67. package/dist/server/index.js +3 -3
  68. package/dist/server/internal.js +7 -7
  69. package/dist/server/request-context.d.ts.map +1 -1
  70. package/package.json +1 -1
  71. package/src/client/index.ts +0 -9
  72. package/src/client/use-cookie.ts +2 -2
  73. package/src/cookies/define-cookie.ts +100 -166
  74. package/src/fonts/ast.ts +64 -27
  75. package/src/server/request-context.ts +1 -8
  76. package/dist/_chunks/actions-BsfxK6yu.js.map +0 -1
  77. package/dist/_chunks/chunk-Cfpv9whK.js +0 -32
  78. package/dist/_chunks/define-cookie-BjpIt4UC.js +0 -194
  79. package/dist/_chunks/define-cookie-BjpIt4UC.js.map +0 -1
  80. package/dist/_chunks/merge-search-params-BphMdht_.js.map +0 -1
@@ -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 +1 @@
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"}
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;AAkFD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAgIrE"}
package/dist/index.js CHANGED
@@ -1,8 +1,7 @@
1
- import { i as __toCommonJS, n as __exportAll, r as __require, t as __esmMin } from "./_chunks/chunk-Cfpv9whK.js";
2
- import { n as setViteServer } from "./_chunks/warnings-Cg47l5sk.js";
3
- import { h as swallow } from "./_chunks/logger-0m8MsKdc.js";
4
- import { i as scanRoutes, n as collectInterceptionRewrites, r as generateRouteMap, t as collectLeafRoutes } from "./_chunks/walkers-Tg0Alwcg.js";
5
- import { t as formatSize } from "./_chunks/format-Bcn-Iv1x.js";
1
+ import { n as setViteServer } from "./_chunks/warnings-B30wpfaS.js";
2
+ import { h as swallow } from "./_chunks/logger-DDmK5skc.js";
3
+ import { i as scanRoutes, n as collectInterceptionRewrites, r as generateRouteMap, t as collectLeafRoutes } from "./_chunks/walkers-DQn5NNrf.js";
4
+ import { t as formatSize } from "./_chunks/format-CYBGxKtc.js";
6
5
  import { dirname, extname, join, normalize, resolve } from "node:path";
7
6
  import { createRequire } from "node:module";
8
7
  import react, { reactCompilerPreset } from "@vitejs/plugin-react";
@@ -15,6 +14,37 @@ import { createHash, randomUUID } from "node:crypto";
15
14
  import { parseAst } from "vite";
16
15
  import { performance as performance$1 } from "node:perf_hooks";
17
16
  import http from "node:http";
17
+ //#region \0rolldown/runtime.js
18
+ var __defProp = Object.defineProperty;
19
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
20
+ var __getOwnPropNames = Object.getOwnPropertyNames;
21
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
22
+ var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
23
+ var __exportAll = (all, no_symbols) => {
24
+ let target = {};
25
+ for (var name in all) __defProp(target, name, {
26
+ get: all[name],
27
+ enumerable: true
28
+ });
29
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
30
+ return target;
31
+ };
32
+ var __copyProps = (to, from, except, desc) => {
33
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
34
+ key = keys[i];
35
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
36
+ get: ((k) => from[k]).bind(null, key),
37
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
38
+ });
39
+ }
40
+ return to;
41
+ };
42
+ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
44
+ if (typeof require !== "undefined") return require.apply(this, arguments);
45
+ throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
46
+ });
47
+ //#endregion
18
48
  //#region src/plugins/content.ts
19
49
  var CONFIG_FILE_NAMES$1 = [
20
50
  "content-collections.ts",
@@ -3356,6 +3386,24 @@ var LOCAL_FONT_SOURCES = new Set([
3356
3386
  "@timber-js/app/fonts/local",
3357
3387
  "next/font/local"
3358
3388
  ]);
3389
+ function isImportDeclaration(node) {
3390
+ return node.type === "ImportDeclaration";
3391
+ }
3392
+ function isVariableDeclaration(node) {
3393
+ return node.type === "VariableDeclaration";
3394
+ }
3395
+ function isExpressionStatement(node) {
3396
+ return node.type === "ExpressionStatement";
3397
+ }
3398
+ function isExportNamedDeclaration(node) {
3399
+ return node.type === "ExportNamedDeclaration";
3400
+ }
3401
+ function isCallExpression(node) {
3402
+ return node.type === "CallExpression";
3403
+ }
3404
+ function isIdentifier(node) {
3405
+ return node.type === "Identifier";
3406
+ }
3359
3407
  /**
3360
3408
  * Parse a full source file and find all font imports and call sites.
3361
3409
  *
@@ -3371,7 +3419,7 @@ function findFontCallSites(source) {
3371
3419
  const bindings = [];
3372
3420
  const importNodesToRemove = [];
3373
3421
  for (const stmt of program.body) {
3374
- if (stmt.type !== "ImportDeclaration") continue;
3422
+ if (!isImportDeclaration(stmt)) continue;
3375
3423
  const importDecl = stmt;
3376
3424
  const specSource = importDecl.source.value;
3377
3425
  let provider = null;
@@ -3391,8 +3439,8 @@ function findFontCallSites(source) {
3391
3439
  importNode: importDecl
3392
3440
  });
3393
3441
  importNodesToRemove.push({
3394
- start: importDecl.start,
3395
- end: importDecl.end
3442
+ start: stmt.start,
3443
+ end: stmt.end
3396
3444
  });
3397
3445
  }
3398
3446
  if (bindings.length === 0) return null;
@@ -3400,39 +3448,36 @@ function findFontCallSites(source) {
3400
3448
  const callSites = [];
3401
3449
  let dynamicCall = null;
3402
3450
  for (const stmt of program.body) {
3403
- if (stmt.type === "VariableDeclaration") {
3404
- const varDecl = stmt;
3405
- for (const declarator of varDecl.declarations) {
3406
- if (!declarator.init || declarator.init.type !== "CallExpression") continue;
3407
- const call = declarator.init;
3408
- const site = matchCallExpression(call, bindingsByName, source);
3409
- if (!site) continue;
3410
- if (site === "dynamic") {
3411
- if (!dynamicCall) {
3412
- const calleeName = call.callee.name;
3413
- const argStart = call.arguments[0].start;
3414
- const argEnd = call.arguments[0].end;
3415
- dynamicCall = `${calleeName}(${source.slice(argStart, argEnd)})`;
3416
- }
3417
- continue;
3451
+ const effectiveStmt = isExportNamedDeclaration(stmt) && stmt.declaration ? stmt.declaration : stmt;
3452
+ if (isVariableDeclaration(effectiveStmt)) for (const declarator of effectiveStmt.declarations) {
3453
+ if (!declarator.init) continue;
3454
+ if (!isCallExpression(declarator.init)) continue;
3455
+ const call = declarator.init;
3456
+ const site = matchCallExpression(call, bindingsByName, source);
3457
+ if (!site) continue;
3458
+ if (site === "dynamic") {
3459
+ if (!dynamicCall && isIdentifier(call.callee)) {
3460
+ const argStart = call.arguments[0].start;
3461
+ const argEnd = call.arguments[0].end;
3462
+ dynamicCall = `${call.callee.name}(${source.slice(argStart, argEnd)})`;
3418
3463
  }
3419
- const assignedName = declarator.id.type === "Identifier" ? declarator.id.name : null;
3420
- const { line, column } = offsetToLineColumn(source, call.start);
3421
- callSites.push({
3422
- binding: site.binding,
3423
- assignedName,
3424
- configNode: site.configNode,
3425
- replaceStart: call.start,
3426
- replaceEnd: call.end,
3427
- line,
3428
- column
3429
- });
3464
+ continue;
3430
3465
  }
3466
+ const assignedName = isIdentifier(declarator.id) ? declarator.id.name : null;
3467
+ const { line, column } = offsetToLineColumn(source, call.start);
3468
+ callSites.push({
3469
+ binding: site.binding,
3470
+ assignedName,
3471
+ configNode: site.configNode,
3472
+ replaceStart: call.start,
3473
+ replaceEnd: call.end,
3474
+ line,
3475
+ column
3476
+ });
3431
3477
  }
3432
- if (stmt.type === "ExpressionStatement") {
3433
- const exprStmt = stmt;
3434
- if (exprStmt.expression.type === "CallExpression") {
3435
- const call = exprStmt.expression;
3478
+ if (isExpressionStatement(effectiveStmt)) {
3479
+ if (isCallExpression(effectiveStmt.expression)) {
3480
+ const call = effectiveStmt.expression;
3436
3481
  const site = matchCallExpression(call, bindingsByName, source);
3437
3482
  if (site && site !== "dynamic") {
3438
3483
  const { line, column } = offsetToLineColumn(source, call.start);
@@ -3440,16 +3485,15 @@ function findFontCallSites(source) {
3440
3485
  binding: site.binding,
3441
3486
  assignedName: null,
3442
3487
  configNode: site.configNode,
3443
- replaceStart: exprStmt.start,
3444
- replaceEnd: exprStmt.end,
3488
+ replaceStart: effectiveStmt.start,
3489
+ replaceEnd: effectiveStmt.end,
3445
3490
  line,
3446
3491
  column
3447
3492
  });
3448
- } else if (site === "dynamic" && !dynamicCall) {
3449
- const calleeName = call.callee.name;
3493
+ } else if (site === "dynamic" && !dynamicCall && isIdentifier(call.callee)) {
3450
3494
  const argStart = call.arguments[0].start;
3451
3495
  const argEnd = call.arguments[0].end;
3452
- dynamicCall = `${calleeName}(${source.slice(argStart, argEnd)})`;
3496
+ dynamicCall = `${call.callee.name}(${source.slice(argStart, argEnd)})`;
3453
3497
  }
3454
3498
  }
3455
3499
  }
@@ -3523,7 +3567,7 @@ function walkForNestedFontCalls(node, bindings, source, out, isNested) {
3523
3567
  * if the callee doesn't match any font binding.
3524
3568
  */
3525
3569
  function matchCallExpression(call, bindings, _source) {
3526
- if (call.callee.type !== "Identifier") return null;
3570
+ if (!isIdentifier(call.callee)) return null;
3527
3571
  const calleeName = call.callee.name;
3528
3572
  const binding = bindings.get(calleeName);
3529
3573
  if (!binding) return null;
@@ -7132,6 +7176,6 @@ function timber(config) {
7132
7176
  ];
7133
7177
  }
7134
7178
  //#endregion
7135
- export { timber as default, timber, defineConfig };
7179
+ export { timber as default, timber, defineConfig, __exportAll as t };
7136
7180
 
7137
7181
  //# sourceMappingURL=index.js.map