@lovrozagar/flare 0.1.0

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 (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/package.json +146 -0
  4. package/scripts/download-fonts.ts +136 -0
  5. package/scripts/populate-fonts.ts +721 -0
  6. package/src/await.ts +2 -0
  7. package/src/boundaries/index.ts +99 -0
  8. package/src/broadcast/channel.ts +65 -0
  9. package/src/broadcast/context.ts +12 -0
  10. package/src/broadcast/index.ts +75 -0
  11. package/src/broadcast/provider.tsx +7 -0
  12. package/src/build-location.ts +2 -0
  13. package/src/caches/index.ts +384 -0
  14. package/src/client/index.ts +75 -0
  15. package/src/client.tsx +2 -0
  16. package/src/codegen/index.ts +41 -0
  17. package/src/components/await.tsx +140 -0
  18. package/src/components/dev-error-overlay.tsx +154 -0
  19. package/src/components/direction-script.tsx +22 -0
  20. package/src/components/index.ts +150 -0
  21. package/src/components/locale-script.tsx +26 -0
  22. package/src/components/reset-css.tsx +14 -0
  23. package/src/components/ssr-context.tsx +37 -0
  24. package/src/components/theme-script.tsx +22 -0
  25. package/src/components/view-transition-css.tsx +21 -0
  26. package/src/config/index.ts +84 -0
  27. package/src/create-client-only-fn.ts +1 -0
  28. package/src/create-isomorphic-fn.ts +2 -0
  29. package/src/create-layout.ts +1 -0
  30. package/src/create-page.ts +1 -0
  31. package/src/create-path-segment.ts +1 -0
  32. package/src/create-query-client-getter.ts +2 -0
  33. package/src/create-root-layout.ts +1 -0
  34. package/src/create-router.ts +8 -0
  35. package/src/create-server-only-fn.ts +1 -0
  36. package/src/dedupe/index.ts +151 -0
  37. package/src/defer/index.ts +82 -0
  38. package/src/direction/index.tsx +163 -0
  39. package/src/direction.ts +3 -0
  40. package/src/duration/index.ts +18 -0
  41. package/src/env-fn/index.ts +101 -0
  42. package/src/env-fn.ts +2 -0
  43. package/src/errors/index.ts +166 -0
  44. package/src/fonts/abeezee.ts +50 -0
  45. package/src/fonts/abel.ts +26 -0
  46. package/src/fonts/abril-fatface.ts +34 -0
  47. package/src/fonts/acme.ts +26 -0
  48. package/src/fonts/advent-pro.ts +92 -0
  49. package/src/fonts/alegreya-sans.ts +228 -0
  50. package/src/fonts/alegreya.ts +228 -0
  51. package/src/fonts/alex-brush.ts +42 -0
  52. package/src/fonts/alfa-slab-one.ts +42 -0
  53. package/src/fonts/alice.ts +48 -0
  54. package/src/fonts/amatic-sc.ts +94 -0
  55. package/src/fonts/amiri.ts +114 -0
  56. package/src/fonts/antic-slab.ts +26 -0
  57. package/src/fonts/anton.ts +42 -0
  58. package/src/fonts/archivo-black.ts +34 -0
  59. package/src/fonts/archivo-narrow.ts +114 -0
  60. package/src/fonts/archivo.ts +66 -0
  61. package/src/fonts/arimo.ts +256 -0
  62. package/src/fonts/arvo.ts +50 -0
  63. package/src/fonts/asap.ts +66 -0
  64. package/src/fonts/assistant.ts +64 -0
  65. package/src/fonts/baloo-2.ts +82 -0
  66. package/src/fonts/barlow-condensed.ts +114 -0
  67. package/src/fonts/barlow-semi-condensed.ts +114 -0
  68. package/src/fonts/barlow.ts +114 -0
  69. package/src/fonts/be-vietnam-pro.ts +114 -0
  70. package/src/fonts/bebas-neue.ts +34 -0
  71. package/src/fonts/besley.ts +82 -0
  72. package/src/fonts/biorhyme.ts +50 -0
  73. package/src/fonts/bitter.ts +94 -0
  74. package/src/fonts/black-ops-one.ts +49 -0
  75. package/src/fonts/bree-serif.ts +34 -0
  76. package/src/fonts/bricolage-grotesque.ts +66 -0
  77. package/src/fonts/cabin.ts +114 -0
  78. package/src/fonts/cairo.ts +66 -0
  79. package/src/fonts/cardo.ts +193 -0
  80. package/src/fonts/catamaran.ts +41 -0
  81. package/src/fonts/caveat.ts +78 -0
  82. package/src/fonts/chakra-petch.ts +142 -0
  83. package/src/fonts/chivo.ts +66 -0
  84. package/src/fonts/cinzel.ts +50 -0
  85. package/src/fonts/comfortaa.ts +109 -0
  86. package/src/fonts/commissioner.ts +64 -0
  87. package/src/fonts/component.tsx +27 -0
  88. package/src/fonts/cormorant-garamond.ts +171 -0
  89. package/src/fonts/cormorant.ts +170 -0
  90. package/src/fonts/courgette.ts +34 -0
  91. package/src/fonts/courier-prime.ts +82 -0
  92. package/src/fonts/create-font.ts +47 -0
  93. package/src/fonts/create-registry-font.ts +40 -0
  94. package/src/fonts/crete-round.ts +50 -0
  95. package/src/fonts/crimson-text.ts +114 -0
  96. package/src/fonts/css.ts +86 -0
  97. package/src/fonts/dancing-script.ts +66 -0
  98. package/src/fonts/dm-mono.ts +50 -0
  99. package/src/fonts/dm-sans.ts +50 -0
  100. package/src/fonts/dm-serif-display.ts +50 -0
  101. package/src/fonts/domine.ts +50 -0
  102. package/src/fonts/dosis.ts +66 -0
  103. package/src/fonts/eb-garamond.ts +228 -0
  104. package/src/fonts/eczar.ts +94 -0
  105. package/src/fonts/encode-sans.ts +42 -0
  106. package/src/fonts/epilogue.ts +66 -0
  107. package/src/fonts/exo-2.ts +94 -0
  108. package/src/fonts/exo.ts +66 -0
  109. package/src/fonts/figtree.ts +82 -0
  110. package/src/fonts/fira-code.ts +121 -0
  111. package/src/fonts/fira-sans-condensed.ts +228 -0
  112. package/src/fonts/fira-sans.ts +228 -0
  113. package/src/fonts/fjalla-one.ts +49 -0
  114. package/src/fonts/font-urls.gen.json +1962 -0
  115. package/src/fonts/fraunces.ts +66 -0
  116. package/src/fonts/fredoka.ts +64 -0
  117. package/src/fonts/gelasio.ts +114 -0
  118. package/src/fonts/gloria-hallelujah.ts +34 -0
  119. package/src/fonts/gothic-a1.ts +124 -0
  120. package/src/fonts/great-vibes.ts +64 -0
  121. package/src/fonts/gudea.ts +66 -0
  122. package/src/fonts/heebo.ts +57 -0
  123. package/src/fonts/hind-siliguri.ts +66 -0
  124. package/src/fonts/hind.ts +66 -0
  125. package/src/fonts/ibm-plex-mono.ts +172 -0
  126. package/src/fonts/ibm-plex-sans-arabic.ts +80 -0
  127. package/src/fonts/ibm-plex-sans.ts +199 -0
  128. package/src/fonts/ibm-plex-serif.ts +171 -0
  129. package/src/fonts/inconsolata.ts +66 -0
  130. package/src/fonts/index.ts +4 -0
  131. package/src/fonts/indie-flower.ts +34 -0
  132. package/src/fonts/instrument-sans.ts +82 -0
  133. package/src/fonts/instrument-serif.ts +50 -0
  134. package/src/fonts/inter-display.ts +52 -0
  135. package/src/fonts/inter-tight.ts +124 -0
  136. package/src/fonts/inter.ts +123 -0
  137. package/src/fonts/jetbrains-mono.ts +199 -0
  138. package/src/fonts/josefin-sans.ts +114 -0
  139. package/src/fonts/josefin-slab.ts +50 -0
  140. package/src/fonts/jost.ts +64 -0
  141. package/src/fonts/kalam.ts +66 -0
  142. package/src/fonts/kanit.ts +142 -0
  143. package/src/fonts/karla.ts +82 -0
  144. package/src/fonts/khand.ts +66 -0
  145. package/src/fonts/lato.ts +82 -0
  146. package/src/fonts/league-spartan.ts +42 -0
  147. package/src/fonts/lexend-deca.ts +42 -0
  148. package/src/fonts/lexend.ts +42 -0
  149. package/src/fonts/libre-baskerville.ts +82 -0
  150. package/src/fonts/libre-franklin.ts +95 -0
  151. package/src/fonts/lilita-one.ts +34 -0
  152. package/src/fonts/lobster-two.ts +50 -0
  153. package/src/fonts/lobster.ts +56 -0
  154. package/src/fonts/lora.ts +235 -0
  155. package/src/fonts/m-plus-rounded-1c.ts +138 -0
  156. package/src/fonts/manrope.ts +109 -0
  157. package/src/fonts/maven-pro.ts +66 -0
  158. package/src/fonts/merriweather-sans.ts +142 -0
  159. package/src/fonts/merriweather.ts +171 -0
  160. package/src/fonts/montserrat-alternates.ts +171 -0
  161. package/src/fonts/montserrat.ts +94 -0
  162. package/src/fonts/mukta.ts +66 -0
  163. package/src/fonts/mulish.ts +170 -0
  164. package/src/fonts/nanum-gothic.ts +34 -0
  165. package/src/fonts/nanum-myeongjo.ts +34 -0
  166. package/src/fonts/neuton.ts +66 -0
  167. package/src/fonts/newsreader.ts +114 -0
  168. package/src/fonts/noticia-text.ts +114 -0
  169. package/src/fonts/noto-sans-arabic.ts +58 -0
  170. package/src/fonts/noto-sans-hk.ts +49 -0
  171. package/src/fonts/noto-sans-jp.ts +49 -0
  172. package/src/fonts/noto-sans-kr.ts +49 -0
  173. package/src/fonts/noto-sans-sc.ts +49 -0
  174. package/src/fonts/noto-sans-tc.ts +49 -0
  175. package/src/fonts/noto-sans.ts +140 -0
  176. package/src/fonts/noto-serif-jp.ts +80 -0
  177. package/src/fonts/noto-serif.ts +140 -0
  178. package/src/fonts/nunito-sans.ts +170 -0
  179. package/src/fonts/nunito.ts +170 -0
  180. package/src/fonts/old-standard-tt.ts +133 -0
  181. package/src/fonts/onest.ts +48 -0
  182. package/src/fonts/open-sans.ts +340 -0
  183. package/src/fonts/orbitron.ts +34 -0
  184. package/src/fonts/oswald.ts +94 -0
  185. package/src/fonts/outfit.ts +34 -0
  186. package/src/fonts/overpass.ts +94 -0
  187. package/src/fonts/oxygen.ts +50 -0
  188. package/src/fonts/pacifico.ts +56 -0
  189. package/src/fonts/passion-one.ts +50 -0
  190. package/src/fonts/pathway-gothic-one.ts +34 -0
  191. package/src/fonts/permanent-marker.ts +26 -0
  192. package/src/fonts/philosopher.ts +172 -0
  193. package/src/fonts/play.ts +109 -0
  194. package/src/fonts/playfair-display.ts +142 -0
  195. package/src/fonts/plus-jakarta-sans.ts +142 -0
  196. package/src/fonts/poppins.ts +114 -0
  197. package/src/fonts/prompt.ts +142 -0
  198. package/src/fonts/pt-sans-narrow.ts +78 -0
  199. package/src/fonts/pt-sans.ts +138 -0
  200. package/src/fonts/pt-serif.ts +138 -0
  201. package/src/fonts/public-sans.ts +66 -0
  202. package/src/fonts/questrial.ts +42 -0
  203. package/src/fonts/quicksand.ts +66 -0
  204. package/src/fonts/rajdhani.ts +66 -0
  205. package/src/fonts/raleway.ts +94 -0
  206. package/src/fonts/recursive.ts +80 -0
  207. package/src/fonts/red-hat-display.ts +82 -0
  208. package/src/fonts/red-rose.ts +66 -0
  209. package/src/fonts/registry.gen.ts +173 -0
  210. package/src/fonts/righteous.ts +34 -0
  211. package/src/fonts/roboto-condensed.ts +124 -0
  212. package/src/fonts/roboto-flex.ts +64 -0
  213. package/src/fonts/roboto-mono.ts +199 -0
  214. package/src/fonts/roboto-slab.ts +72 -0
  215. package/src/fonts/roboto.ts +156 -0
  216. package/src/fonts/rokkitt.ts +66 -0
  217. package/src/fonts/rubik.ts +199 -0
  218. package/src/fonts/sacramento.ts +34 -0
  219. package/src/fonts/saira.ts +66 -0
  220. package/src/fonts/sarabun.ts +142 -0
  221. package/src/fonts/satisfy.ts +26 -0
  222. package/src/fonts/sawarabi-mincho.ts +41 -0
  223. package/src/fonts/shadows-into-light.ts +34 -0
  224. package/src/fonts/signika-negative.ts +66 -0
  225. package/src/fonts/signika.ts +66 -0
  226. package/src/fonts/slabo-27px.ts +34 -0
  227. package/src/fonts/sora.ts +50 -0
  228. package/src/fonts/source-code-pro.ts +228 -0
  229. package/src/fonts/source-sans-3.ts +228 -0
  230. package/src/fonts/source-serif-4.ts +199 -0
  231. package/src/fonts/space-grotesk.ts +66 -0
  232. package/src/fonts/space-mono.ts +114 -0
  233. package/src/fonts/spectral.ts +170 -0
  234. package/src/fonts/tajawal.ts +50 -0
  235. package/src/fonts/teko.ts +66 -0
  236. package/src/fonts/tenor-sans.ts +41 -0
  237. package/src/fonts/tinos.ts +256 -0
  238. package/src/fonts/titillium-web.ts +82 -0
  239. package/src/fonts/types.ts +43 -0
  240. package/src/fonts/ubuntu-condensed.ts +63 -0
  241. package/src/fonts/ubuntu-mono.ts +195 -0
  242. package/src/fonts/ubuntu.ts +195 -0
  243. package/src/fonts/unbounded.ts +94 -0
  244. package/src/fonts/unicode-ranges.gen.ts +28 -0
  245. package/src/fonts/urbanist.ts +50 -0
  246. package/src/fonts/varela-round.ts +49 -0
  247. package/src/fonts/vollkorn.ts +199 -0
  248. package/src/fonts/work-sans.ts +66 -0
  249. package/src/fonts/yanone-kaffeesatz.ts +128 -0
  250. package/src/fonts/yantramanav.ts +66 -0
  251. package/src/fonts/yellowtail.ts +34 -0
  252. package/src/fonts/young-serif.ts +34 -0
  253. package/src/fonts/zen-kaku-gothic-new.ts +64 -0
  254. package/src/fonts/zilla-slab.ts +82 -0
  255. package/src/form/index.tsx +205 -0
  256. package/src/generators/index.ts +1589 -0
  257. package/src/head-client/index.ts +649 -0
  258. package/src/history/index.ts +210 -0
  259. package/src/hooks.ts +61 -0
  260. package/src/hydrate/index.tsx +381 -0
  261. package/src/hydration/index.ts +187 -0
  262. package/src/i18n/index.ts +250 -0
  263. package/src/i18n/jsx.tsx +42 -0
  264. package/src/i18n/message-format.ts +174 -0
  265. package/src/image/index.tsx +473 -0
  266. package/src/image.ts +12 -0
  267. package/src/intercept-outlet/index.tsx +18 -0
  268. package/src/intercept-outlet.ts +2 -0
  269. package/src/internal/index.ts +143 -0
  270. package/src/internal/once-idle.ts +24 -0
  271. package/src/internal.ts +12 -0
  272. package/src/lazy/index.tsx +205 -0
  273. package/src/link/index.tsx +367 -0
  274. package/src/loader-pipeline/index.ts +639 -0
  275. package/src/locale/index.tsx +137 -0
  276. package/src/locale.ts +3 -0
  277. package/src/logger.ts +22 -0
  278. package/src/middleware/builtins/api-proxy.ts +64 -0
  279. package/src/middleware/builtins/cdn-proxy.ts +58 -0
  280. package/src/middleware/builtins/i18n.ts +256 -0
  281. package/src/middleware/builtins/keepalive.ts +24 -0
  282. package/src/middleware/builtins/markdown-negotiation.ts +141 -0
  283. package/src/middleware/builtins/static-assets.ts +32 -0
  284. package/src/middleware/index.ts +223 -0
  285. package/src/module-graph/index.ts +181 -0
  286. package/src/mount/index.ts +146 -0
  287. package/src/navigate.ts +1 -0
  288. package/src/navigation/index.ts +1278 -0
  289. package/src/navigation/types.ts +59 -0
  290. package/src/navigation-progress/index.tsx +247 -0
  291. package/src/navigation-progress.ts +1 -0
  292. package/src/ndjson-client/index.ts +376 -0
  293. package/src/ndjson-server/index.ts +284 -0
  294. package/src/outlet/index.tsx +633 -0
  295. package/src/outlet/types.ts +243 -0
  296. package/src/plugins/css-transform.ts +70 -0
  297. package/src/plugins/dev-cdn-cache.ts +454 -0
  298. package/src/plugins/dev-dashboard/client.tsx +2603 -0
  299. package/src/plugins/dev-dashboard/match-route-tree.ts +159 -0
  300. package/src/plugins/dev-dashboard/plugin.ts +404 -0
  301. package/src/plugins/dev-prerender.ts +168 -0
  302. package/src/plugins/dev-server.ts +327 -0
  303. package/src/plugins/generate-watch.ts +32 -0
  304. package/src/plugins/image-plugin.ts +171 -0
  305. package/src/plugins/index.ts +445 -0
  306. package/src/plugins/options.ts +37 -0
  307. package/src/plugins/parse-utils.ts +59 -0
  308. package/src/plugins/prerender-plugin.ts +144 -0
  309. package/src/plugins/purge.ts +242 -0
  310. package/src/plugins/server-fn.ts +641 -0
  311. package/src/plugins/service-worker.ts +225 -0
  312. package/src/plugins/solid-jsx.d.ts +12 -0
  313. package/src/plugins/sx-ast/atomic.ts +166 -0
  314. package/src/plugins/sx-ast/evaluator.ts +235 -0
  315. package/src/plugins/sx-ast/index.ts +372 -0
  316. package/src/plugins/sx-ast/parser.ts +22 -0
  317. package/src/plugins/sx-ast/rewrite.ts +763 -0
  318. package/src/plugins/sx.d.ts +14 -0
  319. package/src/plugins/tw-compile.ts +240 -0
  320. package/src/plugins/types.ts +41 -0
  321. package/src/plugins/virtual.d.ts +110 -0
  322. package/src/plugins/virtual.ts +184 -0
  323. package/src/preload/index.ts +77 -0
  324. package/src/prerender/index.ts +431 -0
  325. package/src/query-client/index.tsx +168 -0
  326. package/src/registry/index.ts +88 -0
  327. package/src/reset-css.ts +1 -0
  328. package/src/revalidation/index.ts +84 -0
  329. package/src/rewrite/index.ts +83 -0
  330. package/src/route-builder/create-layout.ts +655 -0
  331. package/src/route-builder/create-page.ts +806 -0
  332. package/src/route-builder/create-path-segment.ts +34 -0
  333. package/src/route-builder/create-root-layout.ts +608 -0
  334. package/src/route-builder/index.ts +49 -0
  335. package/src/route-builder/register.ts +242 -0
  336. package/src/route-builder/types.ts +294 -0
  337. package/src/router-config/index.ts +91 -0
  338. package/src/router-primitives/index.ts +25 -0
  339. package/src/router-primitives/location.ts +29 -0
  340. package/src/router-primitives/match-id.ts +111 -0
  341. package/src/router-primitives/paths.ts +109 -0
  342. package/src/router-primitives/tree.ts +243 -0
  343. package/src/router-primitives/types.ts +74 -0
  344. package/src/router.ts +31 -0
  345. package/src/search-engine/bing.ts +32 -0
  346. package/src/search-engine/google-jwt.ts +95 -0
  347. package/src/search-engine/google.ts +139 -0
  348. package/src/search-engine/index-now.ts +64 -0
  349. package/src/search-engine/index.ts +12 -0
  350. package/src/security/index.ts +230 -0
  351. package/src/server/index.ts +286 -0
  352. package/src/server-context/browser.ts +113 -0
  353. package/src/server-context/index.ts +217 -0
  354. package/src/server-fn/index.ts +710 -0
  355. package/src/server-fn-query.ts +169 -0
  356. package/src/server-handler/etag.ts +51 -0
  357. package/src/server-handler/headers.ts +5 -0
  358. package/src/server-handler/index.ts +1664 -0
  359. package/src/server-handler/types.ts +24 -0
  360. package/src/server-handler/validate-static-params.ts +130 -0
  361. package/src/server.ts +2 -0
  362. package/src/service-worker/template.ts +153 -0
  363. package/src/service-worker-hook/index.ts +70 -0
  364. package/src/sitemap/index.ts +231 -0
  365. package/src/ssr/critical-css.ts +150 -0
  366. package/src/ssr/head-prefix.ts +65 -0
  367. package/src/ssr/head.ts +259 -0
  368. package/src/ssr/index.tsx +879 -0
  369. package/src/state-parser/index.ts +266 -0
  370. package/src/store/filesystem.ts +131 -0
  371. package/src/store/index.ts +29 -0
  372. package/src/styles/index.ts +1200 -0
  373. package/src/styles/sx-types.ts +11 -0
  374. package/src/testing/index.ts +251 -0
  375. package/src/testing.ts +2 -0
  376. package/src/theme/index.tsx +232 -0
  377. package/src/theme.ts +3 -0
  378. package/src/tracing/index.ts +4 -0
  379. package/src/tracing/noop.ts +13 -0
  380. package/src/tracing/otel.ts +37 -0
  381. package/src/tracing/timing.ts +34 -0
  382. package/src/tracing/types.ts +9 -0
  383. package/src/url/index.ts +140 -0
  384. package/src/use-router.ts +11 -0
  385. package/src/use-suspense-query.ts +2 -0
  386. package/src/validation/index.ts +57 -0
  387. package/src/view-transition-css.ts +1 -0
@@ -0,0 +1,187 @@
1
+ import { batch } from "solid-js";
2
+ import type { GlobalBoundaries } from "../boundaries/index.ts";
3
+ import type { CachedMatch, MatchCache } from "../caches/index.ts";
4
+ import { applyPerRouteHeads, initRouteHierarchy } from "../head-client/index.ts";
5
+ import { isRenderFn, retryImport } from "../internal.ts";
6
+ import type { LoadedRouteModule, LoadedRouteModules } from "../navigation/types.ts";
7
+ import type { ClientMatch, FlareProviderContext } from "../outlet/types.ts";
8
+ import type { HeadConfig } from "../route-builder/types.ts";
9
+ import { computeMatchId, deriveLayouts, matchRoute, toLocaleMatch } from "../router-primitives/index.ts";
10
+ import type { MatchResult, TreeNode } from "../router-primitives/types.ts";
11
+ import type { LocaleConfig } from "../locale.ts";
12
+ import { parseSearchParams, type SearchParams } from "../url/index.ts";
13
+
14
+ export async function loadRouteModules(
15
+ pathname: string,
16
+ routeTree: TreeNode,
17
+ layouts: Record<string, () => Promise<{ default: unknown }>>,
18
+ caseSensitive?: boolean,
19
+ localeConfig?: LocaleConfig,
20
+ ): Promise<LoadedRouteModules | null> {
21
+ const match: MatchResult | null = matchRoute(routeTree, pathname, caseSensitive, toLocaleMatch(localeConfig));
22
+ if (!match) return null;
23
+
24
+ const layoutKeys = deriveLayouts(match.route.x);
25
+
26
+ const promises: Promise<{ default: unknown } | null>[] = [
27
+ retryImport(() => match.route.p() as Promise<{ default: unknown }>),
28
+ ...layoutKeys.map((key) => {
29
+ const loader = layouts[key];
30
+ if (!loader) return Promise.resolve(null);
31
+ return retryImport(() => loader());
32
+ }),
33
+ ];
34
+
35
+ const [pageResult, ...layoutResults] = await Promise.all(promises);
36
+
37
+ const rawPage = (pageResult?.default ?? pageResult) as LoadedRouteModule;
38
+ const page: LoadedRouteModule = { ...rawPage, variablePath: match.route.v };
39
+ const loadedLayouts: LoadedRouteModule[] = layoutResults
40
+ .filter((r): r is { default: unknown } => r !== null)
41
+ .map((r) => {
42
+ const raw = (r.default ?? r) as LoadedRouteModule;
43
+ return { ...raw, variablePath: "" };
44
+ });
45
+
46
+ return {
47
+ layouts: loadedLayouts,
48
+ page,
49
+ params: match.params,
50
+ };
51
+ }
52
+
53
+ export function buildMatches(ctx: FlareProviderContext, modules: LoadedRouteModules): void {
54
+ const search: SearchParams =
55
+ typeof window !== "undefined" ? parseSearchParams(new URL(window.location.href).searchParams) : {};
56
+ const allModules: LoadedRouteModule[] = [...modules.layouts, modules.page];
57
+
58
+ const clientMatches: ClientMatch[] = allModules.map((mod) => {
59
+ const deps = mod.effectsConfig?.loaderDeps?.({ search }) ?? [];
60
+ const matchId = computeMatchId({
61
+ loaderDeps: () => deps,
62
+ params: modules.params,
63
+ routeId: mod.virtualPath,
64
+ search,
65
+ });
66
+ const cached: CachedMatch | undefined = ctx.matchCache.get(matchId);
67
+
68
+ return {
69
+ _type: mod._type,
70
+ error: cached?.error,
71
+ errorRender: isRenderFn(mod.errorRender) ? mod.errorRender : undefined,
72
+ loaderData: cached?.data,
73
+ notFoundRender: isRenderFn(mod.notFoundRender) ? mod.notFoundRender : undefined,
74
+ preloaderContext: cached?.preloaderContext,
75
+ render: mod.render,
76
+ unauthenticatedRender: isRenderFn(mod.unauthenticatedRender) ? mod.unauthenticatedRender : undefined,
77
+ unauthorizedRender: isRenderFn(mod.unauthorizedRender) ? mod.unauthorizedRender : undefined,
78
+ variablePath: mod.variablePath,
79
+ virtualPath: mod.virtualPath,
80
+ };
81
+ });
82
+
83
+ batch(() => {
84
+ ctx.setMatches(clientMatches);
85
+ ctx.setParams(modules.params);
86
+ });
87
+ }
88
+
89
+ export function extractRootBoundaries(rootLayout: LoadedRouteModule | undefined): GlobalBoundaries {
90
+ const boundaries: GlobalBoundaries = {};
91
+ if (!rootLayout) return boundaries;
92
+ if (isRenderFn(rootLayout.errorRender)) boundaries.error = rootLayout.errorRender;
93
+ if (isRenderFn(rootLayout.notFoundRender)) boundaries.notFound = rootLayout.notFoundRender;
94
+ if (isRenderFn(rootLayout.unauthenticatedRender)) {
95
+ boundaries.unauthenticated = rootLayout.unauthenticatedRender;
96
+ }
97
+ if (isRenderFn(rootLayout.unauthorizedRender)) {
98
+ boundaries.unauthorized = rootLayout.unauthorizedRender;
99
+ }
100
+ return boundaries;
101
+ }
102
+
103
+ export function buildInitialMatches(
104
+ modules: LoadedRouteModule[],
105
+ matchCache: MatchCache,
106
+ params: Record<string, string | string[]>,
107
+ search: SearchParams,
108
+ errorMap?: Map<string, Error>,
109
+ ): ClientMatch[] {
110
+ return modules.map((mod) => {
111
+ const deps = mod.effectsConfig?.loaderDeps?.({ search }) ?? [];
112
+ const matchId = computeMatchId({
113
+ loaderDeps: () => deps,
114
+ params,
115
+ routeId: mod.virtualPath,
116
+ search,
117
+ });
118
+ const cached = matchCache.get(matchId);
119
+ return {
120
+ _type: mod._type,
121
+ error: errorMap?.get(mod.virtualPath),
122
+ errorRender: isRenderFn(mod.errorRender) ? mod.errorRender : undefined,
123
+ loaderData: cached?.data,
124
+ notFoundRender: isRenderFn(mod.notFoundRender) ? mod.notFoundRender : undefined,
125
+ preloaderContext: cached?.preloaderContext,
126
+ render: mod.render,
127
+ unauthenticatedRender: isRenderFn(mod.unauthenticatedRender) ? mod.unauthenticatedRender : undefined,
128
+ unauthorizedRender: isRenderFn(mod.unauthorizedRender) ? mod.unauthorizedRender : undefined,
129
+ variablePath: mod.variablePath,
130
+ virtualPath: mod.virtualPath,
131
+ };
132
+ });
133
+ }
134
+
135
+ export interface HydrationState {
136
+ e?: Array<{ message: string; name: string; source?: string; stack?: string }>;
137
+ matches: Array<{
138
+ loaderData: unknown;
139
+ matchId: string;
140
+ preloaderContext?: Record<string, unknown>;
141
+ }>;
142
+ params: Record<string, string | string[]>;
143
+ pathname: string;
144
+ ph?: Array<{ head: HeadConfig; matchId: string }>;
145
+ q?: Array<{ data: unknown; key: unknown[]; staleTime?: number }>;
146
+ resolvers: Map<string, { reject: (e: Error) => void; resolve: (d: unknown) => void }>;
147
+ search: SearchParams;
148
+ }
149
+
150
+ export function populateMatchCache(
151
+ matchCache: MatchCache,
152
+ matches: HydrationState["matches"],
153
+ perRouteHeads?: HydrationState["ph"],
154
+ ): void {
155
+ const headMap = new Map<string, HeadConfig>();
156
+ if (perRouteHeads) {
157
+ for (const h of perRouteHeads) {
158
+ headMap.set(h.matchId, h.head);
159
+ }
160
+ }
161
+ const now = Date.now();
162
+ for (const m of matches) {
163
+ matchCache.set({
164
+ data: m.loaderData,
165
+ headConfig: headMap.get(m.matchId),
166
+ invalid: false,
167
+ matchId: m.matchId,
168
+ preloaderContext: m.preloaderContext,
169
+ updatedAt: now,
170
+ });
171
+ }
172
+ }
173
+
174
+ export function hydrateHeadState(state: Pick<HydrationState, "ph">): void {
175
+ if (state.ph) {
176
+ /* First entry is root layout — its title is the fallback when pages don't define .head() */
177
+ const rootTitle = state.ph[0]?.head.title;
178
+ const matchIds: string[] = [];
179
+ const headEntries: Array<{ head: (typeof state.ph)[number]["head"]; matchId: string }> = [];
180
+ for (const h of state.ph) {
181
+ matchIds.push(h.matchId);
182
+ headEntries.push({ head: h.head, matchId: h.matchId });
183
+ }
184
+ initRouteHierarchy(matchIds, rootTitle);
185
+ applyPerRouteHeads(headEntries);
186
+ }
187
+ }
@@ -0,0 +1,250 @@
1
+ import { parseRichText } from "./jsx.tsx";
2
+ import { formatMessage } from "./message-format.ts";
3
+
4
+ export { parseRichText } from "./jsx.tsx";
5
+ export { formatMessage } from "./message-format.ts";
6
+
7
+ /* ── createTranslations ────────────────────────────────────────────── */
8
+
9
+ type TranslationDict = Record<string, string>;
10
+
11
+ /**
12
+ * Static import: () => import("./en/common.json") → { default: T }
13
+ * Dynamic fetch: () => fetchTranslations("en", "common") → T directly
14
+ */
15
+ type TranslationLoader<T extends TranslationDict = TranslationDict> =
16
+ | (() => Promise<T>)
17
+ | (() => Promise<{ default: T }>);
18
+
19
+ type TranslationNamespaces = Record<string, Record<string, TranslationLoader>>;
20
+
21
+ /**
22
+ * Extract the resolved dict type for a namespace.
23
+ * Unwraps both { default: D } (static import) and D (dynamic fetch).
24
+ */
25
+ type UnwrapLoader<TLoader> = TLoader extends () => Promise<{ default: infer D }>
26
+ ? D
27
+ : TLoader extends () => Promise<infer D>
28
+ ? D
29
+ : TranslationDict;
30
+
31
+ type ResolvedDict<TLoaders extends Record<string, TranslationLoader>> = UnwrapLoader<TLoaders[keyof TLoaders]>;
32
+
33
+ type LoadResult<T extends TranslationNamespaces, K extends keyof T & string> = {
34
+ [N in K]: ResolvedDict<T[N]>;
35
+ };
36
+
37
+ interface TranslationsConfig<T extends TranslationNamespaces> {
38
+ load: <K extends keyof T & string>(locale: string, namespaces: K[]) => Promise<LoadResult<T, K>>;
39
+ }
40
+
41
+ function unwrapModule(mod: unknown): TranslationDict {
42
+ if (
43
+ mod !== null &&
44
+ typeof mod === "object" &&
45
+ "default" in (mod as Record<string, unknown>) &&
46
+ typeof (mod as Record<string, unknown>).default === "object"
47
+ ) {
48
+ return (mod as { default: TranslationDict }).default;
49
+ }
50
+ return mod as TranslationDict;
51
+ }
52
+
53
+ export function createTranslations<const T extends TranslationNamespaces>(namespaces: T): TranslationsConfig<T> {
54
+ return {
55
+ async load<K extends keyof T & string>(locale: string, nsKeys: K[]): Promise<LoadResult<T, K>> {
56
+ const entries = await Promise.all(
57
+ nsKeys.map(async (ns) => {
58
+ const loaders = namespaces[ns];
59
+ if (!loaders) throw new Error(`Unknown namespace: ${ns}`);
60
+ const loader = loaders[locale];
61
+ if (!loader) throw new Error(`Missing locale "${locale}" for namespace "${ns}"`);
62
+ const result = await loader();
63
+ return [ns, unwrapModule(result)] as const;
64
+ }),
65
+ );
66
+
67
+ return Object.fromEntries(entries) as LoadResult<T, K>;
68
+ },
69
+ };
70
+ }
71
+
72
+ /* ── createTranslator ──────────────────────────────────────────────── */
73
+
74
+ type PrefixKeys<
75
+ T extends Record<string, Record<string, string>>,
76
+ NS extends keyof T & string,
77
+ > = `${NS}.${string & keyof T[NS]}`;
78
+
79
+ export type FlatKeys<T extends Record<string, Record<string, string>>> = [T] extends [never]
80
+ ? never
81
+ : {
82
+ [NS in keyof T & string]: PrefixKeys<T, NS>;
83
+ }[keyof T & string];
84
+
85
+ /** Extract `t` property from loader data or preloader context */
86
+ export type ExtractT<TData> = TData extends {
87
+ t: infer T extends Record<string, Record<string, string>>;
88
+ }
89
+ ? T
90
+ : never;
91
+
92
+ /* ── ICU variable extraction (type-level) ─────────────────────────── */
93
+
94
+ type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
95
+ type Alpha =
96
+ | "A"
97
+ | "B"
98
+ | "C"
99
+ | "D"
100
+ | "E"
101
+ | "F"
102
+ | "G"
103
+ | "H"
104
+ | "I"
105
+ | "J"
106
+ | "K"
107
+ | "L"
108
+ | "M"
109
+ | "N"
110
+ | "O"
111
+ | "P"
112
+ | "Q"
113
+ | "R"
114
+ | "S"
115
+ | "T"
116
+ | "U"
117
+ | "V"
118
+ | "W"
119
+ | "X"
120
+ | "Y"
121
+ | "Z"
122
+ | "a"
123
+ | "b"
124
+ | "c"
125
+ | "d"
126
+ | "e"
127
+ | "f"
128
+ | "g"
129
+ | "h"
130
+ | "i"
131
+ | "j"
132
+ | "k"
133
+ | "l"
134
+ | "m"
135
+ | "n"
136
+ | "o"
137
+ | "p"
138
+ | "q"
139
+ | "r"
140
+ | "s"
141
+ | "t"
142
+ | "u"
143
+ | "v"
144
+ | "w"
145
+ | "x"
146
+ | "y"
147
+ | "z";
148
+ type WordChar = Alpha | Digit | "_";
149
+
150
+ type EndsWithWordChar<S extends string> = S extends `${string}${WordChar}` ? true : false;
151
+
152
+ type IsIdent<S extends string> = S extends `${Alpha | "_"}${string}`
153
+ ? S extends `${string} ${string}`
154
+ ? false
155
+ : true
156
+ : false;
157
+
158
+ /**
159
+ * Extract ICU variable names from a template string at the type level.
160
+ * Handles `{var}`, `{var, plural, ...}`, `{var, select, ...}`, `{var, number}`.
161
+ * Filters out branch content (e.g. `one{# item}`) by checking if `{` is
162
+ * preceded by a word character (ICU branch syntax, not a variable reference).
163
+ */
164
+ export type ExtractICUVars<S extends string> = S extends `${infer Before}{${infer After}`
165
+ ?
166
+ | (EndsWithWordChar<Before> extends true
167
+ ? never
168
+ : After extends `${infer Word},${string}`
169
+ ? Word extends `${infer Clean}}${string}`
170
+ ? IsIdent<Clean> extends true
171
+ ? Clean
172
+ : never
173
+ : IsIdent<Word> extends true
174
+ ? Word
175
+ : never
176
+ : After extends `${infer Word}}${string}`
177
+ ? IsIdent<Word> extends true
178
+ ? Word
179
+ : never
180
+ : never)
181
+ | ExtractICUVars<After>
182
+ : never;
183
+
184
+ /** Resolve flat key `"ns.key"` back to the template string type */
185
+ type LookupTemplate<
186
+ TDict extends Record<string, Record<string, string>>,
187
+ K extends string,
188
+ > = K extends `${infer NS}.${infer Key}`
189
+ ? NS extends keyof TDict
190
+ ? Key extends keyof TDict[NS]
191
+ ? TDict[NS][Key]
192
+ : string
193
+ : string
194
+ : string;
195
+
196
+ /** Required typed values when template has ICU vars, optional otherwise */
197
+ type TranslatorArgs<Template extends string> = [ExtractICUVars<Template>] extends [never]
198
+ ? [values?: Record<string, unknown>]
199
+ : [values: { [K in ExtractICUVars<Template>]: number | string }];
200
+
201
+ export interface Translator<
202
+ TDict extends Record<string, Record<string, string>> = Record<string, Record<string, string>>,
203
+ > {
204
+ <K extends FlatKeys<TDict>>(key: K, ...args: TranslatorArgs<LookupTemplate<TDict, K>>): string;
205
+ rich: <K extends FlatKeys<TDict>>(
206
+ key: K,
207
+ components: Record<string, (children: string) => unknown>,
208
+ ...args: TranslatorArgs<LookupTemplate<TDict, K>>
209
+ ) => unknown;
210
+ }
211
+
212
+ export function createTranslator<T extends Record<string, Record<string, string>>>(
213
+ loaded: T,
214
+ locale?: string,
215
+ ): Translator<T> {
216
+ /* Flatten: { ns: { "key": "val" } } → { "ns.key": "val" } */
217
+ const flat: Record<string, string> = {};
218
+ for (const [ns, entries] of Object.entries(loaded)) {
219
+ for (const [key, val] of Object.entries(entries)) {
220
+ flat[`${ns}.${key}`] = val;
221
+ }
222
+ }
223
+
224
+ const t = (key: string, values?: Record<string, unknown>): string => {
225
+ const template = flat[key];
226
+ if (template === undefined) return key;
227
+ return formatMessage(template, values, locale);
228
+ };
229
+
230
+ t.rich = (
231
+ key: string,
232
+ components: Record<string, (children: string) => unknown>,
233
+ values?: Record<string, unknown>,
234
+ ): unknown => {
235
+ const template = flat[key];
236
+ if (template === undefined) return key;
237
+
238
+ /* First apply ICU formatting if values provided */
239
+ const formatted = values ? formatMessage(template, values, locale) : template;
240
+
241
+ /* Then parse rich text components */
242
+ const parts = parseRichText(formatted, components);
243
+
244
+ /* If single element, return it directly */
245
+ if (parts.length === 1) return parts[0];
246
+ return parts;
247
+ };
248
+
249
+ return t as Translator<T>;
250
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Rich text parsing for JSX interpolation
3
+ * Parses [[component:content]] syntax into component calls
4
+ */
5
+
6
+ const RICH_RE = /\[\[([a-zA-Z0-9_-]+):([^\]]*)\]\]/g;
7
+
8
+ export function parseRichText(text: string, components: Record<string, (children: string) => unknown>): unknown[] {
9
+ const parts: unknown[] = [];
10
+ let lastIndex = 0;
11
+
12
+ RICH_RE.lastIndex = 0;
13
+ let match = RICH_RE.exec(text);
14
+
15
+ while (match !== null) {
16
+ const before = text.slice(lastIndex, match.index);
17
+ parts.push(before);
18
+
19
+ const componentName = match[1] ?? "";
20
+ const content = match[2] ?? "";
21
+ const component = components[componentName];
22
+
23
+ if (component) {
24
+ parts.push(component(content));
25
+ } else {
26
+ parts.push(content);
27
+ }
28
+
29
+ lastIndex = match.index + match[0].length;
30
+ match = RICH_RE.exec(text);
31
+ }
32
+
33
+ if (lastIndex < text.length) {
34
+ parts.push(text.slice(lastIndex));
35
+ }
36
+
37
+ if (parts.length === 0) {
38
+ parts.push(text);
39
+ }
40
+
41
+ return parts;
42
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Minimal ICU MessageFormat parser
3
+ * Handles: {var}, {var, plural, ...}, {var, select, ...}, {var, number}
4
+ */
5
+
6
+ type PluralCategory = "few" | "many" | "one" | "other" | "two" | "zero";
7
+
8
+ function getPluralCategory(n: number, _locale?: string): PluralCategory {
9
+ if (n === 1) return "one";
10
+ return "other";
11
+ }
12
+
13
+ interface ParsedBlock {
14
+ branches: Record<string, string>;
15
+ type: "plural" | "select";
16
+ varName: string;
17
+ }
18
+
19
+ interface ParsedNumber {
20
+ type: "number";
21
+ varName: string;
22
+ }
23
+
24
+ interface ParsedSimple {
25
+ type: "simple";
26
+ varName: string;
27
+ }
28
+
29
+ type ParsedToken = ParsedBlock | ParsedNumber | ParsedSimple | string;
30
+
31
+ function findMatchingBrace(str: string, start: number): number {
32
+ let depth = 0;
33
+ for (let i = start; i < str.length; i++) {
34
+ if (str[i] === "{") depth++;
35
+ else if (str[i] === "}") {
36
+ depth--;
37
+ if (depth === 0) return i;
38
+ }
39
+ }
40
+ return -1;
41
+ }
42
+
43
+ function parseBranches(content: string): Record<string, string> {
44
+ const branches: Record<string, string> = {};
45
+ let i = 0;
46
+ while (i < content.length) {
47
+ /* skip whitespace */
48
+ while (i < content.length && /\s/.test(content[i] ?? "")) i++;
49
+ if (i >= content.length) break;
50
+
51
+ /* read category name (e.g. "one", "other", "=0") */
52
+ let category = "";
53
+ while (i < content.length && content[i] !== "{" && !/\s/.test(content[i] ?? "")) {
54
+ category += content[i];
55
+ i++;
56
+ }
57
+ if (!category) break;
58
+
59
+ /* skip whitespace before { */
60
+ while (i < content.length && /\s/.test(content[i] ?? "")) i++;
61
+ if (i >= content.length || content[i] !== "{") break;
62
+
63
+ /* find matching } */
64
+ const end = findMatchingBrace(content, i);
65
+ if (end === -1) break;
66
+
67
+ branches[category] = content.slice(i + 1, end);
68
+ i = end + 1;
69
+ }
70
+ return branches;
71
+ }
72
+
73
+ function tokenize(message: string): ParsedToken[] {
74
+ const tokens: ParsedToken[] = [];
75
+ let i = 0;
76
+
77
+ while (i < message.length) {
78
+ const braceIdx = message.indexOf("{", i);
79
+ if (braceIdx === -1) {
80
+ tokens.push(message.slice(i));
81
+ break;
82
+ }
83
+
84
+ if (braceIdx > i) {
85
+ tokens.push(message.slice(i, braceIdx));
86
+ }
87
+
88
+ const endBrace = findMatchingBrace(message, braceIdx);
89
+ if (endBrace === -1) {
90
+ tokens.push(message.slice(braceIdx));
91
+ break;
92
+ }
93
+
94
+ const inner = message.slice(braceIdx + 1, endBrace);
95
+ const commaIdx = inner.indexOf(",");
96
+
97
+ if (commaIdx === -1) {
98
+ /* simple interpolation: {varName} */
99
+ tokens.push({ type: "simple", varName: inner.trim() });
100
+ } else {
101
+ const varName = inner.slice(0, commaIdx).trim();
102
+ const rest = inner.slice(commaIdx + 1).trim();
103
+ const secondComma = rest.indexOf(",");
104
+
105
+ if (secondComma === -1) {
106
+ /* {var, number} or similar */
107
+ const formatType = rest.trim();
108
+ if (formatType === "number") {
109
+ tokens.push({ type: "number", varName });
110
+ } else {
111
+ tokens.push({ type: "simple", varName });
112
+ }
113
+ } else {
114
+ /* {var, plural/select, branches} */
115
+ const formatType = rest.slice(0, secondComma).trim();
116
+ const branchContent = rest.slice(secondComma + 1).trim();
117
+ const branches = parseBranches(branchContent);
118
+
119
+ if (formatType === "plural" || formatType === "select") {
120
+ tokens.push({ branches, type: formatType, varName });
121
+ } else {
122
+ tokens.push({ type: "simple", varName });
123
+ }
124
+ }
125
+ }
126
+
127
+ i = endBrace + 1;
128
+ }
129
+
130
+ return tokens;
131
+ }
132
+
133
+ function resolveToken(token: ParsedToken, values: Record<string, unknown>, locale?: string): string {
134
+ if (typeof token === "string") return token;
135
+
136
+ if (token.type === "simple") {
137
+ const val = values[token.varName];
138
+ return val !== undefined && val !== null ? String(val) : `{${token.varName}}`;
139
+ }
140
+
141
+ if (token.type === "number") {
142
+ const val = values[token.varName];
143
+ if (val === undefined || val === null) return `{${token.varName}}`;
144
+ try {
145
+ return new Intl.NumberFormat(locale).format(Number(val));
146
+ } catch {
147
+ return String(val);
148
+ }
149
+ }
150
+
151
+ /* plural or select */
152
+ const val = values[token.varName];
153
+
154
+ if (token.type === "plural") {
155
+ const num = Number(val ?? 0);
156
+ const exactKey = `=${num}`;
157
+ const category = getPluralCategory(num, locale);
158
+ const template = token.branches[exactKey] ?? token.branches[category] ?? token.branches.other ?? "";
159
+ const resolved = template.replace(/#/g, String(num));
160
+ return formatMessage(resolved, values, locale);
161
+ }
162
+
163
+ /* select */
164
+ const strVal = val !== undefined && val !== null ? String(val) : "";
165
+ const template = token.branches[strVal] ?? token.branches.other ?? "";
166
+ return formatMessage(template, values, locale);
167
+ }
168
+
169
+ export function formatMessage(message: string, values?: Record<string, unknown>, locale?: string): string {
170
+ if (!message) return message;
171
+ const safeValues = values ?? {};
172
+ const tokens = tokenize(message);
173
+ return tokens.map((t) => resolveToken(t, safeValues, locale)).join("");
174
+ }