@timber-js/app 0.2.0-alpha.147 → 0.2.0-alpha.148

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/dist/_chunks/{actions-OIZ8siQu.js → actions-a0RczDnB.js} +8 -34
  2. package/dist/_chunks/{actions-OIZ8siQu.js.map → actions-a0RczDnB.js.map} +1 -1
  3. package/dist/_chunks/cache-api-Co-yI-gP.js +424 -0
  4. package/dist/_chunks/cache-api-Co-yI-gP.js.map +1 -0
  5. package/dist/_chunks/{metadata-routes-BjepjefT.js → canonicalize-P41GR6tY.js} +65 -2
  6. package/dist/_chunks/canonicalize-P41GR6tY.js.map +1 -0
  7. package/dist/_chunks/{cli-schema-sync-CQaxupHv.js → cli-schema-sync-DJDdyEae.js} +111 -260
  8. package/dist/_chunks/cli-schema-sync-DJDdyEae.js.map +1 -0
  9. package/dist/_chunks/cli-schema-sync-D_IhHEUW.js +2 -0
  10. package/dist/_chunks/{define-DMVhsipD.js → define-Bssfp6ot.js} +3 -33
  11. package/dist/_chunks/define-Bssfp6ot.js.map +1 -0
  12. package/dist/_chunks/{define-C3RvHQPK.js → define-CFmvb4Bt.js} +15 -7
  13. package/dist/_chunks/define-CFmvb4Bt.js.map +1 -0
  14. package/dist/_chunks/{href-validation-DyZIzfMJ.js → href-validation-FiA_rToW.js} +2 -1
  15. package/dist/_chunks/{href-validation-DyZIzfMJ.js.map → href-validation-FiA_rToW.js.map} +1 -1
  16. package/dist/_chunks/{tracing-M_zKubhk.js → logger-CM0clugc.js} +394 -107
  17. package/dist/_chunks/logger-CM0clugc.js.map +1 -0
  18. package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -1
  19. package/dist/_chunks/plugin-context-DurqFBuY.js +2 -0
  20. package/dist/_chunks/plugin-context-GfDWsdd2.js +268 -0
  21. package/dist/_chunks/plugin-context-GfDWsdd2.js.map +1 -0
  22. package/dist/_chunks/{resolve-schema-Dj8tQloi.js → resolve-schema-3iUvBV5T.js} +3 -30
  23. package/dist/_chunks/resolve-schema-3iUvBV5T.js.map +1 -0
  24. package/dist/_chunks/{schema-bridge-DK_89h8O.js → schema-bridge-BY3QLBL7.js} +35 -2
  25. package/dist/_chunks/schema-bridge-BY3QLBL7.js.map +1 -0
  26. package/dist/_chunks/tree-match-D2l830j2.js +102 -0
  27. package/dist/_chunks/tree-match-D2l830j2.js.map +1 -0
  28. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -1
  29. package/dist/_chunks/{walkers-Ck4Y45XN.js → walkers-DvWDj453.js} +107 -82
  30. package/dist/_chunks/walkers-DvWDj453.js.map +1 -0
  31. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -1
  32. package/dist/adapters/cloudflare-kv-cache.js +36 -14
  33. package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
  34. package/dist/adapters/compress-module.d.ts +5 -4
  35. package/dist/adapters/compress-module.d.ts.map +1 -1
  36. package/dist/adapters/nitro.d.ts +1 -3
  37. package/dist/adapters/nitro.d.ts.map +1 -1
  38. package/dist/adapters/nitro.js +14 -134
  39. package/dist/adapters/nitro.js.map +1 -1
  40. package/dist/cache/cache-api.d.ts.map +1 -1
  41. package/dist/cache/index.d.ts +3 -1
  42. package/dist/cache/index.d.ts.map +1 -1
  43. package/dist/cache/index.js +20 -235
  44. package/dist/cache/index.js.map +1 -1
  45. package/dist/cache/invalidation-epoch.d.ts +43 -0
  46. package/dist/cache/invalidation-epoch.d.ts.map +1 -0
  47. package/dist/cache/redis-handler.d.ts +13 -0
  48. package/dist/cache/redis-handler.d.ts.map +1 -1
  49. package/dist/cache/timber-cache.d.ts +17 -9
  50. package/dist/cache/timber-cache.d.ts.map +1 -1
  51. package/dist/cli-schema-sync.d.ts +21 -1
  52. package/dist/cli-schema-sync.d.ts.map +1 -1
  53. package/dist/cli.d.ts +12 -0
  54. package/dist/cli.d.ts.map +1 -1
  55. package/dist/cli.js +26 -31
  56. package/dist/cli.js.map +1 -1
  57. package/dist/client/browser-entry/hmr.d.ts.map +1 -1
  58. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  59. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  60. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  61. package/dist/client/history.d.ts +10 -17
  62. package/dist/client/history.d.ts.map +1 -1
  63. package/dist/client/index.js +1 -1
  64. package/dist/client/index.js.map +1 -1
  65. package/dist/client/internal.js +30 -33
  66. package/dist/client/internal.js.map +1 -1
  67. package/dist/client/navigation-api.d.ts +9 -2
  68. package/dist/client/navigation-api.d.ts.map +1 -1
  69. package/dist/client/navigation-context.d.ts +0 -11
  70. package/dist/client/navigation-context.d.ts.map +1 -1
  71. package/dist/client/navigation-root.d.ts +0 -5
  72. package/dist/client/navigation-root.d.ts.map +1 -1
  73. package/dist/client/router.d.ts.map +1 -1
  74. package/dist/client/rsc-fetch.d.ts.map +1 -1
  75. package/dist/client/use-search-params.d.ts +10 -5
  76. package/dist/client/use-search-params.d.ts.map +1 -1
  77. package/dist/codec.js +1 -1
  78. package/dist/config-validation.d.ts.map +1 -1
  79. package/dist/cookies/define-cookie.d.ts.map +1 -1
  80. package/dist/cookies/index.js +2 -4
  81. package/dist/cookies/index.js.map +1 -1
  82. package/dist/dev-tools/dev-page-shell.d.ts +1 -0
  83. package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
  84. package/dist/dev-tools/hydration-overlay.d.ts +11 -0
  85. package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
  86. package/dist/dev-tools/index.d.ts +1 -2
  87. package/dist/dev-tools/index.d.ts.map +1 -1
  88. package/dist/fonts/ast-walk.d.ts +68 -0
  89. package/dist/fonts/ast-walk.d.ts.map +1 -0
  90. package/dist/fonts/ast.d.ts +23 -11
  91. package/dist/fonts/ast.d.ts.map +1 -1
  92. package/dist/fonts/bundle.d.ts +3 -1
  93. package/dist/fonts/bundle.d.ts.map +1 -1
  94. package/dist/fonts/dev-middleware.d.ts +1 -1
  95. package/dist/fonts/dev-middleware.d.ts.map +1 -1
  96. package/dist/fonts/fallbacks.d.ts +0 -7
  97. package/dist/fonts/fallbacks.d.ts.map +1 -1
  98. package/dist/fonts/google.d.ts +4 -2
  99. package/dist/fonts/google.d.ts.map +1 -1
  100. package/dist/fonts/local.d.ts +3 -3
  101. package/dist/fonts/local.d.ts.map +1 -1
  102. package/dist/fonts/paths.d.ts +43 -0
  103. package/dist/fonts/paths.d.ts.map +1 -0
  104. package/dist/fonts/pipeline.d.ts +7 -21
  105. package/dist/fonts/pipeline.d.ts.map +1 -1
  106. package/dist/fonts/transform.d.ts.map +1 -1
  107. package/dist/fonts/virtual-modules.d.ts +1 -18
  108. package/dist/fonts/virtual-modules.d.ts.map +1 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +609 -406
  111. package/dist/index.js.map +1 -1
  112. package/dist/params/index.js +1 -1
  113. package/dist/params/resolve-schema.d.ts.map +1 -1
  114. package/dist/plugin-context.d.ts +28 -5
  115. package/dist/plugin-context.d.ts.map +1 -1
  116. package/dist/plugins/cache.d.ts +13 -5
  117. package/dist/plugins/cache.d.ts.map +1 -1
  118. package/dist/plugins/dev-server.d.ts.map +1 -1
  119. package/dist/plugins/fonts.d.ts +1 -2
  120. package/dist/plugins/fonts.d.ts.map +1 -1
  121. package/dist/plugins/routing.d.ts.map +1 -1
  122. package/dist/routing/codegen.d.ts.map +1 -1
  123. package/dist/routing/convention-lint.d.ts.map +1 -1
  124. package/dist/routing/file-cache.d.ts +8 -0
  125. package/dist/routing/file-cache.d.ts.map +1 -0
  126. package/dist/routing/index.js +2 -2
  127. package/dist/routing/interception.d.ts +0 -5
  128. package/dist/routing/interception.d.ts.map +1 -1
  129. package/dist/routing/manifest-codegen.d.ts +32 -0
  130. package/dist/routing/manifest-codegen.d.ts.map +1 -0
  131. package/dist/routing/scanner.d.ts.map +1 -1
  132. package/dist/schema-bridge.d.ts +15 -0
  133. package/dist/schema-bridge.d.ts.map +1 -1
  134. package/dist/search-params/define.d.ts.map +1 -1
  135. package/dist/search-params/index.js +7 -3
  136. package/dist/search-params/index.js.map +1 -1
  137. package/dist/search-params/wrappers.d.ts.map +1 -1
  138. package/dist/segment-params/define.d.ts.map +1 -1
  139. package/dist/segment-params/index.js +1 -1
  140. package/dist/server/access-gate.d.ts.map +1 -1
  141. package/dist/server/actions.d.ts +0 -14
  142. package/dist/server/actions.d.ts.map +1 -1
  143. package/dist/server/build-manifest.d.ts +0 -29
  144. package/dist/server/build-manifest.d.ts.map +1 -1
  145. package/dist/server/canonicalize.d.ts +10 -0
  146. package/dist/server/canonicalize.d.ts.map +1 -1
  147. package/dist/server/deny-renderer.d.ts +1 -1
  148. package/dist/server/deny-renderer.d.ts.map +1 -1
  149. package/dist/server/html-injector-core.d.ts +8 -0
  150. package/dist/server/html-injector-core.d.ts.map +1 -1
  151. package/dist/server/html-injectors.d.ts.map +1 -1
  152. package/dist/server/index.js +2 -2
  153. package/dist/server/internal.d.ts +1 -5
  154. package/dist/server/internal.d.ts.map +1 -1
  155. package/dist/server/internal.js +12 -171
  156. package/dist/server/internal.js.map +1 -1
  157. package/dist/server/node-stream-transforms.d.ts +0 -11
  158. package/dist/server/node-stream-transforms.d.ts.map +1 -1
  159. package/dist/server/render-utils.d.ts +25 -0
  160. package/dist/server/render-utils.d.ts.map +1 -0
  161. package/dist/server/route-element-builder.d.ts +11 -25
  162. package/dist/server/route-element-builder.d.ts.map +1 -1
  163. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  164. package/dist/server/rsc-entry/helpers.d.ts +2 -18
  165. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  166. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  167. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  168. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  169. package/dist/server/ssr-render.d.ts.map +1 -1
  170. package/dist/shared/href-validation.d.ts.map +1 -1
  171. package/dist/shims/image.d.ts +15 -15
  172. package/package.json +2 -2
  173. package/src/adapters/cloudflare-kv-cache.ts +56 -19
  174. package/src/adapters/compress-module.ts +27 -118
  175. package/src/adapters/nitro.ts +3 -41
  176. package/src/adapters/raw-imports.d.ts +5 -0
  177. package/src/cache/cache-api.ts +9 -1
  178. package/src/cache/index.ts +5 -2
  179. package/src/cache/invalidation-epoch.ts +93 -0
  180. package/src/cache/redis-handler.ts +33 -2
  181. package/src/cache/timber-cache.ts +109 -53
  182. package/src/cli-schema-sync.ts +123 -30
  183. package/src/cli.ts +33 -37
  184. package/src/client/browser-entry/hmr.ts +0 -11
  185. package/src/client/browser-entry/hydrate.ts +39 -5
  186. package/src/client/browser-entry/post-hydration.ts +6 -15
  187. package/src/client/browser-entry/router-init.ts +98 -3
  188. package/src/client/history.ts +10 -24
  189. package/src/client/navigation-api.ts +14 -9
  190. package/src/client/navigation-context.ts +1 -21
  191. package/src/client/navigation-root.tsx +0 -8
  192. package/src/client/router.ts +18 -8
  193. package/src/client/rsc-fetch.ts +7 -2
  194. package/src/client/use-search-params.ts +10 -5
  195. package/src/config-validation.ts +33 -25
  196. package/src/cookies/define-cookie.ts +2 -18
  197. package/src/dev-tools/dev-page-shell.ts +6 -2
  198. package/src/dev-tools/hydration-overlay.ts +158 -0
  199. package/src/dev-tools/index.ts +3 -16
  200. package/src/fonts/ast-walk.ts +235 -0
  201. package/src/fonts/ast.ts +91 -249
  202. package/src/fonts/bundle.ts +16 -9
  203. package/src/fonts/dev-middleware.ts +16 -5
  204. package/src/fonts/fallbacks.ts +0 -23
  205. package/src/fonts/google.ts +7 -3
  206. package/src/fonts/local.ts +7 -6
  207. package/src/fonts/paths.ts +58 -0
  208. package/src/fonts/pipeline.ts +27 -48
  209. package/src/fonts/transform.ts +27 -0
  210. package/src/fonts/virtual-modules.ts +1 -57
  211. package/src/index.ts +5 -11
  212. package/src/params/resolve-schema.ts +2 -34
  213. package/src/plugin-context.ts +95 -17
  214. package/src/plugins/cache.ts +64 -17
  215. package/src/plugins/dev-server.ts +61 -9
  216. package/src/plugins/fonts.ts +21 -6
  217. package/src/plugins/routing.ts +5 -348
  218. package/src/routing/codegen.ts +3 -2
  219. package/src/routing/convention-lint.ts +4 -3
  220. package/src/routing/file-cache.ts +23 -0
  221. package/src/routing/interception.ts +2 -21
  222. package/src/routing/manifest-codegen.ts +290 -0
  223. package/src/routing/scanner.ts +5 -17
  224. package/src/routing/schema-validation.ts +2 -2
  225. package/src/schema-bridge.ts +63 -2
  226. package/src/search-params/define.ts +34 -2
  227. package/src/search-params/wrappers.ts +21 -3
  228. package/src/segment-params/define.ts +2 -62
  229. package/src/server/access-gate.tsx +8 -0
  230. package/src/server/actions.ts +8 -31
  231. package/src/server/build-manifest.ts +0 -56
  232. package/src/server/canonicalize.ts +6 -3
  233. package/src/server/deny-renderer.ts +6 -0
  234. package/src/server/html-injector-core.ts +19 -0
  235. package/src/server/html-injectors.ts +14 -4
  236. package/src/server/internal.ts +1 -18
  237. package/src/server/node-stream-transforms.ts +5 -72
  238. package/src/server/render-utils.ts +31 -0
  239. package/src/server/route-element-builder.ts +77 -47
  240. package/src/server/rsc-entry/error-renderer.ts +1 -0
  241. package/src/server/rsc-entry/helpers.ts +6 -34
  242. package/src/server/rsc-entry/index.ts +11 -0
  243. package/src/server/rsc-entry/render-route.ts +7 -9
  244. package/src/server/rsc-entry/rsc-payload.ts +2 -1
  245. package/src/server/rsc-entry/ssr-renderer.ts +2 -2
  246. package/src/server/ssr-render.ts +1 -11
  247. package/src/shared/href-validation.ts +8 -0
  248. package/dist/_chunks/cli-schema-sync-CBiMEtqa.js +0 -2
  249. package/dist/_chunks/cli-schema-sync-CQaxupHv.js.map +0 -1
  250. package/dist/_chunks/define-C3RvHQPK.js.map +0 -1
  251. package/dist/_chunks/define-DMVhsipD.js.map +0 -1
  252. package/dist/_chunks/handler-store-BVDgyTh7.js +0 -78
  253. package/dist/_chunks/handler-store-BVDgyTh7.js.map +0 -1
  254. package/dist/_chunks/logger-Dt-jQaBO.js +0 -291
  255. package/dist/_chunks/logger-Dt-jQaBO.js.map +0 -1
  256. package/dist/_chunks/metadata-routes-BjepjefT.js.map +0 -1
  257. package/dist/_chunks/resolve-schema-Dj8tQloi.js.map +0 -1
  258. package/dist/_chunks/schema-bridge-DK_89h8O.js.map +0 -1
  259. package/dist/_chunks/tracing-M_zKubhk.js.map +0 -1
  260. package/dist/_chunks/walkers-Ck4Y45XN.js.map +0 -1
  261. package/dist/_chunks/warnings-CNPXaypM.js +0 -125
  262. package/dist/_chunks/warnings-CNPXaypM.js.map +0 -1
  263. package/dist/client/link-pending-store.d.ts +0 -65
  264. package/dist/client/link-pending-store.d.ts.map +0 -1
  265. package/dist/client/nav-link-store.d.ts +0 -27
  266. package/dist/client/nav-link-store.d.ts.map +0 -1
  267. package/dist/dev-tools/warnings.d.ts +0 -109
  268. package/dist/dev-tools/warnings.d.ts.map +0 -1
  269. package/dist/server/flush.d.ts +0 -74
  270. package/dist/server/flush.d.ts.map +0 -1
  271. package/src/client/link-pending-store.ts +0 -116
  272. package/src/client/nav-link-store.ts +0 -37
  273. package/src/dev-tools/warnings.ts +0 -238
  274. package/src/server/flush.ts +0 -183
