@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,24 @@
1
+ import type { FlareTracer } from "../tracing/types.ts";
2
+
3
+ export interface TracingConfig {
4
+ provider?: FlareTracer;
5
+ timing?: boolean;
6
+ }
7
+
8
+ export interface CspDirectives {
9
+ "base-uri"?: string[];
10
+ "connect-src"?: string[];
11
+ "default-src"?: string[];
12
+ "font-src"?: string[];
13
+ "form-action"?: string[];
14
+ "frame-ancestors"?: string[];
15
+ "frame-src"?: string[];
16
+ "img-src"?: string[];
17
+ "media-src"?: string[];
18
+ "object-src"?: string[];
19
+ "script-src"?: string[];
20
+ "style-src"?: string[];
21
+ "block-all-mixed-content"?: boolean;
22
+ "upgrade-insecure-requests"?: boolean;
23
+ "worker-src"?: string[];
24
+ }
@@ -0,0 +1,130 @@
1
+ import type { ResolvedRoute } from "../loader-pipeline/index.ts";
2
+ import type { CacheConfig } from "../route-builder/types.ts";
3
+
4
+ type ParamsFn = (ctx: { params: Record<string, string | string[]> }) => unknown;
5
+
6
+ /**
7
+ * Extract params fn from a route's cache config.
8
+ * Handles: `ssg: fn`, `ssg: { params: fn }`, `isr: { params: fn }`
9
+ */
10
+ export function extractParamsFn(cache: CacheConfig | undefined): ParamsFn | undefined {
11
+ if (!cache) return undefined;
12
+
13
+ const ssg = cache.ssg;
14
+ if (typeof ssg === "function") return ssg as ParamsFn;
15
+ if (ssg && typeof ssg === "object") {
16
+ const params = (ssg as Record<string, unknown>).params;
17
+ if (typeof params === "function") return params as ParamsFn;
18
+ }
19
+
20
+ const isr = cache.isr;
21
+ if (isr && typeof isr === "object") {
22
+ const params = (isr as Record<string, unknown>).params;
23
+ if (typeof params === "function") return params as ParamsFn;
24
+ }
25
+
26
+ return undefined;
27
+ }
28
+
29
+ /**
30
+ * Determine whether a cache config requires strict param validation.
31
+ * - ssg with params fn → always validate
32
+ * - isr with params fn + dynamicParams: false → validate
33
+ * - everything else → skip
34
+ */
35
+ function shouldValidateParams(cache: CacheConfig | undefined): boolean {
36
+ if (!cache) return false;
37
+
38
+ const ssg = cache.ssg;
39
+ if (typeof ssg === "function") return true;
40
+ if (ssg && typeof ssg === "object" && "params" in ssg) return true;
41
+
42
+ const isr = cache.isr;
43
+ if (isr && typeof isr === "object" && "params" in isr) {
44
+ const dynamicParams = (isr as Record<string, unknown>).dynamicParams ?? true;
45
+ return dynamicParams === false;
46
+ }
47
+
48
+ return false;
49
+ }
50
+
51
+ /*
52
+ * Production cache: caches params fn results per virtualPath+matchParams.
53
+ * Skipped in dev mode so route file edits take effect without restart —
54
+ * layout modules are loaded via dynamic imports that Vite invalidates on
55
+ * file change, but this module's state persists across those invalidations.
56
+ *
57
+ * Bounded to MAX_PARAMS_CACHE_SIZE with FIFO eviction to prevent unbounded
58
+ * memory growth in production with many unique URL param combinations.
59
+ */
60
+ const MAX_PARAMS_CACHE_SIZE = 500;
61
+ const paramsCache = new Map<string, Record<string, string | string[]>[]>();
62
+
63
+ export function clearParamsCache(): void {
64
+ paramsCache.clear();
65
+ }
66
+
67
+ /**
68
+ * Validate that the matched URL params are within the allowed set
69
+ * defined by SSG/ISR params functions in the route chain.
70
+ *
71
+ * Returns `false` if any route in the chain rejects the params.
72
+ *
73
+ * In dev mode, params fn results are NOT cached so edits to route files
74
+ * (e.g. changing params lists) take effect immediately without restart.
75
+ */
76
+ export async function validateStaticParams(
77
+ resolvedRoutes: ResolvedRoute[],
78
+ matchParams: Record<string, string | string[]>,
79
+ isDev?: boolean,
80
+ ): Promise<boolean> {
81
+ for (const route of resolvedRoutes) {
82
+ if (!shouldValidateParams(route.cache)) continue;
83
+
84
+ const paramsFn = extractParamsFn(route.cache);
85
+ if (!paramsFn) continue;
86
+
87
+ /* Cache key includes matchParams because params fns can depend on parent
88
+ * params (e.g. repoSegment reads ctx.params.org to filter repos). */
89
+ const cacheKey = `${route.virtualPath}:${JSON.stringify(matchParams, Object.keys(matchParams).sort())}`;
90
+ let allowedList = isDev ? undefined : paramsCache.get(cacheKey);
91
+ if (!allowedList) {
92
+ const produced = await paramsFn({ params: matchParams });
93
+ allowedList = Array.isArray(produced) ? (produced as Record<string, string | string[]>[]) : [];
94
+ if (!isDev) {
95
+ if (paramsCache.size >= MAX_PARAMS_CACHE_SIZE) {
96
+ const oldest = paramsCache.keys().next().value;
97
+ if (oldest !== undefined) paramsCache.delete(oldest);
98
+ }
99
+ paramsCache.set(cacheKey, allowedList);
100
+ }
101
+ }
102
+
103
+ if (allowedList.length === 0) return false;
104
+
105
+ /* Extract which param keys this level defines */
106
+ const paramKeys = Object.keys(allowedList[0] ?? {});
107
+ if (paramKeys.length === 0) continue;
108
+
109
+ /* Check if matchParams values exist in the allowed list */
110
+ const matched = allowedList.some((allowed) =>
111
+ paramKeys.every((key) => {
112
+ const matchVal = matchParams[key];
113
+ const allowedVal = allowed[key];
114
+ /* Optional param [[x]] skipped — not in matchParams → skip validation */
115
+ if (matchVal === undefined) return true;
116
+ if (allowedVal === undefined) return false;
117
+ if (Array.isArray(matchVal) && Array.isArray(allowedVal)) {
118
+ if (matchVal.length !== allowedVal.length) return false;
119
+ return matchVal.every((v, i) => v === allowedVal[i]);
120
+ }
121
+ if (Array.isArray(matchVal) || Array.isArray(allowedVal)) return false;
122
+ return String(matchVal) === String(allowedVal);
123
+ }),
124
+ );
125
+
126
+ if (!matched) return false;
127
+ }
128
+
129
+ return true;
130
+ }
package/src/server.ts ADDED
@@ -0,0 +1,2 @@
1
+ /* test stub */
2
+ export {};
@@ -0,0 +1,153 @@
1
+ export interface SwTemplateConfig {
2
+ /** URL prefix for cache-first asset matching. Defaults to `"/assets"`. */
3
+ assetsBase?: string;
4
+ offlineFallback: string | null;
5
+ runtimeCacheMax: number;
6
+ skipWaiting: boolean;
7
+ }
8
+
9
+ export function generateSwSource(precacheManifest: string[], buildId: string, config: SwTemplateConfig): string {
10
+ const manifest = JSON.stringify(precacheManifest);
11
+ const assetsBase = config.assetsBase ?? "/assets";
12
+ const swConfig = JSON.stringify({
13
+ assetsBase,
14
+ offlineFallback: config.offlineFallback,
15
+ runtimeCacheMax: config.runtimeCacheMax,
16
+ skipWaiting: config.skipWaiting,
17
+ });
18
+
19
+ return `/* Flare Service Worker — generated at build time */
20
+ var PRECACHE_MANIFEST = ${manifest}
21
+ var SW_CONFIG = ${swConfig}
22
+ var BUILD_ID = "${buildId}"
23
+ var CACHE_NAME = "flare-assets-${buildId}"
24
+ var RUNTIME_CACHE = "flare-runtime-v1"
25
+
26
+ /* ── Install ─────────────────────────────────────────────────────── */
27
+
28
+ self.addEventListener("install", function (event) {
29
+ event.waitUntil(
30
+ caches.open(CACHE_NAME).then(function (cache) {
31
+ var promises = [cache.addAll(PRECACHE_MANIFEST)]
32
+ if (SW_CONFIG.offlineFallback) {
33
+ promises.push(
34
+ caches.open(RUNTIME_CACHE).then(function (rtCache) {
35
+ return fetch(SW_CONFIG.offlineFallback).then(function (res) {
36
+ if (res.ok) return rtCache.put(SW_CONFIG.offlineFallback, res)
37
+ }).catch(function () {})
38
+ })
39
+ )
40
+ }
41
+ return Promise.all(promises)
42
+ }).then(function () {
43
+ if (SW_CONFIG.skipWaiting) self.skipWaiting()
44
+ }).catch(function (err) {
45
+ /* Install failed — old SW stays active. Log for debugging. */
46
+ console.error("[flare-sw] install failed:", err)
47
+ })
48
+ )
49
+ })
50
+
51
+ /* ── Activate ────────────────────────────────────────────────────── */
52
+
53
+ self.addEventListener("activate", function (event) {
54
+ event.waitUntil(
55
+ Promise.all([
56
+ self.registration.navigationPreload && self.registration.navigationPreload.enable(),
57
+ caches.keys().then(function (names) {
58
+ return Promise.all(
59
+ names.filter(function (n) {
60
+ return n.startsWith("flare-assets-") && n !== CACHE_NAME
61
+ }).map(function (n) {
62
+ return caches.delete(n)
63
+ })
64
+ )
65
+ }),
66
+ self.clients.claim(),
67
+ ])
68
+ )
69
+ })
70
+
71
+ /* ── Message ─────────────────────────────────────────────────────── */
72
+
73
+ self.addEventListener("message", function (event) {
74
+ if (event.data && event.data.type === "SKIP_WAITING") {
75
+ self.skipWaiting()
76
+ }
77
+ })
78
+
79
+ /* ── Fetch ───────────────────────────────────────────────────────── */
80
+
81
+ self.addEventListener("fetch", function (event) {
82
+ var url = new URL(event.request.url)
83
+
84
+ /* Only handle same-origin */
85
+ if (url.origin !== self.location.origin) return
86
+
87
+ /* Passthrough: NDJSON (x-d header), server functions, keepalive */
88
+ if (event.request.headers.has("x-d")) return
89
+ if (url.pathname.startsWith("/_fn/")) return
90
+ if (url.pathname === "/_flare/keepalive") return
91
+
92
+ /* Cache-first for hashed assets under the configured assetsBase */
93
+ if (url.pathname.startsWith(${JSON.stringify(`${assetsBase}/`)})) {
94
+ event.respondWith(
95
+ caches.match(event.request).then(function (cached) {
96
+ if (cached) return cached
97
+ return fetch(event.request).then(function (response) {
98
+ if (response.ok) {
99
+ var clone = response.clone()
100
+ caches.open(CACHE_NAME).then(function (cache) {
101
+ cache.put(event.request, clone)
102
+ }).catch(function () {})
103
+ }
104
+ return response
105
+ })
106
+ }).catch(function () {
107
+ /* Cache API error — fall through to network */
108
+ return fetch(event.request)
109
+ })
110
+ )
111
+ return
112
+ }
113
+
114
+ /* Network-first for navigations */
115
+ if (event.request.mode === "navigate") {
116
+ event.respondWith(
117
+ (function () {
118
+ var preload = event.preloadResponse || Promise.resolve(undefined)
119
+ return preload.then(function (preloaded) {
120
+ if (preloaded) return preloaded
121
+ return fetch(event.request)
122
+ }).then(function (response) {
123
+ if (response.ok) {
124
+ var clone = response.clone()
125
+ caches.open(RUNTIME_CACHE).then(function (cache) {
126
+ cache.put(event.request, clone).catch(function () {})
127
+ /* LRU eviction — batch delete to stay under limit */
128
+ cache.keys().then(function (keys) {
129
+ var i = 0
130
+ while (keys.length - i > SW_CONFIG.runtimeCacheMax) {
131
+ cache.delete(keys[i])
132
+ i++
133
+ }
134
+ })
135
+ }).catch(function () {})
136
+ }
137
+ return response
138
+ }).catch(function () {
139
+ return caches.match(event.request).then(function (cached) {
140
+ if (cached) return cached
141
+ if (SW_CONFIG.offlineFallback) {
142
+ return caches.match(SW_CONFIG.offlineFallback)
143
+ }
144
+ return undefined
145
+ })
146
+ })
147
+ })()
148
+ )
149
+ return
150
+ }
151
+ })
152
+ `;
153
+ }
@@ -0,0 +1,70 @@
1
+ import { createSignal, onCleanup } from "solid-js";
2
+
3
+ export interface ServiceWorkerState {
4
+ update: () => void;
5
+ updateAvailable: () => boolean;
6
+ }
7
+
8
+ export function useServiceWorker(): ServiceWorkerState {
9
+ const [updateAvailable, setUpdateAvailable] = createSignal(false);
10
+ let waitingWorker: ServiceWorker | null = null;
11
+
12
+ if ("serviceWorker" in navigator) {
13
+ const sw = navigator.serviceWorker;
14
+ const trackedListeners: Array<{
15
+ handler: () => void;
16
+ name: string;
17
+ target: { removeEventListener: (name: string, handler: () => void) => void };
18
+ }> = [];
19
+
20
+ const onControllerChange = () => {
21
+ window.location.reload();
22
+ };
23
+
24
+ sw.addEventListener("controllerchange", onControllerChange);
25
+
26
+ onCleanup(() => {
27
+ sw.removeEventListener("controllerchange", onControllerChange);
28
+ for (const entry of trackedListeners) {
29
+ entry.target.removeEventListener(entry.name, entry.handler);
30
+ }
31
+ });
32
+
33
+ sw.ready.then((registration) => {
34
+ const checkWaiting = (worker: ServiceWorker | null) => {
35
+ if (!worker) return;
36
+ if (worker.state === "installed") {
37
+ waitingWorker = worker;
38
+ setUpdateAvailable(true);
39
+ return;
40
+ }
41
+ const handler = () => {
42
+ if (worker.state === "installed") {
43
+ waitingWorker = worker;
44
+ setUpdateAvailable(true);
45
+ }
46
+ };
47
+ worker.addEventListener("statechange", handler);
48
+ trackedListeners.push({ handler, name: "statechange", target: worker });
49
+ };
50
+
51
+ checkWaiting(registration.waiting);
52
+ checkWaiting(registration.installing);
53
+
54
+ const onUpdateFound = () => {
55
+ checkWaiting(registration.installing);
56
+ };
57
+ registration.addEventListener("updatefound", onUpdateFound);
58
+ trackedListeners.push({ handler: onUpdateFound, name: "updatefound", target: registration });
59
+ });
60
+ }
61
+
62
+ return {
63
+ update() {
64
+ if (waitingWorker) {
65
+ waitingWorker.postMessage({ type: "SKIP_WAITING" });
66
+ }
67
+ },
68
+ updateAvailable,
69
+ };
70
+ }
@@ -0,0 +1,231 @@
1
+ import type { RouteDefinition } from "../generators/index.ts";
2
+
3
+ /* ── Types ────────────────────────────────────────────────────────────── */
4
+
5
+ export type ChangeFreq = "always" | "daily" | "hourly" | "monthly" | "never" | "weekly" | "yearly";
6
+
7
+ export interface SitemapEntry {
8
+ changefreq?: ChangeFreq;
9
+ lastmod?: string;
10
+ loc: string;
11
+ priority?: number;
12
+ }
13
+
14
+ export interface SitemapConfig {
15
+ additionalEntries?: SitemapEntry[];
16
+ changefreq?: ChangeFreq | Record<string, ChangeFreq>;
17
+ exclude?: string[];
18
+ origin: string;
19
+ priority?: number | Record<string, number>;
20
+ }
21
+
22
+ export interface SitemapResult {
23
+ files: Array<{ content: string; path: string }>;
24
+ urls: string[];
25
+ }
26
+
27
+ /* ── Glob matching ────────────────────────────────────────────────────── */
28
+
29
+ function globToRegex(pattern: string): RegExp {
30
+ let result = "^";
31
+ let i = 0;
32
+ while (i < pattern.length) {
33
+ if (pattern[i] === "*" && pattern[i + 1] === "*") {
34
+ result += ".*";
35
+ i += 2;
36
+ if (pattern[i] === "/") i++;
37
+ } else if (pattern[i] === "*") {
38
+ result += "[^/]*";
39
+ i++;
40
+ } else if (".+?^${}()|[]\\".includes(pattern[i] ?? "")) {
41
+ result += `\\${pattern[i]}`;
42
+ i++;
43
+ } else {
44
+ result += pattern[i];
45
+ i++;
46
+ }
47
+ }
48
+ result += "$";
49
+ return new RegExp(result);
50
+ }
51
+
52
+ /* ── URL computation (mirrors generators/index.ts computeUrlPattern) ── */
53
+
54
+ function computeUrlPattern(virtualPath: string): string {
55
+ const parts = virtualPath.split("/");
56
+ const rootIdx = parts.findIndex((p) => p.startsWith("_") && p.endsWith("_") && p.length >= 3);
57
+ const urlParts: string[] = [];
58
+
59
+ for (let i = 0; i < parts.length; i++) {
60
+ const part = parts[i] ?? "";
61
+ if (rootIdx >= 0 && i <= rootIdx) continue;
62
+ if (part.startsWith("(") && part.endsWith(")")) continue;
63
+ if (part === "") continue;
64
+ urlParts.push(part);
65
+ }
66
+
67
+ if (urlParts.length === 0) return "/";
68
+ return `/${urlParts.join("/")}`;
69
+ }
70
+
71
+ /* ── Dynamic param detection ──────────────────────────────────────────── */
72
+
73
+ const DYNAMIC_PARAM_RE = /\[.*\]/;
74
+
75
+ function hasDynamicParams(virtualPath: string): boolean {
76
+ return DYNAMIC_PARAM_RE.test(virtualPath);
77
+ }
78
+
79
+ /* ── Route filtering ──────────────────────────────────────────────────── */
80
+
81
+ export function filterSitemapRoutes(defs: RouteDefinition[], exclude?: string[]): RouteDefinition[] {
82
+ const excludePatterns = exclude?.map(globToRegex) ?? [];
83
+
84
+ return defs.filter((def) => {
85
+ if (def.type !== "page") return false;
86
+ if (def.responseRoute) return false;
87
+ if (def.authenticateMode === true) return false;
88
+ if (hasDynamicParams(def.virtualPath)) return false;
89
+
90
+ const url = computeUrlPattern(def.virtualPath);
91
+ for (const pattern of excludePatterns) {
92
+ if (pattern.test(url)) return false;
93
+ }
94
+
95
+ return true;
96
+ });
97
+ }
98
+
99
+ /* ── Entry building ───────────────────────────────────────────────────── */
100
+
101
+ function resolveOverride<T>(url: string, value: T | Record<string, T> | undefined): T | undefined {
102
+ if (value === undefined) return undefined;
103
+ if (typeof value !== "object" || value === null) return value as T;
104
+
105
+ const overrides = value as Record<string, T>;
106
+ let bestMatch: { key: string; value: T } | undefined;
107
+
108
+ for (const [pattern, val] of Object.entries(overrides)) {
109
+ const re = globToRegex(pattern);
110
+ if (re.test(url)) {
111
+ if (!bestMatch || pattern.length > bestMatch.key.length) {
112
+ bestMatch = { key: pattern, value: val };
113
+ }
114
+ }
115
+ }
116
+
117
+ return bestMatch?.value;
118
+ }
119
+
120
+ export function buildSitemapEntries(defs: RouteDefinition[], config: SitemapConfig): SitemapEntry[] {
121
+ const entries: SitemapEntry[] = [];
122
+ const origin = config.origin.replace(/\/+$/, "");
123
+
124
+ for (const def of defs) {
125
+ const url = computeUrlPattern(def.virtualPath);
126
+ const entry: SitemapEntry = { loc: `${origin}${url}` };
127
+
128
+ const freq = resolveOverride(url, config.changefreq);
129
+ if (freq) entry.changefreq = freq;
130
+
131
+ const prio = resolveOverride(url, config.priority);
132
+ if (prio !== undefined) entry.priority = prio;
133
+
134
+ entries.push(entry);
135
+ }
136
+
137
+ if (config.additionalEntries) {
138
+ entries.push(...config.additionalEntries);
139
+ }
140
+
141
+ return entries;
142
+ }
143
+
144
+ /* ── XML generation ───────────────────────────────────────────────────── */
145
+
146
+ function escapeXml(str: string): string {
147
+ return str
148
+ .replace(/&/g, "&amp;")
149
+ .replace(/</g, "&lt;")
150
+ .replace(/>/g, "&gt;")
151
+ .replace(/"/g, "&quot;")
152
+ .replace(/'/g, "&apos;");
153
+ }
154
+
155
+ export function generateSitemapXml(entries: SitemapEntry[]): string {
156
+ const lines = [
157
+ '<?xml version="1.0" encoding="UTF-8"?>',
158
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
159
+ ];
160
+
161
+ for (const entry of entries) {
162
+ lines.push(" <url>");
163
+ lines.push(` <loc>${escapeXml(entry.loc)}</loc>`);
164
+ if (entry.lastmod) lines.push(` <lastmod>${escapeXml(entry.lastmod)}</lastmod>`);
165
+ if (entry.changefreq) lines.push(` <changefreq>${escapeXml(entry.changefreq)}</changefreq>`);
166
+ if (entry.priority !== undefined) lines.push(` <priority>${entry.priority}</priority>`);
167
+ lines.push(" </url>");
168
+ }
169
+
170
+ lines.push("</urlset>");
171
+ return lines.join("\n");
172
+ }
173
+
174
+ export function generateSitemapIndexXml(origin: string, count: number): string {
175
+ const lines = [
176
+ '<?xml version="1.0" encoding="UTF-8"?>',
177
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
178
+ ];
179
+
180
+ for (let i = 0; i < count; i++) {
181
+ lines.push(" <sitemap>");
182
+ lines.push(` <loc>${escapeXml(origin)}/sitemap-${i}.xml</loc>`);
183
+ lines.push(" </sitemap>");
184
+ }
185
+
186
+ lines.push("</sitemapindex>");
187
+ return lines.join("\n");
188
+ }
189
+
190
+ /* ── Full pipeline ────────────────────────────────────────────────────── */
191
+
192
+ const MAX_SITEMAP_ENTRIES = 50_000;
193
+
194
+ export function generateSitemap(config: SitemapConfig, entries: SitemapEntry[]): SitemapResult {
195
+ const urls = entries.map((e) => e.loc);
196
+
197
+ if (entries.length <= MAX_SITEMAP_ENTRIES) {
198
+ return {
199
+ files: [{ content: generateSitemapXml(entries), path: "sitemap.xml" }],
200
+ urls,
201
+ };
202
+ }
203
+
204
+ const files: Array<{ content: string; path: string }> = [];
205
+ const partCount = Math.ceil(entries.length / MAX_SITEMAP_ENTRIES);
206
+
207
+ for (let i = 0; i < partCount; i++) {
208
+ const start = i * MAX_SITEMAP_ENTRIES;
209
+ const chunk = entries.slice(start, start + MAX_SITEMAP_ENTRIES);
210
+ files.push({ content: generateSitemapXml(chunk), path: `sitemap-${i}.xml` });
211
+ }
212
+
213
+ files.push({ content: generateSitemapIndexXml(config.origin, partCount), path: "sitemap.xml" });
214
+
215
+ return { files, urls };
216
+ }
217
+
218
+ /* ── robots.txt ───────────────────────────────────────────────────────── */
219
+
220
+ export function generateRobotsTxt(sitemapUrl: string, rules?: string): string {
221
+ const base = rules ?? "User-agent: *\nAllow: /";
222
+ return `${base}\n\nSitemap: ${sitemapUrl}\n`;
223
+ }
224
+
225
+ /* ── Convenience: filter + build + generate ───────────────────────────── */
226
+
227
+ export function buildSitemapFromDefs(defs: RouteDefinition[], config: SitemapConfig): SitemapResult {
228
+ const filtered = filterSitemapRoutes(defs, config.exclude);
229
+ const entries = buildSitemapEntries(filtered, config);
230
+ return generateSitemap(config, entries);
231
+ }