@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.
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/package.json +146 -0
- package/scripts/download-fonts.ts +136 -0
- package/scripts/populate-fonts.ts +721 -0
- package/src/await.ts +2 -0
- package/src/boundaries/index.ts +99 -0
- package/src/broadcast/channel.ts +65 -0
- package/src/broadcast/context.ts +12 -0
- package/src/broadcast/index.ts +75 -0
- package/src/broadcast/provider.tsx +7 -0
- package/src/build-location.ts +2 -0
- package/src/caches/index.ts +384 -0
- package/src/client/index.ts +75 -0
- package/src/client.tsx +2 -0
- package/src/codegen/index.ts +41 -0
- package/src/components/await.tsx +140 -0
- package/src/components/dev-error-overlay.tsx +154 -0
- package/src/components/direction-script.tsx +22 -0
- package/src/components/index.ts +150 -0
- package/src/components/locale-script.tsx +26 -0
- package/src/components/reset-css.tsx +14 -0
- package/src/components/ssr-context.tsx +37 -0
- package/src/components/theme-script.tsx +22 -0
- package/src/components/view-transition-css.tsx +21 -0
- package/src/config/index.ts +84 -0
- package/src/create-client-only-fn.ts +1 -0
- package/src/create-isomorphic-fn.ts +2 -0
- package/src/create-layout.ts +1 -0
- package/src/create-page.ts +1 -0
- package/src/create-path-segment.ts +1 -0
- package/src/create-query-client-getter.ts +2 -0
- package/src/create-root-layout.ts +1 -0
- package/src/create-router.ts +8 -0
- package/src/create-server-only-fn.ts +1 -0
- package/src/dedupe/index.ts +151 -0
- package/src/defer/index.ts +82 -0
- package/src/direction/index.tsx +163 -0
- package/src/direction.ts +3 -0
- package/src/duration/index.ts +18 -0
- package/src/env-fn/index.ts +101 -0
- package/src/env-fn.ts +2 -0
- package/src/errors/index.ts +166 -0
- package/src/fonts/abeezee.ts +50 -0
- package/src/fonts/abel.ts +26 -0
- package/src/fonts/abril-fatface.ts +34 -0
- package/src/fonts/acme.ts +26 -0
- package/src/fonts/advent-pro.ts +92 -0
- package/src/fonts/alegreya-sans.ts +228 -0
- package/src/fonts/alegreya.ts +228 -0
- package/src/fonts/alex-brush.ts +42 -0
- package/src/fonts/alfa-slab-one.ts +42 -0
- package/src/fonts/alice.ts +48 -0
- package/src/fonts/amatic-sc.ts +94 -0
- package/src/fonts/amiri.ts +114 -0
- package/src/fonts/antic-slab.ts +26 -0
- package/src/fonts/anton.ts +42 -0
- package/src/fonts/archivo-black.ts +34 -0
- package/src/fonts/archivo-narrow.ts +114 -0
- package/src/fonts/archivo.ts +66 -0
- package/src/fonts/arimo.ts +256 -0
- package/src/fonts/arvo.ts +50 -0
- package/src/fonts/asap.ts +66 -0
- package/src/fonts/assistant.ts +64 -0
- package/src/fonts/baloo-2.ts +82 -0
- package/src/fonts/barlow-condensed.ts +114 -0
- package/src/fonts/barlow-semi-condensed.ts +114 -0
- package/src/fonts/barlow.ts +114 -0
- package/src/fonts/be-vietnam-pro.ts +114 -0
- package/src/fonts/bebas-neue.ts +34 -0
- package/src/fonts/besley.ts +82 -0
- package/src/fonts/biorhyme.ts +50 -0
- package/src/fonts/bitter.ts +94 -0
- package/src/fonts/black-ops-one.ts +49 -0
- package/src/fonts/bree-serif.ts +34 -0
- package/src/fonts/bricolage-grotesque.ts +66 -0
- package/src/fonts/cabin.ts +114 -0
- package/src/fonts/cairo.ts +66 -0
- package/src/fonts/cardo.ts +193 -0
- package/src/fonts/catamaran.ts +41 -0
- package/src/fonts/caveat.ts +78 -0
- package/src/fonts/chakra-petch.ts +142 -0
- package/src/fonts/chivo.ts +66 -0
- package/src/fonts/cinzel.ts +50 -0
- package/src/fonts/comfortaa.ts +109 -0
- package/src/fonts/commissioner.ts +64 -0
- package/src/fonts/component.tsx +27 -0
- package/src/fonts/cormorant-garamond.ts +171 -0
- package/src/fonts/cormorant.ts +170 -0
- package/src/fonts/courgette.ts +34 -0
- package/src/fonts/courier-prime.ts +82 -0
- package/src/fonts/create-font.ts +47 -0
- package/src/fonts/create-registry-font.ts +40 -0
- package/src/fonts/crete-round.ts +50 -0
- package/src/fonts/crimson-text.ts +114 -0
- package/src/fonts/css.ts +86 -0
- package/src/fonts/dancing-script.ts +66 -0
- package/src/fonts/dm-mono.ts +50 -0
- package/src/fonts/dm-sans.ts +50 -0
- package/src/fonts/dm-serif-display.ts +50 -0
- package/src/fonts/domine.ts +50 -0
- package/src/fonts/dosis.ts +66 -0
- package/src/fonts/eb-garamond.ts +228 -0
- package/src/fonts/eczar.ts +94 -0
- package/src/fonts/encode-sans.ts +42 -0
- package/src/fonts/epilogue.ts +66 -0
- package/src/fonts/exo-2.ts +94 -0
- package/src/fonts/exo.ts +66 -0
- package/src/fonts/figtree.ts +82 -0
- package/src/fonts/fira-code.ts +121 -0
- package/src/fonts/fira-sans-condensed.ts +228 -0
- package/src/fonts/fira-sans.ts +228 -0
- package/src/fonts/fjalla-one.ts +49 -0
- package/src/fonts/font-urls.gen.json +1962 -0
- package/src/fonts/fraunces.ts +66 -0
- package/src/fonts/fredoka.ts +64 -0
- package/src/fonts/gelasio.ts +114 -0
- package/src/fonts/gloria-hallelujah.ts +34 -0
- package/src/fonts/gothic-a1.ts +124 -0
- package/src/fonts/great-vibes.ts +64 -0
- package/src/fonts/gudea.ts +66 -0
- package/src/fonts/heebo.ts +57 -0
- package/src/fonts/hind-siliguri.ts +66 -0
- package/src/fonts/hind.ts +66 -0
- package/src/fonts/ibm-plex-mono.ts +172 -0
- package/src/fonts/ibm-plex-sans-arabic.ts +80 -0
- package/src/fonts/ibm-plex-sans.ts +199 -0
- package/src/fonts/ibm-plex-serif.ts +171 -0
- package/src/fonts/inconsolata.ts +66 -0
- package/src/fonts/index.ts +4 -0
- package/src/fonts/indie-flower.ts +34 -0
- package/src/fonts/instrument-sans.ts +82 -0
- package/src/fonts/instrument-serif.ts +50 -0
- package/src/fonts/inter-display.ts +52 -0
- package/src/fonts/inter-tight.ts +124 -0
- package/src/fonts/inter.ts +123 -0
- package/src/fonts/jetbrains-mono.ts +199 -0
- package/src/fonts/josefin-sans.ts +114 -0
- package/src/fonts/josefin-slab.ts +50 -0
- package/src/fonts/jost.ts +64 -0
- package/src/fonts/kalam.ts +66 -0
- package/src/fonts/kanit.ts +142 -0
- package/src/fonts/karla.ts +82 -0
- package/src/fonts/khand.ts +66 -0
- package/src/fonts/lato.ts +82 -0
- package/src/fonts/league-spartan.ts +42 -0
- package/src/fonts/lexend-deca.ts +42 -0
- package/src/fonts/lexend.ts +42 -0
- package/src/fonts/libre-baskerville.ts +82 -0
- package/src/fonts/libre-franklin.ts +95 -0
- package/src/fonts/lilita-one.ts +34 -0
- package/src/fonts/lobster-two.ts +50 -0
- package/src/fonts/lobster.ts +56 -0
- package/src/fonts/lora.ts +235 -0
- package/src/fonts/m-plus-rounded-1c.ts +138 -0
- package/src/fonts/manrope.ts +109 -0
- package/src/fonts/maven-pro.ts +66 -0
- package/src/fonts/merriweather-sans.ts +142 -0
- package/src/fonts/merriweather.ts +171 -0
- package/src/fonts/montserrat-alternates.ts +171 -0
- package/src/fonts/montserrat.ts +94 -0
- package/src/fonts/mukta.ts +66 -0
- package/src/fonts/mulish.ts +170 -0
- package/src/fonts/nanum-gothic.ts +34 -0
- package/src/fonts/nanum-myeongjo.ts +34 -0
- package/src/fonts/neuton.ts +66 -0
- package/src/fonts/newsreader.ts +114 -0
- package/src/fonts/noticia-text.ts +114 -0
- package/src/fonts/noto-sans-arabic.ts +58 -0
- package/src/fonts/noto-sans-hk.ts +49 -0
- package/src/fonts/noto-sans-jp.ts +49 -0
- package/src/fonts/noto-sans-kr.ts +49 -0
- package/src/fonts/noto-sans-sc.ts +49 -0
- package/src/fonts/noto-sans-tc.ts +49 -0
- package/src/fonts/noto-sans.ts +140 -0
- package/src/fonts/noto-serif-jp.ts +80 -0
- package/src/fonts/noto-serif.ts +140 -0
- package/src/fonts/nunito-sans.ts +170 -0
- package/src/fonts/nunito.ts +170 -0
- package/src/fonts/old-standard-tt.ts +133 -0
- package/src/fonts/onest.ts +48 -0
- package/src/fonts/open-sans.ts +340 -0
- package/src/fonts/orbitron.ts +34 -0
- package/src/fonts/oswald.ts +94 -0
- package/src/fonts/outfit.ts +34 -0
- package/src/fonts/overpass.ts +94 -0
- package/src/fonts/oxygen.ts +50 -0
- package/src/fonts/pacifico.ts +56 -0
- package/src/fonts/passion-one.ts +50 -0
- package/src/fonts/pathway-gothic-one.ts +34 -0
- package/src/fonts/permanent-marker.ts +26 -0
- package/src/fonts/philosopher.ts +172 -0
- package/src/fonts/play.ts +109 -0
- package/src/fonts/playfair-display.ts +142 -0
- package/src/fonts/plus-jakarta-sans.ts +142 -0
- package/src/fonts/poppins.ts +114 -0
- package/src/fonts/prompt.ts +142 -0
- package/src/fonts/pt-sans-narrow.ts +78 -0
- package/src/fonts/pt-sans.ts +138 -0
- package/src/fonts/pt-serif.ts +138 -0
- package/src/fonts/public-sans.ts +66 -0
- package/src/fonts/questrial.ts +42 -0
- package/src/fonts/quicksand.ts +66 -0
- package/src/fonts/rajdhani.ts +66 -0
- package/src/fonts/raleway.ts +94 -0
- package/src/fonts/recursive.ts +80 -0
- package/src/fonts/red-hat-display.ts +82 -0
- package/src/fonts/red-rose.ts +66 -0
- package/src/fonts/registry.gen.ts +173 -0
- package/src/fonts/righteous.ts +34 -0
- package/src/fonts/roboto-condensed.ts +124 -0
- package/src/fonts/roboto-flex.ts +64 -0
- package/src/fonts/roboto-mono.ts +199 -0
- package/src/fonts/roboto-slab.ts +72 -0
- package/src/fonts/roboto.ts +156 -0
- package/src/fonts/rokkitt.ts +66 -0
- package/src/fonts/rubik.ts +199 -0
- package/src/fonts/sacramento.ts +34 -0
- package/src/fonts/saira.ts +66 -0
- package/src/fonts/sarabun.ts +142 -0
- package/src/fonts/satisfy.ts +26 -0
- package/src/fonts/sawarabi-mincho.ts +41 -0
- package/src/fonts/shadows-into-light.ts +34 -0
- package/src/fonts/signika-negative.ts +66 -0
- package/src/fonts/signika.ts +66 -0
- package/src/fonts/slabo-27px.ts +34 -0
- package/src/fonts/sora.ts +50 -0
- package/src/fonts/source-code-pro.ts +228 -0
- package/src/fonts/source-sans-3.ts +228 -0
- package/src/fonts/source-serif-4.ts +199 -0
- package/src/fonts/space-grotesk.ts +66 -0
- package/src/fonts/space-mono.ts +114 -0
- package/src/fonts/spectral.ts +170 -0
- package/src/fonts/tajawal.ts +50 -0
- package/src/fonts/teko.ts +66 -0
- package/src/fonts/tenor-sans.ts +41 -0
- package/src/fonts/tinos.ts +256 -0
- package/src/fonts/titillium-web.ts +82 -0
- package/src/fonts/types.ts +43 -0
- package/src/fonts/ubuntu-condensed.ts +63 -0
- package/src/fonts/ubuntu-mono.ts +195 -0
- package/src/fonts/ubuntu.ts +195 -0
- package/src/fonts/unbounded.ts +94 -0
- package/src/fonts/unicode-ranges.gen.ts +28 -0
- package/src/fonts/urbanist.ts +50 -0
- package/src/fonts/varela-round.ts +49 -0
- package/src/fonts/vollkorn.ts +199 -0
- package/src/fonts/work-sans.ts +66 -0
- package/src/fonts/yanone-kaffeesatz.ts +128 -0
- package/src/fonts/yantramanav.ts +66 -0
- package/src/fonts/yellowtail.ts +34 -0
- package/src/fonts/young-serif.ts +34 -0
- package/src/fonts/zen-kaku-gothic-new.ts +64 -0
- package/src/fonts/zilla-slab.ts +82 -0
- package/src/form/index.tsx +205 -0
- package/src/generators/index.ts +1589 -0
- package/src/head-client/index.ts +649 -0
- package/src/history/index.ts +210 -0
- package/src/hooks.ts +61 -0
- package/src/hydrate/index.tsx +381 -0
- package/src/hydration/index.ts +187 -0
- package/src/i18n/index.ts +250 -0
- package/src/i18n/jsx.tsx +42 -0
- package/src/i18n/message-format.ts +174 -0
- package/src/image/index.tsx +473 -0
- package/src/image.ts +12 -0
- package/src/intercept-outlet/index.tsx +18 -0
- package/src/intercept-outlet.ts +2 -0
- package/src/internal/index.ts +143 -0
- package/src/internal/once-idle.ts +24 -0
- package/src/internal.ts +12 -0
- package/src/lazy/index.tsx +205 -0
- package/src/link/index.tsx +367 -0
- package/src/loader-pipeline/index.ts +639 -0
- package/src/locale/index.tsx +137 -0
- package/src/locale.ts +3 -0
- package/src/logger.ts +22 -0
- package/src/middleware/builtins/api-proxy.ts +64 -0
- package/src/middleware/builtins/cdn-proxy.ts +58 -0
- package/src/middleware/builtins/i18n.ts +256 -0
- package/src/middleware/builtins/keepalive.ts +24 -0
- package/src/middleware/builtins/markdown-negotiation.ts +141 -0
- package/src/middleware/builtins/static-assets.ts +32 -0
- package/src/middleware/index.ts +223 -0
- package/src/module-graph/index.ts +181 -0
- package/src/mount/index.ts +146 -0
- package/src/navigate.ts +1 -0
- package/src/navigation/index.ts +1278 -0
- package/src/navigation/types.ts +59 -0
- package/src/navigation-progress/index.tsx +247 -0
- package/src/navigation-progress.ts +1 -0
- package/src/ndjson-client/index.ts +376 -0
- package/src/ndjson-server/index.ts +284 -0
- package/src/outlet/index.tsx +633 -0
- package/src/outlet/types.ts +243 -0
- package/src/plugins/css-transform.ts +70 -0
- package/src/plugins/dev-cdn-cache.ts +454 -0
- package/src/plugins/dev-dashboard/client.tsx +2603 -0
- package/src/plugins/dev-dashboard/match-route-tree.ts +159 -0
- package/src/plugins/dev-dashboard/plugin.ts +404 -0
- package/src/plugins/dev-prerender.ts +168 -0
- package/src/plugins/dev-server.ts +327 -0
- package/src/plugins/generate-watch.ts +32 -0
- package/src/plugins/image-plugin.ts +171 -0
- package/src/plugins/index.ts +445 -0
- package/src/plugins/options.ts +37 -0
- package/src/plugins/parse-utils.ts +59 -0
- package/src/plugins/prerender-plugin.ts +144 -0
- package/src/plugins/purge.ts +242 -0
- package/src/plugins/server-fn.ts +641 -0
- package/src/plugins/service-worker.ts +225 -0
- package/src/plugins/solid-jsx.d.ts +12 -0
- package/src/plugins/sx-ast/atomic.ts +166 -0
- package/src/plugins/sx-ast/evaluator.ts +235 -0
- package/src/plugins/sx-ast/index.ts +372 -0
- package/src/plugins/sx-ast/parser.ts +22 -0
- package/src/plugins/sx-ast/rewrite.ts +763 -0
- package/src/plugins/sx.d.ts +14 -0
- package/src/plugins/tw-compile.ts +240 -0
- package/src/plugins/types.ts +41 -0
- package/src/plugins/virtual.d.ts +110 -0
- package/src/plugins/virtual.ts +184 -0
- package/src/preload/index.ts +77 -0
- package/src/prerender/index.ts +431 -0
- package/src/query-client/index.tsx +168 -0
- package/src/registry/index.ts +88 -0
- package/src/reset-css.ts +1 -0
- package/src/revalidation/index.ts +84 -0
- package/src/rewrite/index.ts +83 -0
- package/src/route-builder/create-layout.ts +655 -0
- package/src/route-builder/create-page.ts +806 -0
- package/src/route-builder/create-path-segment.ts +34 -0
- package/src/route-builder/create-root-layout.ts +608 -0
- package/src/route-builder/index.ts +49 -0
- package/src/route-builder/register.ts +242 -0
- package/src/route-builder/types.ts +294 -0
- package/src/router-config/index.ts +91 -0
- package/src/router-primitives/index.ts +25 -0
- package/src/router-primitives/location.ts +29 -0
- package/src/router-primitives/match-id.ts +111 -0
- package/src/router-primitives/paths.ts +109 -0
- package/src/router-primitives/tree.ts +243 -0
- package/src/router-primitives/types.ts +74 -0
- package/src/router.ts +31 -0
- package/src/search-engine/bing.ts +32 -0
- package/src/search-engine/google-jwt.ts +95 -0
- package/src/search-engine/google.ts +139 -0
- package/src/search-engine/index-now.ts +64 -0
- package/src/search-engine/index.ts +12 -0
- package/src/security/index.ts +230 -0
- package/src/server/index.ts +286 -0
- package/src/server-context/browser.ts +113 -0
- package/src/server-context/index.ts +217 -0
- package/src/server-fn/index.ts +710 -0
- package/src/server-fn-query.ts +169 -0
- package/src/server-handler/etag.ts +51 -0
- package/src/server-handler/headers.ts +5 -0
- package/src/server-handler/index.ts +1664 -0
- package/src/server-handler/types.ts +24 -0
- package/src/server-handler/validate-static-params.ts +130 -0
- package/src/server.ts +2 -0
- package/src/service-worker/template.ts +153 -0
- package/src/service-worker-hook/index.ts +70 -0
- package/src/sitemap/index.ts +231 -0
- package/src/ssr/critical-css.ts +150 -0
- package/src/ssr/head-prefix.ts +65 -0
- package/src/ssr/head.ts +259 -0
- package/src/ssr/index.tsx +879 -0
- package/src/state-parser/index.ts +266 -0
- package/src/store/filesystem.ts +131 -0
- package/src/store/index.ts +29 -0
- package/src/styles/index.ts +1200 -0
- package/src/styles/sx-types.ts +11 -0
- package/src/testing/index.ts +251 -0
- package/src/testing.ts +2 -0
- package/src/theme/index.tsx +232 -0
- package/src/theme.ts +3 -0
- package/src/tracing/index.ts +4 -0
- package/src/tracing/noop.ts +13 -0
- package/src/tracing/otel.ts +37 -0
- package/src/tracing/timing.ts +34 -0
- package/src/tracing/types.ts +9 -0
- package/src/url/index.ts +140 -0
- package/src/use-router.ts +11 -0
- package/src/use-suspense-query.ts +2 -0
- package/src/validation/index.ts +57 -0
- package/src/view-transition-css.ts +1 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import type { HeadConfig } from "../route-builder/types.ts";
|
|
2
|
+
import type { FlareMatchState, FlareState } from "../ssr/index.tsx";
|
|
3
|
+
import type { SearchParams } from "../url/index.ts";
|
|
4
|
+
|
|
5
|
+
export type { FlareState, FlareMatchState };
|
|
6
|
+
|
|
7
|
+
export interface DeferredMarker {
|
|
8
|
+
__deferred: true;
|
|
9
|
+
key: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface HydratedMatch {
|
|
13
|
+
errorName?: string;
|
|
14
|
+
headConfig?: HeadConfig;
|
|
15
|
+
loaderData: unknown;
|
|
16
|
+
matchId: string;
|
|
17
|
+
preloaderContext?: Record<string, unknown>;
|
|
18
|
+
virtualPath: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ParseResult {
|
|
22
|
+
matches: HydratedMatch[];
|
|
23
|
+
params: Record<string, string | string[]>;
|
|
24
|
+
pathname: string;
|
|
25
|
+
resolvers: Map<string, DeferredResolver>;
|
|
26
|
+
search: SearchParams;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DeferredResolver {
|
|
30
|
+
reject: (error: Error) => void;
|
|
31
|
+
resolve: (data: unknown) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function parseFlareState(raw: unknown): FlareState | null {
|
|
35
|
+
if (raw === null || raw === undefined || typeof raw !== "object") return null;
|
|
36
|
+
|
|
37
|
+
const obj = raw as Record<string, unknown>;
|
|
38
|
+
if (
|
|
39
|
+
typeof obj.c !== "object" ||
|
|
40
|
+
obj.c === null ||
|
|
41
|
+
!Array.isArray(obj.m) ||
|
|
42
|
+
typeof obj.p !== "string" ||
|
|
43
|
+
typeof obj.r !== "object" ||
|
|
44
|
+
obj.r === null ||
|
|
45
|
+
typeof obj.s !== "object" ||
|
|
46
|
+
obj.s === null
|
|
47
|
+
) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return raw as FlareState;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isDeferredMarker(value: unknown): value is DeferredMarker {
|
|
55
|
+
if (value === null || value === undefined || typeof value !== "object") return false;
|
|
56
|
+
const obj = value as Record<string, unknown>;
|
|
57
|
+
return obj.__deferred === true && "key" in obj && typeof obj.key === "string";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function hydrateLoaderData(matchId: string, data: unknown, resolvers: Map<string, DeferredResolver>): unknown {
|
|
61
|
+
if (data === null || data === undefined) return data;
|
|
62
|
+
if (typeof data !== "object") return data;
|
|
63
|
+
|
|
64
|
+
if (isDeferredMarker(data)) {
|
|
65
|
+
let resolveFn: (d: unknown) => void = () => {};
|
|
66
|
+
let rejectFn: (e: Error) => void = () => {};
|
|
67
|
+
const promise = new Promise<unknown>((resolve, reject) => {
|
|
68
|
+
resolveFn = resolve;
|
|
69
|
+
rejectFn = reject;
|
|
70
|
+
});
|
|
71
|
+
resolvers.set(`${matchId}:${data.key}`, { reject: rejectFn, resolve: resolveFn });
|
|
72
|
+
return { __deferred: true, __key: data.key, promise };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (Array.isArray(data)) {
|
|
76
|
+
return data.map((item) => hydrateLoaderData(matchId, item, resolvers));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const obj = data as Record<string, unknown>;
|
|
80
|
+
const result: Record<string, unknown> = Object.create(null);
|
|
81
|
+
for (const key of Object.keys(obj)) {
|
|
82
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
83
|
+
result[key] = hydrateLoaderData(matchId, obj[key], resolvers);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Register `self.__flare_r(resolverKey, data)` global so streamed `<script>` tags
|
|
90
|
+
* from SSR deferred resolution can resolve hydrated promise shells.
|
|
91
|
+
*/
|
|
92
|
+
declare global {
|
|
93
|
+
var __flare_q:
|
|
94
|
+
| Array<[string, unknown, boolean?]>
|
|
95
|
+
| { push: (entry: [string, unknown, boolean?]) => number }
|
|
96
|
+
| undefined;
|
|
97
|
+
var __flare_qc: Array<[unknown]> | { push: (entry: [unknown]) => number } | undefined;
|
|
98
|
+
var __flare_r: ((key: string, data: unknown) => void) | undefined;
|
|
99
|
+
var __flare_re: ((key: string, message: string) => void) | undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* Multi-instance registry: supports multiple Flare apps hydrating on the same page.
|
|
104
|
+
* Each call to installDeferredResolver registers its resolver map. The global
|
|
105
|
+
* __flare_r/__flare_re/__flare_q search ALL active maps when resolving a key.
|
|
106
|
+
* Globals are only cleaned when every active map is drained AND no pending entries remain.
|
|
107
|
+
*/
|
|
108
|
+
const activeInstances = new Set<Map<string, DeferredResolver>>();
|
|
109
|
+
const pendingEntries: Array<[string, unknown, boolean?]> = [];
|
|
110
|
+
|
|
111
|
+
function resolveOrBuffer(key: string, data: unknown, isError: boolean): void {
|
|
112
|
+
for (const m of activeInstances) {
|
|
113
|
+
const resolver = m.get(key);
|
|
114
|
+
if (resolver) {
|
|
115
|
+
if (isError) {
|
|
116
|
+
resolver.reject(new Error(data as string));
|
|
117
|
+
} else {
|
|
118
|
+
resolver.resolve(data);
|
|
119
|
+
}
|
|
120
|
+
m.delete(key);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
pendingEntries.push(isError ? [key, data, true] : [key, data]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function cleanupIfAllEmpty(): void {
|
|
128
|
+
if (pendingEntries.length > 0) return;
|
|
129
|
+
for (const m of activeInstances) {
|
|
130
|
+
if (m.size > 0) return;
|
|
131
|
+
}
|
|
132
|
+
globalThis.__flare_r = undefined;
|
|
133
|
+
globalThis.__flare_re = undefined;
|
|
134
|
+
globalThis.__flare_q = undefined;
|
|
135
|
+
activeInstances.clear();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Drain buffered deferred chunks from SSR streamed `<script>` tags,
|
|
140
|
+
* then install live resolver for any late-arriving chunks.
|
|
141
|
+
*
|
|
142
|
+
* SSR scripts push `[key, data]` (or `[key, msg, true]` for errors)
|
|
143
|
+
* into `self.__flare_q` array. This function drains them, then replaces
|
|
144
|
+
* the array push with a direct resolver so future chunks resolve immediately.
|
|
145
|
+
*
|
|
146
|
+
* Safe for multiple Flare instances on the same page — resolvers compose
|
|
147
|
+
* rather than overwrite, and globals are only cleaned when all are drained.
|
|
148
|
+
*/
|
|
149
|
+
export function installDeferredResolver(resolvers: Map<string, DeferredResolver>): void {
|
|
150
|
+
if (typeof globalThis === "undefined") return;
|
|
151
|
+
|
|
152
|
+
/* Reset registry if globals were cleaned externally (e.g. tests) */
|
|
153
|
+
if (!globalThis.__flare_r && activeInstances.size > 0) {
|
|
154
|
+
activeInstances.clear();
|
|
155
|
+
pendingEntries.length = 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
activeInstances.add(resolvers);
|
|
159
|
+
|
|
160
|
+
/* Drain any buffered entries from SSR script tags */
|
|
161
|
+
const queue = globalThis.__flare_q;
|
|
162
|
+
if (Array.isArray(queue)) {
|
|
163
|
+
for (const entry of queue) {
|
|
164
|
+
resolveOrBuffer(entry[0], entry[1], Boolean(entry[2]));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Drain pending entries — new instance may have matching resolvers */
|
|
169
|
+
if (pendingEntries.length > 0) {
|
|
170
|
+
const pending = [...pendingEntries];
|
|
171
|
+
pendingEntries.length = 0;
|
|
172
|
+
for (const entry of pending) {
|
|
173
|
+
resolveOrBuffer(entry[0], entry[1], Boolean(entry[2]));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Install live resolvers for chunks that stream after hydration */
|
|
178
|
+
globalThis.__flare_r = (key: string, data: unknown) => {
|
|
179
|
+
resolveOrBuffer(key, data, false);
|
|
180
|
+
cleanupIfAllEmpty();
|
|
181
|
+
};
|
|
182
|
+
globalThis.__flare_re = (key: string, message: string) => {
|
|
183
|
+
resolveOrBuffer(key, message, true);
|
|
184
|
+
cleanupIfAllEmpty();
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* Trap __flare_q so late-arriving SSR script pushes resolve immediately.
|
|
189
|
+
* SSR scripts do `(self.__flare_q=self.__flare_q||[]).push([...])` — after
|
|
190
|
+
* drain, new pushes must route through the live resolver, not the array.
|
|
191
|
+
*/
|
|
192
|
+
globalThis.__flare_q = {
|
|
193
|
+
push(entry: [string, unknown, boolean?]) {
|
|
194
|
+
resolveOrBuffer(entry[0], entry[1], Boolean(entry[2]));
|
|
195
|
+
cleanupIfAllEmpty();
|
|
196
|
+
return 0;
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/* If no resolvers needed (all data was instant), clean up immediately */
|
|
201
|
+
cleanupIfAllEmpty();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Drain buffered deferred QC entries from SSR streamed `<script>` tags,
|
|
206
|
+
* then install live proxy for late-arriving entries.
|
|
207
|
+
*
|
|
208
|
+
* SSR scripts push `[{data, key, staleTime?}]` into `self.__flare_qc` array.
|
|
209
|
+
* This function drains them, then replaces the array with a push-proxy
|
|
210
|
+
* so future scripts hydrate immediately.
|
|
211
|
+
*/
|
|
212
|
+
export function installQueryCacheResolver(queryClient: unknown): void {
|
|
213
|
+
if (typeof globalThis === "undefined") return;
|
|
214
|
+
|
|
215
|
+
const qc = queryClient as {
|
|
216
|
+
setQueryData: (key: unknown[], data: unknown) => void;
|
|
217
|
+
setQueryDefaults: (key: unknown[], defaults: { staleTime: number }) => void;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
function applyEntry(entry: unknown): void {
|
|
221
|
+
if (typeof entry !== "object" || entry === null) return;
|
|
222
|
+
const e = entry as { data: unknown; key: unknown[]; staleTime?: number };
|
|
223
|
+
if (!Array.isArray(e.key)) return;
|
|
224
|
+
qc.setQueryData(e.key, e.data);
|
|
225
|
+
if (typeof e.staleTime === "number" && Number.isFinite(e.staleTime) && e.staleTime >= 0) {
|
|
226
|
+
qc.setQueryDefaults(e.key, { staleTime: e.staleTime });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Drain any buffered entries from SSR script tags */
|
|
231
|
+
const queue = globalThis.__flare_qc;
|
|
232
|
+
if (Array.isArray(queue)) {
|
|
233
|
+
for (const entry of queue) {
|
|
234
|
+
applyEntry(entry[0]);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* Install push-proxy for late-arriving SSR scripts */
|
|
239
|
+
globalThis.__flare_qc = {
|
|
240
|
+
push(entry: [unknown]) {
|
|
241
|
+
applyEntry(entry[0]);
|
|
242
|
+
return 0;
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function hydrateFlareState(state: FlareState): ParseResult {
|
|
248
|
+
const resolvers = new Map<string, DeferredResolver>();
|
|
249
|
+
|
|
250
|
+
const matches: HydratedMatch[] = state.m.map((match) => ({
|
|
251
|
+
errorName: match.x,
|
|
252
|
+
headConfig: match.h,
|
|
253
|
+
loaderData: hydrateLoaderData(match.i, match.d, resolvers),
|
|
254
|
+
matchId: match.i,
|
|
255
|
+
preloaderContext: match.p,
|
|
256
|
+
virtualPath: match.v,
|
|
257
|
+
}));
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
matches,
|
|
261
|
+
params: state.r,
|
|
262
|
+
pathname: state.p,
|
|
263
|
+
resolvers,
|
|
264
|
+
search: state.s,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import type { FlareStore, FlareStoreEntry } from "./index.ts";
|
|
4
|
+
|
|
5
|
+
interface StoredEntry extends FlareStoreEntry {
|
|
6
|
+
expiresAt?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Encode a store key to a flat filename.
|
|
11
|
+
* `static:/about` → `static/_about.json`
|
|
12
|
+
* `flare:_root_/[id]:{"id":"42"}` → `loader/_root___[id]__{"id":"42"}.json`
|
|
13
|
+
*/
|
|
14
|
+
export function keyToPath(key: string): string {
|
|
15
|
+
let subdir: string;
|
|
16
|
+
let rest: string;
|
|
17
|
+
|
|
18
|
+
if (key.startsWith("static:")) {
|
|
19
|
+
subdir = "static";
|
|
20
|
+
rest = key.slice(7);
|
|
21
|
+
} else if (key.startsWith("cdn:")) {
|
|
22
|
+
subdir = "cdn";
|
|
23
|
+
rest = key.slice(4);
|
|
24
|
+
} else if (key.startsWith("flare:")) {
|
|
25
|
+
subdir = "loader";
|
|
26
|
+
rest = key.slice(6);
|
|
27
|
+
} else {
|
|
28
|
+
subdir = "other";
|
|
29
|
+
rest = key;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* flatten slashes and colons to underscores to keep files flat */
|
|
33
|
+
const encoded = rest.replace(/\//g, "_").replace(/:/g, "__");
|
|
34
|
+
return `${subdir}/${encoded}.json`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createFileSystemStore(config?: { cacheDir?: string }): FlareStore {
|
|
38
|
+
const baseDir = config?.cacheDir ?? ".flare/cache";
|
|
39
|
+
|
|
40
|
+
function fullPath(key: string): string {
|
|
41
|
+
return join(baseDir, keyToPath(key));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ensureDir(filePath: string): void {
|
|
45
|
+
const dir = dirname(filePath);
|
|
46
|
+
if (!existsSync(dir)) {
|
|
47
|
+
mkdirSync(dir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readEntry(filePath: string): StoredEntry | null {
|
|
52
|
+
try {
|
|
53
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
54
|
+
return JSON.parse(raw) as StoredEntry;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function removeFile(fp: string): void {
|
|
61
|
+
try {
|
|
62
|
+
rmSync(fp);
|
|
63
|
+
} catch {
|
|
64
|
+
/* file may not exist */
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
delete(key: string): Promise<void> {
|
|
70
|
+
removeFile(fullPath(key));
|
|
71
|
+
return Promise.resolve();
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
deleteByKeys(keys: string[]): Promise<void> {
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
removeFile(fullPath(key));
|
|
77
|
+
}
|
|
78
|
+
return Promise.resolve();
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
deleteByTags(tags: string[]): Promise<void> {
|
|
82
|
+
const tagSet = new Set(tags);
|
|
83
|
+
const subdirs = ["static", "loader", "cdn", "other"];
|
|
84
|
+
for (const sub of subdirs) {
|
|
85
|
+
const dir = join(baseDir, sub);
|
|
86
|
+
if (!existsSync(dir)) continue;
|
|
87
|
+
|
|
88
|
+
const files = readdirSync(dir);
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
if (!file.endsWith(".json")) continue;
|
|
91
|
+
const entry = readEntry(join(dir, file));
|
|
92
|
+
if (entry?.tags?.some((t) => tagSet.has(t))) {
|
|
93
|
+
removeFile(join(dir, file));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return Promise.resolve();
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
get(key: string): Promise<FlareStoreEntry | null> {
|
|
101
|
+
const fp = fullPath(key);
|
|
102
|
+
const stored = readEntry(fp);
|
|
103
|
+
if (!stored) return Promise.resolve(null);
|
|
104
|
+
|
|
105
|
+
if (stored.expiresAt !== undefined && Date.now() >= stored.expiresAt) {
|
|
106
|
+
removeFile(fp);
|
|
107
|
+
return Promise.resolve(null);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result: FlareStoreEntry = {
|
|
111
|
+
data: stored.data,
|
|
112
|
+
storedAt: stored.storedAt,
|
|
113
|
+
};
|
|
114
|
+
if (stored.tags) result.tags = stored.tags;
|
|
115
|
+
return Promise.resolve(result);
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
set(key: string, entry: FlareStoreEntry, ttl?: number): Promise<void> {
|
|
119
|
+
const fp = fullPath(key);
|
|
120
|
+
ensureDir(fp);
|
|
121
|
+
|
|
122
|
+
const stored: StoredEntry = { ...entry };
|
|
123
|
+
if (ttl !== undefined) {
|
|
124
|
+
stored.expiresAt = Date.now() + ttl * 1000;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
writeFileSync(fp, JSON.stringify(stored));
|
|
128
|
+
return Promise.resolve();
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified store — platform-agnostic KV interface for both
|
|
3
|
+
* loader-data cache and ISR/static page artifacts.
|
|
4
|
+
*
|
|
5
|
+
* Key prefixes (`static:`, `flare:`) namespace entry types internally;
|
|
6
|
+
* users configure a single store adapter.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface FlareStoreEntry {
|
|
10
|
+
data: unknown;
|
|
11
|
+
storedAt: number;
|
|
12
|
+
tags?: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface FlareStore {
|
|
16
|
+
delete(key: string): Promise<void>;
|
|
17
|
+
deleteByKeys?(keys: string[], callerData?: unknown): Promise<void>;
|
|
18
|
+
deleteByTags(tags: string[], callerData?: unknown): Promise<void>;
|
|
19
|
+
get(key: string): Promise<FlareStoreEntry | null>;
|
|
20
|
+
set(key: string, entry: FlareStoreEntry, ttl?: number): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Internal shape for ISR/static entries stored as `FlareStoreEntry.data` */
|
|
24
|
+
export interface StaticEntryData {
|
|
25
|
+
etag?: string;
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
html: string;
|
|
28
|
+
ndjson: string;
|
|
29
|
+
}
|