@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,14 @@
1
+ import type { ClassValue, Sx } from "../styles/sx-types";
2
+
3
+ declare module "solid-js" {
4
+ namespace JSX {
5
+ interface HTMLAttributes<T> {
6
+ sx?: Sx;
7
+ class?: string | ClassValue[];
8
+ }
9
+ interface CoreSVGAttributes<T> {
10
+ sx?: Sx;
11
+ class?: string | ClassValue[];
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,240 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join, resolve } from "node:path";
4
+
5
+ export interface TailwindCompiler {
6
+ build: (classes: string[]) => string;
7
+ themeVars: Map<string, string>;
8
+ }
9
+
10
+ /**
11
+ * Tokens Tailwind expresses as literal class selectors for descendants to target.
12
+ * Must land on the DOM as a real `class=` attribute.
13
+ */
14
+ const MARKER_TOKEN_RE = /^(?:group|peer)(?:\/[\w-]+)?$/;
15
+
16
+ export function splitTokens(classes: string): { markers: string[]; utilities: string } {
17
+ const markers: string[] = [];
18
+ const utilities: string[] = [];
19
+ for (const tok of classes.split(/\s+/).filter(Boolean)) {
20
+ if (MARKER_TOKEN_RE.test(tok)) markers.push(tok);
21
+ else utilities.push(tok);
22
+ }
23
+ return { markers, utilities: utilities.join(" ") };
24
+ }
25
+
26
+ function extractPseudo(selector: string): string | null {
27
+ for (let i = selector.length - 1; i >= 0; i--) {
28
+ if (selector[i] === ":" && (i === 0 || selector[i - 1] !== "\\")) {
29
+ return selector.slice(i);
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+
35
+ function cssEscapeClass(cls: string): string {
36
+ return cls.replace(/([^a-zA-Z0-9_-])/g, "\\$1");
37
+ }
38
+
39
+ function selectorMatchesAny(selector: string, prefixes: Set<string>): boolean {
40
+ for (const prefix of prefixes) {
41
+ if (
42
+ selector === prefix ||
43
+ selector.startsWith(`${prefix}:`) ||
44
+ selector.startsWith(`${prefix} `) ||
45
+ selector.startsWith(`${prefix},`)
46
+ ) {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+
53
+ function extractLayerContent(css: string, atStart: number): string {
54
+ const braceStart = css.indexOf("{", atStart);
55
+ if (braceStart === -1) return "";
56
+ let depth = 1;
57
+ let i = braceStart + 1;
58
+ for (; i < css.length; i++) {
59
+ if (css[i] === "{") depth++;
60
+ else if (css[i] === "}") {
61
+ depth--;
62
+ if (depth === 0) break;
63
+ }
64
+ }
65
+ return css.slice(braceStart + 1, i).trim();
66
+ }
67
+
68
+ function extractDeclsInner(css: string, selectorSet?: Set<string>): string {
69
+ const result: string[] = [];
70
+ let remaining = css.trim();
71
+ while (remaining.length > 0) {
72
+ remaining = remaining.trim();
73
+ if (remaining.length === 0) break;
74
+
75
+ if (remaining.startsWith("@")) {
76
+ const braceStart = remaining.indexOf("{");
77
+ if (braceStart === -1) break;
78
+ const atRule = remaining.slice(0, braceStart).trim();
79
+ let depth = 1;
80
+ let i = braceStart + 1;
81
+ for (; i < remaining.length; i++) {
82
+ if (remaining[i] === "{") depth++;
83
+ else if (remaining[i] === "}") {
84
+ depth--;
85
+ if (depth === 0) break;
86
+ }
87
+ }
88
+ const inner = remaining.slice(braceStart + 1, i).trim();
89
+ const innerDecls = extractDeclsInner(inner, selectorSet);
90
+ if (innerDecls.length > 0) {
91
+ result.push(`${atRule} { ${innerDecls} }`);
92
+ }
93
+ remaining = remaining.slice(i + 1).trim();
94
+ continue;
95
+ }
96
+
97
+ const braceStart = remaining.indexOf("{");
98
+ if (braceStart === -1) break;
99
+ const selector = remaining.slice(0, braceStart).trim();
100
+ let depth = 1;
101
+ let i = braceStart + 1;
102
+ for (; i < remaining.length; i++) {
103
+ if (remaining[i] === "{") depth++;
104
+ else if (remaining[i] === "}") {
105
+ depth--;
106
+ if (depth === 0) break;
107
+ }
108
+ }
109
+ const body = remaining.slice(braceStart + 1, i).trim();
110
+ const matchesFilter = !selectorSet || selectorMatchesAny(selector, selectorSet);
111
+ if (matchesFilter && body.length > 0) {
112
+ const pseudo = extractPseudo(selector);
113
+ if (pseudo) {
114
+ result.push(`&${pseudo} { ${body} }`);
115
+ } else {
116
+ result.push(body);
117
+ }
118
+ }
119
+ remaining = remaining.slice(i + 1).trim();
120
+ }
121
+ return result.join(";");
122
+ }
123
+
124
+ function resolveThemeVars(css: string, themeVars: Map<string, string>): string {
125
+ let result = css;
126
+ for (let i = 0; i < 5; i++) {
127
+ const next = result.replace(/var\((--[\w-]+)\)/g, (full, name: string) => {
128
+ return themeVars.get(name) ?? full;
129
+ });
130
+ if (next === result) break;
131
+ result = next;
132
+ }
133
+ return result;
134
+ }
135
+
136
+ /**
137
+ * Returns the full Tailwind preamble from a zero-class build output — everything
138
+ * except the `@layer utilities` block. Captures theme vars and preflight so
139
+ * browser defaults are normalized even when no utility classes are present.
140
+ */
141
+ export function extractPrefaceCss(cssOutput: string): string {
142
+ const stripped = cssOutput.replace(/\/\*[\s\S]*?\*\//g, "").trim();
143
+ /* Strip the utilities layer entirely; keep theme + base + components. */
144
+ const utilMatch = stripped.match(/@layer\s+utilities\s*\{/);
145
+ if (!utilMatch || utilMatch.index === undefined) return stripped;
146
+ const beforeUtil = stripped.slice(0, utilMatch.index).trim();
147
+ const afterUtil = (() => {
148
+ const braceStart = stripped.indexOf("{", utilMatch.index);
149
+ if (braceStart === -1) return "";
150
+ let depth = 1;
151
+ let i = braceStart + 1;
152
+ for (; i < stripped.length; i++) {
153
+ if (stripped[i] === "{") depth++;
154
+ else if (stripped[i] === "}") {
155
+ depth--;
156
+ if (depth === 0) break;
157
+ }
158
+ }
159
+ return stripped.slice(i + 1).trim();
160
+ })();
161
+ return [beforeUtil, afterUtil].filter(Boolean).join("\n").trim();
162
+ }
163
+
164
+ export function extractDeclarations(
165
+ cssOutput: string,
166
+ requestedClasses: string[],
167
+ themeVars?: Map<string, string>,
168
+ ): string {
169
+ const stripped = cssOutput.replace(/\/\*[\s\S]*?\*\//g, "").trim();
170
+ const utilMatch = stripped.match(/@layer\s+utilities\s*\{/);
171
+ const toParse = utilMatch ? extractLayerContent(stripped, utilMatch.index ?? 0) : stripped;
172
+ const selectorSet = new Set(requestedClasses.map((c) => `.${cssEscapeClass(c)}`));
173
+ let raw = extractDeclsInner(toParse, selectorSet);
174
+ if (themeVars) {
175
+ raw = resolveThemeVars(raw, themeVars);
176
+ }
177
+ return raw.replace(/\s+/g, " ").trim();
178
+ }
179
+
180
+ /** Initialize a Tailwind v4 compiler from an optional CSS entry file. */
181
+ export async function initTailwindCompiler(cssPath?: string): Promise<TailwindCompiler> {
182
+ try {
183
+ const tw = await import("tailwindcss");
184
+ const compileFn = tw.compile ?? (tw.default as { compile?: unknown })?.compile;
185
+ if (typeof compileFn !== "function") {
186
+ throw new Error(
187
+ "tailwindcss compile function not found. Ensure tailwindcss ^4.0 is installed: bun add tailwindcss@latest",
188
+ );
189
+ }
190
+
191
+ let cssContent: string;
192
+ if (cssPath) {
193
+ cssContent = readFileSync(resolve(cssPath), "utf-8");
194
+ } else {
195
+ cssContent = '@import "tailwindcss";';
196
+ }
197
+
198
+ const compiler = await (
199
+ compileFn as (
200
+ css: string,
201
+ opts?: unknown,
202
+ ) => Promise<{
203
+ build: (classes: string[]) => string;
204
+ }>
205
+ )(cssContent, {
206
+ loadStylesheet: (id: string, base: string) => {
207
+ if (id === "tailwindcss") {
208
+ const esmRequire = createRequire(import.meta.url);
209
+ const pkgPath = esmRequire.resolve("tailwindcss/package.json");
210
+ const pkgDir = dirname(pkgPath);
211
+ const cssPath2 = join(pkgDir, "index.css");
212
+ const content = readFileSync(cssPath2, "utf-8");
213
+ return { base: pkgDir, content, path: cssPath2 };
214
+ }
215
+ const resolved = resolve(base, id);
216
+ const content = readFileSync(resolved, "utf-8");
217
+ return { base: dirname(resolved), content, path: resolved };
218
+ },
219
+ });
220
+
221
+ const themeVars = new Map<string, string>();
222
+ const originalBuild = compiler.build.bind(compiler);
223
+ const trackingBuild = (classes: string[]): string => {
224
+ const output = originalBuild(classes);
225
+ for (const m of output.matchAll(/(--[\w-]+)\s*:\s*([^;]+)/g)) {
226
+ if (!themeVars.has(m[1])) {
227
+ themeVars.set(m[1], m[2].trim());
228
+ }
229
+ }
230
+ return output;
231
+ };
232
+
233
+ return { build: trackingBuild, themeVars };
234
+ } catch (e: unknown) {
235
+ throw new Error(
236
+ `tailwindcss init failed: ${e instanceof Error ? e.message : String(e)}. Check tailwind.config.ts for syntax errors.`,
237
+ { cause: e },
238
+ );
239
+ }
240
+ }
@@ -0,0 +1,41 @@
1
+ export interface VitePlugin {
2
+ buildStart?: () => Promise<void> | void;
3
+ closeBundle?: () => Promise<void> | void;
4
+ config?: (
5
+ userConfig: unknown,
6
+ env: { command?: string; mode?: string },
7
+ ) => Record<string, unknown> | undefined | void;
8
+ configResolved?: (config: { command?: string; mode?: string }) => Promise<void> | void;
9
+ configurePreviewServer?: (server: unknown) => (() => void) | undefined;
10
+ configureServer?: (server: unknown) => (() => void) | undefined;
11
+ enforce?: "post" | "pre";
12
+ load?: (
13
+ id: string,
14
+ ) =>
15
+ | Promise<string | { code: string; moduleType?: string } | null>
16
+ | string
17
+ | { code: string; moduleType?: string }
18
+ | null;
19
+ name: string;
20
+ resolveId?: (id: string, importer?: unknown, options?: unknown) => string | null;
21
+ transform?: (
22
+ code: string,
23
+ id: string,
24
+ ) => Promise<{ code: string; map?: null } | null> | { code: string; map?: null } | null;
25
+ transformIndexHtml?: (
26
+ html: string,
27
+ ctx: unknown,
28
+ ) =>
29
+ | {
30
+ attrs?: Record<string, string | boolean | undefined>;
31
+ children?: string;
32
+ injectTo?: "body" | "body-prepend" | "head" | "head-prepend";
33
+ tag: string;
34
+ }[]
35
+ | undefined;
36
+ }
37
+
38
+ export interface ResolvedEntries {
39
+ client: string;
40
+ server: string;
41
+ }
@@ -0,0 +1,110 @@
1
+ // oxlint-disable-next-line typescript-eslint/triple-slash-reference
2
+ /// <reference path="solid-jsx.d.ts" />
3
+ // oxlint-disable-next-line typescript-eslint/triple-slash-reference
4
+ /// <reference path="sx.d.ts" />
5
+
6
+ interface ImportMeta {
7
+ readonly env: {
8
+ readonly DEV: boolean;
9
+ readonly PROD: boolean;
10
+ readonly MODE: string;
11
+ readonly BASE_URL: string;
12
+ readonly SSR: boolean;
13
+ [key: string]: unknown;
14
+ };
15
+ }
16
+
17
+ declare module "virtual:flare-server-fn-map" {
18
+ import type { ServerFnRegistration } from "@lovrozagar/flare/server";
19
+ const map: Map<string, ServerFnRegistration>;
20
+ export default map;
21
+ }
22
+
23
+ declare module "virtual:flare-is-dev" {
24
+ const isDev: boolean;
25
+ export default isDev;
26
+ }
27
+
28
+ declare module "virtual:flare-log-level" {
29
+ const level: "error" | "silent" | "verbose" | "warn";
30
+ export default level;
31
+ }
32
+
33
+ declare module "virtual:flare-config" {
34
+ const config: Record<string, unknown>;
35
+ export default config;
36
+ }
37
+
38
+ declare module "virtual:flare-client-entry" {
39
+ const entry: string;
40
+ export default entry;
41
+ }
42
+
43
+ declare module "virtual:flare-generated" {
44
+ export const layoutModuleIds: Record<string, string>;
45
+ export const routeTree: unknown;
46
+ export const layouts: unknown;
47
+ }
48
+
49
+ declare module "virtual:flare-module-preloads" {
50
+ export const clientManifest: Record<string, unknown> | null;
51
+ export const entryPreloads: { css: string[]; js: string[] };
52
+ }
53
+
54
+ declare module "virtual:flare-sx-manifest" {
55
+ import type { SxCssManifest } from "../ssr/critical-css";
56
+ export const sxManifest: SxCssManifest | null;
57
+ }
58
+
59
+ declare module "virtual:flare-sx-dev-css" {
60
+ /** Returns the current accumulated sx CSS string. Re-imported each SSR request to pick up HMR additions. */
61
+ export function getDevSxCss(): string;
62
+ /** Returns the current accumulated class-name list. Seeded into window state so client module injects dedupe against SSR-emitted classes. */
63
+ export function getDevSxClasses(): string[];
64
+ }
65
+
66
+ declare module "virtual:flare-server-fn-secret" {
67
+ const secret: string;
68
+ export default secret;
69
+ }
70
+
71
+ declare module "virtual:flare-sw-config" {
72
+ const config: { enabled: false } | { enabled: true; path: string; scope: string };
73
+ export default config;
74
+ }
75
+
76
+ declare module "*.avif" {
77
+ import type { StaticImageData } from "../image.ts";
78
+ const data: StaticImageData;
79
+ export default data;
80
+ }
81
+
82
+ declare module "*.jpg" {
83
+ import type { StaticImageData } from "../image.ts";
84
+ const data: StaticImageData;
85
+ export default data;
86
+ }
87
+
88
+ declare module "*.jpeg" {
89
+ import type { StaticImageData } from "../image.ts";
90
+ const data: StaticImageData;
91
+ export default data;
92
+ }
93
+
94
+ declare module "*.png" {
95
+ import type { StaticImageData } from "../image.ts";
96
+ const data: StaticImageData;
97
+ export default data;
98
+ }
99
+
100
+ declare module "*.tiff" {
101
+ import type { StaticImageData } from "../image.ts";
102
+ const data: StaticImageData;
103
+ export default data;
104
+ }
105
+
106
+ declare module "*.webp" {
107
+ import type { StaticImageData } from "../image.ts";
108
+ const data: StaticImageData;
109
+ export default data;
110
+ }
@@ -0,0 +1,184 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { findEntryKey, resolveModulePreloads, type ViteManifest } from "../module-graph/index.ts";
5
+ import type { SxCssManifest } from "../ssr/critical-css.ts";
6
+ import type { ResolvedEntries, VitePlugin } from "./types.ts";
7
+
8
+ /**
9
+ * Read the client entry path from Vite's build manifest.
10
+ * buildApp() builds client before SSR, so manifest.json exists
11
+ * when the SSR build loads this virtual module.
12
+ */
13
+ function readClientManifest(root: string): ViteManifest | undefined {
14
+ const manifestPath = join(root, "dist/client/.vite/manifest.json");
15
+ try {
16
+ const raw = readFileSync(manifestPath, "utf-8");
17
+ return JSON.parse(raw) as ViteManifest;
18
+ } catch {
19
+ /* manifest doesn't exist yet (dev mode) — caller uses dev fallback */
20
+ }
21
+ return undefined;
22
+ }
23
+
24
+ /** Read the sx CSS manifest emitted by the sx-ast plugin during the client build. */
25
+ function readSxManifest(root: string): SxCssManifest | undefined {
26
+ const manifestPath = join(root, "dist/client/flare-sx-manifest.json");
27
+ try {
28
+ const raw = readFileSync(manifestPath, "utf-8");
29
+ /* Trust bundleHref written by sx-ast — it knows assetsBase. */
30
+ return JSON.parse(raw) as SxCssManifest;
31
+ } catch {
32
+ /* sx plugin not enabled or client not built yet */
33
+ }
34
+ return undefined;
35
+ }
36
+
37
+ function resolveClientEntryFromManifest(root: string, clientEntry: string): string | undefined {
38
+ const manifest = readClientManifest(root);
39
+ if (!manifest) return undefined;
40
+
41
+ const entry = manifest[clientEntry];
42
+ if (entry?.file) return `/${entry.file}`;
43
+
44
+ /* Fallback: find any entry chunk */
45
+ for (const value of Object.values(manifest)) {
46
+ if (value.isEntry && value.file) return `/${value.file}`;
47
+ }
48
+ return undefined;
49
+ }
50
+
51
+ export function createVirtualPlugin(
52
+ config: { ignorePrefix?: string; logLevel?: string },
53
+ entries: ResolvedEntries,
54
+ codegen?: { routesFilePath?: string },
55
+ ): VitePlugin {
56
+ const routesFilePath = codegen?.routesFilePath ?? "src/_gen/routes.gen.ts";
57
+ const serializedConfig = JSON.stringify({
58
+ clientEntryFilePath: entries.client,
59
+ ignorePrefix: config.ignorePrefix ?? "_",
60
+ });
61
+
62
+ /* Captured from the parent ResolvedConfig — use this instead of `environment.config.mode`,
63
+ because under cf-vite-plugin (Vite 8) the SSR worker environment reports `mode: "production"`
64
+ even during `vite serve`, which silently flips Flare into prod-CSP mode (no unsafe-inline,
65
+ nonces added) and breaks dev HMR + third-party widgets. */
66
+ let isDevMode = false;
67
+
68
+ return {
69
+ config(_userConfig: unknown, env: { command?: string; mode?: string }) {
70
+ if (env.command === "serve" || env.mode === "development") isDevMode = true;
71
+ /* Inject `__FLARE_IS_DEV__` as a Vite define — survives cf-vite-plugin's SSR worker
72
+ bundle where `import.meta.env.DEV` is forced to `false` (SSR env mode defaults to
73
+ `production` even during `vite serve`). Define replacement is per-environment but
74
+ always honored, so this single source-of-truth flag works in every env. */
75
+ return {
76
+ define: {
77
+ __FLARE_IS_DEV__: JSON.stringify(isDevMode),
78
+ },
79
+ };
80
+ },
81
+ configResolved(resolvedConfig: { command?: string; mode?: string }) {
82
+ if (resolvedConfig.command === "serve" || resolvedConfig.mode === "development") {
83
+ isDevMode = true;
84
+ }
85
+ },
86
+ load(
87
+ this: {
88
+ environment?: {
89
+ config?: { build?: { outDir?: string }; mode?: string; root?: string };
90
+ name?: string;
91
+ };
92
+ },
93
+ id: string,
94
+ ): { code: string; moduleType: string } | null {
95
+ if (id === "\0virtual:flare-config") {
96
+ return { code: `export default ${serializedConfig}`, moduleType: "js" };
97
+ }
98
+ if (id === "\0virtual:flare-client-entry") {
99
+ const mode = this.environment?.config?.mode ?? "production";
100
+ if (mode === "development") {
101
+ return { code: `export default "/${entries.client}"`, moduleType: "js" };
102
+ }
103
+ /* Prod: read hashed filename from client build manifest */
104
+ const root = this.environment?.config?.root ?? process.cwd();
105
+ const resolved = resolveClientEntryFromManifest(root, entries.client);
106
+ return {
107
+ code: `export default "${resolved ?? `/${entries.client}`}"`,
108
+ moduleType: "js",
109
+ };
110
+ }
111
+ if (id === "\0virtual:flare-generated") {
112
+ const root = this.environment?.config?.root ?? process.cwd();
113
+ /* file:// URL gives rolldown an unambiguous filesystem anchor so relative imports
114
+ inside routes.gen.ts resolve from the real file location, not from the virtual
115
+ module's synthetic base (which otherwise produced 13-deep ../ traversals under
116
+ vite 8 + rolldown) */
117
+ const genFileUrl = pathToFileURL(resolve(root, routesFilePath)).href;
118
+ return {
119
+ code: `export { routeTree, layouts, layoutModuleIds } from "${genFileUrl}"`,
120
+ moduleType: "js",
121
+ };
122
+ }
123
+ if (id === "\0virtual:flare-is-dev") {
124
+ const dev = isDevMode || this.environment?.config?.mode === "development";
125
+ return { code: `export default ${dev}`, moduleType: "js" };
126
+ }
127
+ if (id === "\0virtual:flare-log-level") {
128
+ const dev = isDevMode || this.environment?.config?.mode === "development";
129
+ const level = config.logLevel ?? (dev ? "warn" : "error");
130
+ return { code: `export default "${level}"`, moduleType: "js" };
131
+ }
132
+ if (id === "\0virtual:flare-module-preloads") {
133
+ const mode = this.environment?.config?.mode ?? "production";
134
+ if (mode === "development") {
135
+ return {
136
+ code: ["export const entryPreloads = { js: [], css: [] }", "export const clientManifest = null"].join("\n"),
137
+ moduleType: "js",
138
+ };
139
+ }
140
+ const root = this.environment?.config?.root ?? process.cwd();
141
+ const manifest = readClientManifest(root);
142
+ if (!manifest) {
143
+ return {
144
+ code: ["export const entryPreloads = { js: [], css: [] }", "export const clientManifest = null"].join("\n"),
145
+ moduleType: "js",
146
+ };
147
+ }
148
+ const entryKey = findEntryKey(manifest);
149
+ const preloads = entryKey ? resolveModulePreloads(manifest, entryKey) : { css: [], js: [] };
150
+ return {
151
+ code: [
152
+ `export const entryPreloads = ${JSON.stringify(preloads)}`,
153
+ `export const clientManifest = ${JSON.stringify(manifest)}`,
154
+ ].join("\n"),
155
+ moduleType: "js",
156
+ };
157
+ }
158
+ if (id === "\0virtual:flare-sx-manifest") {
159
+ const mode = this.environment?.config?.mode ?? "production";
160
+ if (mode === "development") {
161
+ return { code: "export const sxManifest = null", moduleType: "js" };
162
+ }
163
+ const root = this.environment?.config?.root ?? process.cwd();
164
+ const manifest = readSxManifest(root);
165
+ return {
166
+ code: `export const sxManifest = ${manifest ? JSON.stringify(manifest) : "null"}`,
167
+ moduleType: "js",
168
+ };
169
+ }
170
+ return null;
171
+ },
172
+ name: "flare:virtual",
173
+ resolveId(id: string): string | null {
174
+ if (id === "virtual:flare-config") return "\0virtual:flare-config";
175
+ if (id === "virtual:flare-client-entry") return "\0virtual:flare-client-entry";
176
+ if (id === "virtual:flare-generated") return "\0virtual:flare-generated";
177
+ if (id === "virtual:flare-is-dev") return "\0virtual:flare-is-dev";
178
+ if (id === "virtual:flare-log-level") return "\0virtual:flare-log-level";
179
+ if (id === "virtual:flare-module-preloads") return "\0virtual:flare-module-preloads";
180
+ if (id === "virtual:flare-sx-manifest") return "\0virtual:flare-sx-manifest";
181
+ return null;
182
+ },
183
+ };
184
+ }
@@ -0,0 +1,77 @@
1
+ const RETRY_DELAY_MS = 1000;
2
+ const MAX_ATTEMPTS = 2;
3
+
4
+ interface PreloadOptions<T, R extends boolean = false> {
5
+ loader: () => Promise<{ default: T }>;
6
+ throws?: R;
7
+ }
8
+
9
+ interface PreloadResult<T, R extends boolean> {
10
+ load: () => Promise<R extends true ? T : T | undefined>;
11
+ preload: () => void;
12
+ reset: () => void;
13
+ }
14
+
15
+ export function preload<T, R extends boolean = false>(options: PreloadOptions<T, R>): PreloadResult<T, R> {
16
+ let cached: Promise<T | undefined> | null = null;
17
+ let attempts = 0;
18
+ let generation = 0;
19
+
20
+ function doLoad(gen: number): Promise<T | undefined> {
21
+ attempts++;
22
+ return options.loader().then(
23
+ (mod) => mod.default,
24
+ (error: unknown) => {
25
+ /* Discard stale retry from previous generation */
26
+ if (gen !== generation) return undefined;
27
+ if (attempts < MAX_ATTEMPTS) {
28
+ return new Promise<T | undefined>((resolve) => {
29
+ setTimeout(() => {
30
+ /* Check generation again after delay */
31
+ if (gen !== generation) {
32
+ resolve(undefined);
33
+ return;
34
+ }
35
+ resolve(doLoad(gen));
36
+ }, RETRY_DELAY_MS);
37
+ });
38
+ }
39
+ /* exhausted — clear cache for fresh attempt next time */
40
+ cached = null;
41
+ attempts = 0;
42
+ if (options.throws) {
43
+ throw error;
44
+ }
45
+ return undefined;
46
+ },
47
+ );
48
+ }
49
+
50
+ function load(): Promise<T | undefined> {
51
+ if (!cached) {
52
+ cached = doLoad(generation);
53
+ cached.catch(() => {});
54
+ }
55
+ return cached;
56
+ }
57
+
58
+ function preloadFn(): void {
59
+ if (!cached) {
60
+ cached = doLoad(generation);
61
+ /* swallow unhandled rejection */
62
+ cached.catch(() => {});
63
+ }
64
+ }
65
+
66
+ function reset(): void {
67
+ cached = null;
68
+ attempts = 0;
69
+ generation++;
70
+ }
71
+
72
+ return {
73
+ load: load as PreloadResult<T, R>["load"],
74
+ preload: preloadFn,
75
+ reset,
76
+ };
77
+ }