@@ -1 +1 @@
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
+ {"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';\nimport { resolveCodecOrSchema } 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 {\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 return resolveCodecOrSchema('codec', codecOrSchema, 'search') as CookieCodec<T>;\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":";;;;;;;;;;;;;;;;AAsCA,IAAM,4BAAY,IAAI,IAA2B;;AAGjD,SAAgB,eAAe,MAAkC;CAC/D,IAAI,OAAO,aAAa,aAAa,OAAO,KAAA;CAC5C,MAAM,QAAQ,SAAS,OAAO,MAC5B,IAAI,OAAO,gBAAgB,KAAK,QAAQ,uBAAuB,MAAM,IAAI,kBAAkB,CAC7F;CACA,OAAO,QAAQ,mBAAmB,MAAM,EAAE,IAAI,KAAA;AAChD;;AAGA,SAAgB,iBAAiB,SAAuC;CACtE,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,QAAkB,CAAC;CACzB,MAAM,KAAK,QAAQ,QAAQ,QAAQ,KAAK;CACxC,IAAI,QAAQ,QAAQ,MAAM,KAAK,UAAU,QAAQ,QAAQ;CACzD,IAAI,QAAQ,WAAW,KAAA,GAAW,MAAM,KAAK,WAAW,QAAQ,QAAQ;CACxE,IAAI,QAAQ,SAAS,MAAM,KAAK,WAAW,QAAQ,QAAQ,YAAY,GAAG;CAC1E,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,KAAK,YAAY,SAAS,OAAO,CAAC,EAAE,YAAY,IAAI,SAAS,MAAM,CAAC,GAAG;CAC7E,IAAI,QAAQ,QAAQ,MAAM,KAAK,QAAQ;CACvC,OAAO,OAAO,MAAM,KAAK,IAAI;AAC/B;;AAGA,SAAS,OAAO,MAAoB;CAClC,MAAM,OAAO,UAAU,IAAI,IAAI;CAC/B,IAAI,MACF,KAAK,MAAM,MAAM,MAAM,GAAG;AAE9B;;;;;;;;AASA,SAAgB,mBAAmB,MAAoB;CACrD,OAAO,IAAI;AACb;;;;;;;;;;;;AAeA,SAAgB,UACd,MACA,gBACgF;CAChF,MAAM,aAAa,aAAqC;EACtD,IAAI,OAAO,UAAU,IAAI,IAAI;EAC7B,IAAI,CAAC,MAAM;GACT,uBAAO,IAAI,IAAI;GACf,UAAU,IAAI,MAAM,IAAI;EAC1B;EACA,KAAK,IAAI,QAAQ;EACjB,aAAa;GACX,KAAM,OAAO,QAAQ;GACrB,IAAI,KAAM,SAAS,GAAG,UAAU,OAAO,IAAI;EAC7C;CACF;CAEA,MAAM,oBAAwC,eAAe,IAAI;CACjE,MAAM,0BAA8C,WAAW,GAAG,QAAQ,IAAI,IAAI;CAElF,MAAM,QAAQ,qBAAqB,WAAW,aAAa,iBAAiB;CAM5E,sBAAsB,IAAI;CAE1B,MAAM,aAA2B,UAAkB,YAAkC;EACnF,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,MACR,sBAAsB,KAAK,UAAU,IAAI,EAAE,iCAAiC,OAAO,SAAS,oJAG9F;EAEF,MAAM,SAAS;GAAE,GAAG;GAAgB,GAAG;EAAQ;EAK/C,SAAS,SAAS,GAAG,KAAK,GAAG,mBAAmB,QAAQ,IAAI,iBAAiB,MAAM;EACnF,OAAO,IAAI;CACb;CAEA,MAAM,qBAA2B;EAC/B,MAAM,OAAO,gBAAgB,QAAQ;EACrC,MAAM,SAAS,gBAAgB;EAC/B,IAAI,YAAY,GAAG,KAAK,4DAA4D;EACpF,IAAI,QAAQ,aAAa,YAAY;EACrC,SAAS,SAAS;EAClB,OAAO,IAAI;CACb;CAEA,OAAO;EAAC;EAAO;EAAW;CAAY;AACxC;;;;;;;;;;;AC5CA,SAAS,wBAAgE;CACvE,IAAI;EACF,OAAO,aAAa;CACtB,SAAS,GAAG;EAEV,IAAI,aAAa,SAAS,EAAE,QAAQ,SAAS,8BAA8B,GACzE,MAAM;EAGR,OAAO;CACT;AACF;;AAKA,SAAS,gBAAgB,MAAc,OAAe,SAAqC;CACzF,MAAM,QAAkB,CAAC,GAAG,KAAK,GAAG,mBAAmB,KAAK,GAAG;CAC/D,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,KAAK,QAAQ,MAAM;CACzB,IAAI,SAAS,QAAQ,MAAM,KAAK,UAAU,QAAQ,QAAQ;CAC1D,IAAI,SAAS,WAAW,KAAA,GAAW,MAAM,KAAK,WAAW,QAAQ,QAAQ;CACzE,IAAI,SAAS,SAAS,MAAM,KAAK,WAAW,QAAQ,QAAQ,YAAY,GAAG;CAC3E,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,KAAK,YAAY,SAAS,OAAO,CAAC,EAAE,YAAY,IAAI,SAAS,MAAM,CAAC,GAAG;CAC7E,IAAI,SAAS,QAAQ,MAAM,KAAK,QAAQ;CACxC,SAAS,SAAS,MAAM,KAAK,IAAI;CACjC,mBAAmB,IAAI;AACzB;;AAGA,SAAS,mBAAmB,MAAc,SAAqC;CAC7E,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,SAAS;CACxB,IAAI,YAAY,GAAG,KAAK,4DAA4D;CACpF,IAAI,QAAQ,aAAa,YAAY;CACrC,SAAS,SAAS;CAClB,mBAAmB,IAAI;AACzB;AAIA,SAAS,aAAgB,eAAqE;CAC5F,OAAO,qBAAqB,SAAS,eAAe,QAAQ;AAC9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,SAAgB,aACd,MACA,SAC8E;CAC9E,MAAM,EAAE,OAAO,eAAe,GAAG,eAAe;CAChD,MAAM,QAAQ,aAAa,aAAa;CACxC,MAAM,kBAAiC,EAAE,GAAG,WAAW;CACvD,MAAM,aAAa,QAAQ,aAAa;CAExC,SAAS,gBAAqC;EAC5C,OAAO;GACL,MAAM,gBAAgB;GACtB,QAAQ,gBAAgB;GACxB,QAAQ,gBAAgB;GACxB,SAAS,gBAAgB;GACzB,UAAU,gBAAgB;GAC1B,QAAQ,gBAAgB;EAC1B;CACF;CAEA,MAAM,OAAsC;EAC1C;EACA,SAAS;EACT;EAEA,MAAS;GACP,MAAM,YAAY,sBAAsB;GACxC,IAAI,WACF,OAAO,MAAM,MAAM,UAAU,IAAI,IAAI,CAAC;GAGxC,IAAI,YACF,MAAM,IAAI,MACR,0BAA0B,KAAK,6HAEjC;GAEF,MAAM,MAAM,eAAe,IAAI;GAC/B,OAAO,MAAM,MAAM,GAAG;EACxB;EAEA,IAAI,OAAgB;GAClB,MAAM,YAAY,sBAAsB;GACxC,IAAI,WAAW;IACb,MAAM,aAAa,MAAM,UAAU,KAAK;IACxC,IAAI,eAAe,MACjB,UAAU,OAAO,MAAM;KACrB,MAAM,gBAAgB;KACtB,QAAQ,gBAAgB;IAC1B,CAAC;SAED,UAAU,IAAI,MAAM,YAAY,eAAe;IAEjD;GACF;GAEA,IAAI,YACF,MAAM,IAAI,MACR,0BAA0B,KAAK,6HAEjC;GAEF,MAAM,aAAa,MAAM,UAAU,KAAK;GACxC,IAAI,eAAe,MACjB,mBAAmB,MAAM,cAAc,CAAC;QAExC,gBAAgB,MAAM,YAAY,cAAc,CAAC;EAErD;EAEA,SAAe;GACb,MAAM,YAAY,sBAAsB;GACxC,IAAI,WAAW;IACb,UAAU,OAAO,MAAM;KACrB,MAAM,gBAAgB;KACtB,QAAQ,gBAAgB;IAC1B,CAAC;IACD;GACF;GAEA,IAAI,YACF,MAAM,IAAI,MACR,0BAA0B,KAAK,gIAEjC;GAEF,mBAAmB,MAAM,cAAc,CAAC;EAC1C;CACF;CAEA,IAAI,YACF,OAAO;CAyBT,OAAO;EApBL,GAAG;EAEH,YAAiD;GAE/C,MAAM,CAAC,KAAK,QAAQ,aAAa,UAAa,MAD3B,cACiC,CAAU;GAC9D,MAAM,SAAS,MAAM,MAAM,GAAG;GAE9B,MAAM,YAAY,UAAmB;IACnC,MAAM,aAAa,MAAM,UAAU,KAAK;IACxC,IAAI,eAAe,MACjB,UAAU;SAEV,OAAO,UAAU;GAErB;GAEA,OAAO;IAAC;IAAQ;IAAU;GAAS;EACrC;CAGK;AACT;;;;;;;;;;;;;;;;;;;;;;;AC5OA,SAAgB,gBAAmB,cAA4B;CAM7D,MAAM,qBAAwB;EAC5B,IAAI,iBAAiB,KAAA,KAAa,iBAAiB,MACjD,OAAO;EAIT,OAAO,gBAAgB,YAAY;CACrC;CAEA,OAAO;EACL,MAAM,OAAyC;GAC7C,IAAI,UAAU,KAAA,KAAa,UAAU,IACnC,OAAO,aAAa;GAItB,MAAM,MAAM,MAAM,QAAQ,KAAK,IAAI,MAAM,MAAM,SAAS,KAAK;GAC7D,IAAI,QAAQ,KAAA,KAAa,QAAQ,IAC/B,OAAO,aAAa;GAEtB,IAAI;IACF,OAAO,KAAK,MAAM,GAAG;GACvB,QAAQ;IACN,OAAO,aAAa;GACtB;EACF;EAEA,UAAU,OAAyB;GACjC,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;GAET,OAAO,KAAK,UAAU,KAAK;EAC7B;CACF;AACF"}
@@ -36,6 +36,7 @@ export declare function extractHmrOptions(config: {
36
36
  protocol?: string;
37
37
  host?: string;
38
38
  port?: number;
39
+ clientPort?: number;
39
40
  path?: string;
40
41
  } | boolean;
41
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dev-page-shell.d.ts","sourceRoot":"","sources":["../../src/dev-tools/dev-page-shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAA;KAAE,CAAC;IAChG,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,kBAAkB,GAAG,SAAS,CAkBjC;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAuBzE;AAID,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CA0BpE"}
1
+ {"version":3,"file":"dev-page-shell.d.ts","sourceRoot":"","sources":["../../src/dev-tools/dev-page-shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,MAAM,CAAC,EAAE;QACP,GAAG,CAAC,EACA;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,GACvF,OAAO,CAAC;KACb,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,kBAAkB,GAAG,SAAS,CAkBjC;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAuBzE;AAID,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CA0BpE"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Hydration mismatch diff overlay — dev-only.
3
+ *
4
+ * Parses React 19's structured diff from hydration error messages and
5
+ * renders a color-coded + Client / - Server diff in a dismissible overlay.
6
+ *
7
+ * See design/21-dev-server.md §"Error Overlay"
8
+ */
9
+ export declare function isHydrationError(error: unknown): boolean;
10
+ export declare function showHydrationError(error: unknown): void;
11
+ //# sourceMappingURL=hydration-overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydration-overlay.d.ts","sourceRoot":"","sources":["../../src/dev-tools/hydration-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKxD;AA6HD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAOvD"}
@@ -8,7 +8,6 @@
8
8
  * - 404-page: self-contained HTML 404 page
9
9
  * - terminal: boxed terminal error output
10
10
  * - logger: structured request tree logger
11
- * - warnings: dev-mode footgun warnings
12
11
  * - browser-logs: forward browser console to server
13
12
  * - logs: forward server console to browser
14
13
  * - holding-server: startup holding server
@@ -24,9 +23,9 @@ export { extractHmrOptions, renderDevPageShell, buildReloadScript, type DevError
24
23
  export { generateDev404Page, collectRoutes, findSimilarRoutes } from './404-page.js';
25
24
  export { formatTerminalError as formatTerminalErrorDirect } from './terminal.js';
26
25
  export { formatSpanTree, formatSpanSummary, formatJson, resolveLogMode, type DevLogMode, type DevLoggerConfig, } from './logger.js';
27
- export { warnSuspenseWrappingChildren, warnDenyInSuspense, warnRedirectInSuspense, warnRedirectInAccess, warnStaticRequestApi, warnSlowSlotWithoutSuspense, setViteServer, WarningId, type DevWarningConfig, _resetWarnings, _getEmitted, } from './warnings.js';
28
26
  export { timberDevBrowserLogs, type BrowserLogLevel, type DevBrowserLogsConfig, } from './browser-logs.js';
29
27
  export { timberDevLogs } from './logs.js';
30
28
  export { createHoldingServer, type HoldingServer } from './holding-server.js';
31
29
  export { instrumentDevFetch, DevSpanProcessor, type DevFetchCleanup } from './instrumentation.js';
30
+ export { isHydrationError, showHydrationError } from './hydration-overlay.js';
32
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev-tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,SAAS,EACd,KAAK,eAAe,GACrB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,qBAAqB,GAC3B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGrF,OAAO,EAAE,mBAAmB,IAAI,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAGjF,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,EAC3B,aAAa,EACb,SAAS,EACT,KAAK,gBAAgB,EACrB,cAAc,EACd,WAAW,GACZ,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG9E,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev-tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,SAAS,EACd,KAAK,eAAe,GACrB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,qBAAqB,GAC3B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGrF,OAAO,EAAE,mBAAmB,IAAI,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAGjF,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG9E,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGlG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Generic AST node types and recursive walkers for font static analysis.
3
+ *
4
+ * `ast.ts` owns parsing, config extraction, and call-site discovery; this
5
+ * module owns the recursive walks that police where font bindings may be
6
+ * used (dynamic configs, nested scopes, unconsumed references). Split out
7
+ * to keep `ast.ts` under the 500-code-line limit (design/18-build-system.md).
8
+ *
9
+ * Design doc: 24-fonts.md §"Step 1: Static Analysis"
10
+ */
11
+ export interface AstNode {
12
+ type: string;
13
+ [key: string]: unknown;
14
+ }
15
+ export interface IdentifierNode extends AstNode {
16
+ type: 'Identifier';
17
+ name: string;
18
+ }
19
+ export interface PositionedNode extends AstNode {
20
+ start: number;
21
+ end: number;
22
+ }
23
+ /** A flagged reference/usage for build-error reporting. */
24
+ export interface FlaggedUsage {
25
+ name: string;
26
+ line: number;
27
+ column: number;
28
+ }
29
+ /** Convert a 0-based byte offset into a 1-based line and 0-based column. */
30
+ export declare function offsetToLineColumn(source: string, offset: number): {
31
+ line: number;
32
+ column: number;
33
+ };
34
+ /**
35
+ * Invoke `visit` on every direct child AST node of `node` (array elements
36
+ * and object-valued properties with a `type` field).
37
+ */
38
+ export declare function walkChildNodes(node: AstNode, visit: (child: AstNode) => void): void;
39
+ /**
40
+ * Recursively walk the AST looking for CallExpression nodes where
41
+ * the callee is one of the imported font names and the first argument
42
+ * is not an ObjectExpression (i.e. it's dynamic).
43
+ */
44
+ export declare function walkForDynamicCalls(node: AstNode, names: ReadonlySet<string>, source: string): string | null;
45
+ /**
46
+ * Recursively walk an AST node looking for font CallExpressions in nested
47
+ * scopes (function bodies, if-blocks, loops, etc.). Font calls must be
48
+ * module-level; nested calls are collected as errors.
49
+ *
50
+ * `isNested` tracks whether we've descended past the top-level statement.
51
+ * Top-level VariableDeclarations and ExpressionStatements are already
52
+ * handled by the main loop in `findFontCallSites`, so we only flag calls
53
+ * found deeper.
54
+ */
55
+ export declare function walkForNestedFontCalls(node: AstNode, bindingNames: ReadonlyMap<string, unknown>, source: string, out: FlaggedUsage[], isNested: boolean): void;
56
+ /**
57
+ * Recursively walk an AST node looking for references to font bindings
58
+ * that were not consumed by a recognized call site.
59
+ *
60
+ * Skips:
61
+ * - recognized CallExpressions (the transform rewrites them wholesale)
62
+ * - TS type-position nodes (erased at runtime)
63
+ * - non-computed member properties (`obj.Inter` doesn't reference the binding)
64
+ * - non-computed object keys (`{ Inter: 1 }` doesn't reference the binding)
65
+ * - export aliases (`export { inter as Inter }` — only `local` is a reference)
66
+ */
67
+ export declare function walkForUnconsumedReferences(node: AstNode, bindingNames: ReadonlyMap<string, unknown>, consumedCallStarts: ReadonlySet<number>, source: string, out: FlaggedUsage[]): void;
68
+ //# sourceMappingURL=ast-walk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-walk.d.ts","sourceRoot":"","sources":["../../src/fonts/ast-walk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAe,SAAQ,OAAO;IAC7C,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAe,SAAQ,OAAO;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2DAA2D;AAC3D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAUlC;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAcnF;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAuBf;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,OAAO,EACb,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1C,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,YAAY,EAAE,EACnB,QAAQ,EAAE,OAAO,GAChB,IAAI,CAoBN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,OAAO,EACb,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1C,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,EACvC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,YAAY,EAAE,GAClB,IAAI,CA8CN"}
@@ -17,10 +17,8 @@
17
17
  */
18
18
  import type { GoogleFontConfig } from './types.js';
19
19
  import type { LocalFontConfig } from './types.js';
20
- interface AstNode {
21
- type: string;
22
- [key: string]: unknown;
23
- }
20
+ import type { AstNode, FlaggedUsage } from './ast-walk.js';
21
+ export type { FlaggedUsage } from './ast-walk.js';
24
22
  /**
25
23
  * Extract a GoogleFontConfig from the source text of a font function call's
26
24
  * object argument.
@@ -103,7 +101,12 @@ export interface FontCallSite {
103
101
  export interface FontAnalysis {
104
102
  bindings: FontBinding[];
105
103
  callSites: FontCallSite[];
106
- /** Import nodes that should be removed (deduplicated). */
104
+ /**
105
+ * Import nodes that should be removed (deduplicated). Only imports that
106
+ * produced at least one font binding are listed — removing an import
107
+ * whose bindings the transform doesn't rewrite (e.g. a namespace
108
+ * import) would leave dangling references behind.
109
+ */
107
110
  importNodesToRemove: Array<{
108
111
  start: number;
109
112
  end: number;
@@ -114,11 +117,21 @@ export interface FontAnalysis {
114
117
  * Font calls found in nested scopes (functions, if-blocks, etc.).
115
118
  * These are errors — font calls must be module-level.
116
119
  */
117
- nestedCalls: Array<{
118
- name: string;
119
- line: number;
120
- column: number;
121
- }>;
120
+ nestedCalls: FlaggedUsage[];
121
+ /**
122
+ * Namespace imports of font modules (`import * as fonts from ...`).
123
+ * These are errors — the transform cannot rewrite `fonts.Inter(...)`
124
+ * member calls, so the fonts would silently never load.
125
+ */
126
+ namespaceImports: FlaggedUsage[];
127
+ /**
128
+ * References to font bindings that were not consumed by a recognized
129
+ * call site (`export default Inter({...})`, object-literal nesting,
130
+ * member access on the call result, aliasing, re-exports). These are
131
+ * errors — the import is removed, so any leftover reference would be a
132
+ * silent runtime ReferenceError.
133
+ */
134
+ unsupportedUsages: FlaggedUsage[];
122
135
  }
123
136
  /**
124
137
  * Parse a full source file and find all font imports and call sites.
@@ -126,5 +139,4 @@ export interface FontAnalysis {
126
139
  * Returns `null` if the source has no font-related imports.
127
140
  */
128
141
  export declare function findFontCallSites(source: string): FontAnalysis | null;
129
- export {};
130
142
  //# sourceMappingURL=ast.d.ts.map
@@ -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;AAkFD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAgIrE"}
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;AAChE,OAAO,KAAK,EAAE,OAAO,EAAkC,YAAY,EAAE,MAAM,eAAe,CAAC;AAQ3F,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA+GlD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAIhF;AAiCD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAIpF;AAID;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAa/F;AAQD;;;;;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;;;;;OAKG;IACH,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,YAAY,EAAE,CAAC;IAC5B;;;;OAIG;IACH,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC;;;;;;OAMG;IACH,iBAAiB,EAAE,YAAY,EAAE,CAAC;CACnC;AA6ED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA8KrE"}
@@ -42,7 +42,9 @@ export declare function emitFontAssets(pipeline: FontPipeline, emitFile: EmitFil
42
42
  * `buildManifest.css` keys work after TIM-1014.
43
43
  *
44
44
  * All font binaries use content-hashed filenames for immutable caching.
45
+ * Hrefs are prefixed with Vite's resolved `base` so they match the URLs
46
+ * the platform serves the emitted binaries under.
45
47
  */
46
- export declare function writeFontManifest(pipeline: FontPipeline, buildManifest: BuildManifest): void;
48
+ export declare function writeFontManifest(pipeline: FontPipeline, buildManifest: BuildManifest, base?: string): void;
47
49
  export {};
48
50
  //# sourceMappingURL=bundle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/fonts/bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAqB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGpF;;;;GAIG;AACH,UAAU,YAAY;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;CAC7B;AACD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,MAAM,CAAC;AAChD,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzC,kEAAkE;AAClE,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,SAAS,UAAU,EAAE,GACjC,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAS3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,WAAW,GAChB,IAAI,CA4BN;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAgC5F"}
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/fonts/bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAqB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGpF;;;;GAIG;AACH,UAAU,YAAY;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;CAC7B;AACD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,MAAM,CAAC;AAChD,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzC,kEAAkE;AAClE,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,SAAS,UAAU,EAAE,GACjC,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAS3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,WAAW,GAChB,IAAI,CA4BN;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,aAAa,EAC5B,IAAI,SAAM,GACT,IAAI,CAiCN"}
@@ -18,5 +18,5 @@ import type { FontPipeline } from './pipeline.js';
18
18
  * captured by reference so that fonts registered after `configureServer`
19
19
  * runs (during transform) are still resolvable.
20
20
  */
21
- export declare function installFontDevMiddleware(server: ViteDevServer, pipeline: FontPipeline): void;
21
+ export declare function installFontDevMiddleware(server: ViteDevServer, pipeline: FontPipeline, base?: string): void;
22
22
  //# sourceMappingURL=dev-middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev-middleware.d.ts","sourceRoot":"","sources":["../../src/fonts/dev-middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAG1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAUlD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAyC5F"}
1
+ {"version":3,"file":"dev-middleware.d.ts","sourceRoot":"","sources":["../../src/fonts/dev-middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAG1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAWlD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,YAAY,EACtB,IAAI,SAAM,GACT,IAAI,CA+CN"}
@@ -7,14 +7,7 @@
7
7
  *
8
8
  * Design doc: 24-fonts.md §"Step 4: Size-Adjusted Fallbacks"
9
9
  */
10
- import type { FontFaceDescriptor } from './types.js';
11
10
  export declare function getGenericFamily(family: string): string;
12
- /**
13
- * Generate a size-adjusted fallback @font-face for a given font family.
14
- *
15
- * Returns null if no metrics are available (unknown font — no fallback generated).
16
- */
17
- export declare function generateFallbackFontFace(family: string): FontFaceDescriptor | null;
18
11
  /**
19
12
  * Generate the full CSS for a size-adjusted fallback font.
20
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fallbacks.d.ts","sourceRoot":"","sources":["../../src/fonts/fallbacks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAwJrD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAclF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgBrD"}
1
+ {"version":3,"file":"fallbacks.d.ts","sourceRoot":"","sources":["../../src/fonts/fallbacks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAwJH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgBrD"}
@@ -101,9 +101,11 @@ export declare function downloadAndCacheFonts(fonts: ExtractedFont[], projectRoo
101
101
  * Generate @font-face descriptors for cached (production) Google Fonts.
102
102
  *
103
103
  * Each CachedFont gets a FontFaceDescriptor pointing to the
104
- * content-hashed URL under `/_timber/fonts/`.
104
+ * content-hashed URL under `<base>_timber/fonts/`. The `urlPrefix` comes
105
+ * from `fontUrlPrefix(viteBase)` so apps deployed under a non-root base
106
+ * resolve fonts correctly.
105
107
  */
106
- export declare function generateProductionFontFaces(cachedFonts: CachedFont[], display: string): FontFaceDescriptor[];
108
+ export declare function generateProductionFontFaces(cachedFonts: CachedFont[], display: string, urlPrefix?: string): FontFaceDescriptor[];
107
109
  /**
108
110
  * Generate @font-face descriptors for dev mode (CDN-pointing).
109
111
  *
@@ -1 +1 @@
1
- {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/fonts/google.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAepE,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,IAAI,EAAE,cAAc,CAAC;IACrB,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAiC/D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAahF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CA8BjE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAI5F;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAGrD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMnE;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,aAAa,EAAE,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,EAAE,CAAC,CAwCvB;AAeD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,UAAU,EAAE,EACzB,OAAO,EAAE,MAAM,GACd,kBAAkB,EAAE,CAStB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,MAAM,GACd,kBAAkB,EAAE,CAStB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAK5F"}
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/fonts/google.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgBpE,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,IAAI,EAAE,cAAc,CAAC;IACrB,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAiC/D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAahF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CA8BjE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAI5F;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAGrD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMnE;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,aAAa,EAAE,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,EAAE,CAAC,CAwCvB;AAeD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,UAAU,EAAE,EACzB,OAAO,EAAE,MAAM,EACf,SAAS,SAAkB,GAC1B,kBAAkB,EAAE,CAStB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,MAAM,GACd,kBAAkB,EAAE,CAStB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAK5F"}
@@ -45,9 +45,9 @@ export declare function generateFamilyName(sources: LocalFontSrc[]): string;
45
45
  * Generate @font-face descriptors for local font sources.
46
46
  *
47
47
  * Each source entry produces one @font-face rule. The `src` descriptor
48
- * uses a `url()` pointing to the served path under `/_timber/fonts/`.
49
- * The `urlPrefix` defaults to `/_timber/fonts` — the path used by both
50
- * the dev server middleware and the production build output.
48
+ * uses a `url()` pointing to the served path under `<base>_timber/fonts/`.
49
+ * The `urlPrefix` defaults to `fontUrlPrefix()` (root base) — pass
50
+ * `fontUrlPrefix(viteBase)` so non-root deployments resolve correctly.
51
51
  */
52
52
  export declare function generateLocalFontFaces(family: string, sources: LocalFontSrc[], display: string, urlPrefix?: string): FontFaceDescriptor[];
53
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/fonts/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAInG;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,YAAY,EAAE,CASzE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,YAAY,EAAE,GACtB,YAAY,EAAE,CAMhB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAYlE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,SAAmB,GAC3B,kBAAkB,EAAE,CAYtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,GAAG,aAAa,CAyB7F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAEjF"}
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/fonts/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKnG;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,YAAY,EAAE,CASzE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,YAAY,EAAE,GACtB,YAAY,EAAE,CAMhB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAYlE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,SAAkB,GAC1B,kBAAkB,EAAE,CAYtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,GAAG,aAAa,CAyB7F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAEjF"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Shared path/URL helpers for the timber-fonts pipeline.
3
+ *
4
+ * Two concerns live here:
5
+ *
6
+ * - `fontUrlPrefix` — the public URL prefix for font binaries, derived
7
+ * from Vite's resolved `base`. Every URL the pipeline emits (@font-face
8
+ * src, manifest hrefs, dev middleware matching) must go through this so
9
+ * apps deployed under a non-root base (`base: '/my-app/'`) resolve
10
+ * fonts correctly. Emitted *file* locations are not base-prefixed —
11
+ * only URLs are.
12
+ *
13
+ * - `fontOutputBasename` / `hashedFontBasename` — basename derivation for
14
+ * local font sources. Paths are absolutized with `resolve()`, which
15
+ * produces backslash separators on Windows, so `split('/').pop()` is
16
+ * not safe. `path.win32.basename` handles both separators.
17
+ *
18
+ * Design doc: 24-fonts.md
19
+ */
20
+ /** Directory (relative to the build output / URL root) holding font binaries. */
21
+ export declare const FONT_OUTPUT_DIR = "_timber/fonts";
22
+ /**
23
+ * Build the URL prefix for font binaries from Vite's resolved `base`.
24
+ *
25
+ * `fontUrlPrefix('/')` → `/_timber/fonts`
26
+ * `fontUrlPrefix('/my-app/')` → `/my-app/_timber/fonts`
27
+ */
28
+ export declare function fontUrlPrefix(base?: string): string;
29
+ /**
30
+ * Derive the output basename for a local font source path.
31
+ *
32
+ * Uses `path.win32.basename` because it splits on both `/` and `\`,
33
+ * handling absolute paths produced by `resolve()` on any platform.
34
+ */
35
+ export declare function fontOutputBasename(srcPath: string): string;
36
+ /**
37
+ * Derive the content-hashed output basename for a local font source.
38
+ *
39
+ * `hashedFontBasename('C:\\fonts\\MyFont-Bold.woff2', 'a1b2c3d4')`
40
+ * → `MyFont-Bold-a1b2c3d4.woff2`
41
+ */
42
+ export declare function hashedFontBasename(srcPath: string, hash: string): string;
43
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/fonts/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,iFAAiF;AACjF,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,SAAM,GAAG,MAAM,CAGhD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKxE"}
@@ -28,17 +28,6 @@
28
28
  import type { ExtractedFont, FontEntry, FontFaceDescriptor } from './types.js';
29
29
  import type { CachedFont } from './google.js';
30
30
  import { VirtualFontCssIdMap } from './virtual-modules.js';
31
- /**
32
- * Backwards-compatible alias for the registry shape that the standalone
33
- * `pruneRegistryEntries` and `generateAllFontCss` helpers operate on.
34
- *
35
- * The `FontPipeline` itself stores `Map<string, FontEntry>` internally and
36
- * never exposes its underlying map. Tests and external callers that build
37
- * their own font registries (e.g. fixtures in `tests/fonts-hmr-prune.test.ts`)
38
- * still pass plain `Map<string, ExtractedFont>` instances to the standalone
39
- * helpers, which is why the alias survives.
40
- */
41
- export type FontRegistry = Map<string, ExtractedFont>;
42
31
  export declare class FontPipeline {
43
32
  /**
44
33
  * The single per-font store. Keyed by `FontEntry.id` (which is itself
@@ -51,9 +40,16 @@ export declare class FontPipeline {
51
40
  private readonly _entries;
52
41
  /** When true, local font sources are content-hashed at registration time. */
53
42
  private readonly _hashOnRegister;
43
+ /**
44
+ * Vite's resolved `base`. Set from the plugin's `configResolved` hook so
45
+ * every @font-face URL the pipeline renders carries the prefix.
46
+ */
47
+ private _base;
54
48
  constructor(opts?: {
55
49
  hashOnRegister?: boolean;
56
50
  });
51
+ /** Set Vite's resolved `base` (from `configResolved`). */
52
+ setBase(base: string): void;
57
53
  /**
58
54
  * Per-importer virtual CSS module id registry. Populated by the
59
55
  * transform hook when it inlines a font function call, read by the
@@ -159,14 +155,4 @@ export declare class FontPipeline {
159
155
  */
160
156
  getCssForSegment(importer: string): string;
161
157
  }
162
- /**
163
- * Drop every registry entry that originated from `importer` and shares
164
- * `family`. Standalone helper retained as a public export for the test
165
- * suite (`tests/fonts-hmr-prune.test.ts`) and any external callers that
166
- * still build their own `FontRegistry` maps.
167
- *
168
- * Prefer `FontPipeline#pruneFor` inside the plugin itself — it also drops
169
- * attached `faces` and `cachedFiles` in the same operation.
170
- */
171
- export declare function pruneRegistryEntries(registry: FontRegistry, importer: string, family: string): void;
172
158
  //# sourceMappingURL=pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/fonts/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,qBAAa,YAAY;IACvB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAEzD,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;gBAE9B,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE;IAI/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,sBAA6B;IAI9C,kCAAkC;IAClC,IAAI,IAAI,MAAM;IAId,2EAA2E;IAC3E,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAItC,uEAAuE;IACvE,KAAK,IAAI,gBAAgB,CAAC,aAAa,CAAC;IAIxC,2CAA2C;IAC1C,WAAW,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAM3C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI3C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAKjC;;;;;OAKG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IAoBxC,oEAAoE;IACpE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAW9D,8DAA8D;IAC9D,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAW5D;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAShD,mEAAmE;IACnE,KAAK,IAAI,IAAI;IAOb;;;;;OAKG;IACF,iBAAiB,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAYlD;;;;;;;OAOG;IACH,MAAM,IAAI,MAAM;IAQhB;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAQ3C;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,IAAI,CAON"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/fonts/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,qBAAa,YAAY;IACvB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAEzD,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAE1C;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAO;gBAER,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE;IAI/C,0DAA0D;IAC1D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,sBAA6B;IAI9C,kCAAkC;IAClC,IAAI,IAAI,MAAM;IAId,2EAA2E;IAC3E,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAItC,uEAAuE;IACvE,KAAK,IAAI,gBAAgB,CAAC,aAAa,CAAC;IAIxC,2CAA2C;IAC1C,WAAW,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAM3C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI3C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAKjC;;;;;OAKG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IAgBxC,oEAAoE;IACpE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAW9D,8DAA8D;IAC9D,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAW5D;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAShD,mEAAmE;IACnE,KAAK,IAAI,IAAI;IAOb;;;;;OAKG;IACF,iBAAiB,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAYlD;;;;;;;OAOG;IACH,MAAM,IAAI,MAAM;IAShB;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAS3C"}
@@ -1 +1 @@
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
+ {"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,CAiKtE"}
@@ -28,7 +28,7 @@
28
28
  *
29
29
  * Design doc: 24-fonts.md
30
30
  */
31
- import type { ExtractedFont, FontFaceDescriptor } from './types.js';
31
+ import type { ExtractedFont } from './types.js';
32
32
  export declare const VIRTUAL_GOOGLE = "@timber/fonts/google";
33
33
  export declare const VIRTUAL_LOCAL = "@timber/fonts/local";
34
34
  export declare const RESOLVED_GOOGLE = "\0@timber/fonts/google";
@@ -74,21 +74,4 @@ export declare function generateGoogleVirtualModule(fonts: Iterable<ExtractedFon
74
74
  * `FontResult` objects at build time.
75
75
  */
76
76
  export declare function generateLocalVirtualModule(): string;
77
- /**
78
- * Generate combined CSS for a single extracted font.
79
- *
80
- * Includes `@font-face` rules (local or Google), the size-adjusted fallback
81
- * `@font-face`, and the scoped class rule. For Google fonts the resolved
82
- * `FontFaceDescriptor[]` must be passed in (from `generateProductionFontFaces`
83
- * in production or `resolveDevFontFaces` in dev).
84
- */
85
- export declare function generateFontCss(font: ExtractedFont, googleFaces?: FontFaceDescriptor[]): string;
86
- /**
87
- * Generate the CSS output for all extracted fonts.
88
- *
89
- * Includes `@font-face` rules for local and Google fonts, fallback rules,
90
- * and scoped classes. `googleFontFacesMap` provides pre-resolved
91
- * `FontFaceDescriptor[]` for each Google font (keyed by `ExtractedFont.id`).
92
- */
93
- export declare function generateAllFontCss(registry: Map<string, ExtractedFont>, googleFontFacesMap?: Map<string, FontFaceDescriptor[]>): string;
94
77
  //# sourceMappingURL=virtual-modules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtual-modules.d.ts","sourceRoot":"","sources":["../../src/fonts/virtual-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAKpE,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAClE,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,wBAAwB,QAAiC,CAAC;AAiBvE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAM/B,0EAA0E;IAC1E,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAW3C,+DAA+D;IAC/D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAK5B,oDAAoD;IACpD,KAAK,IAAI,IAAI;CAGd;AAUD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAqClF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAcnD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAwB/F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,GACrD,MAAM,CAOR"}
1
+ {"version":3,"file":"virtual-modules.d.ts","sourceRoot":"","sources":["../../src/fonts/virtual-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAClE,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,wBAAwB,QAAiC,CAAC;AAiBvE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAM/B,0EAA0E;IAC1E,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAW3C,+DAA+D;IAC/D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAK5B,oDAAoD;IACpD,KAAK,IAAI,IAAI;CAGd;AAUD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAqClF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAcnD"}