@takazudo/zfb-runtime 0.1.0-next.2

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 (56) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +237 -0
  4. package/dist/client-router/cssesc.d.ts +9 -0
  5. package/dist/client-router/cssesc.d.ts.map +1 -0
  6. package/dist/client-router/cssesc.js +95 -0
  7. package/dist/client-router/cssesc.js.map +1 -0
  8. package/dist/client-router/events.d.ts +42 -0
  9. package/dist/client-router/events.d.ts.map +1 -0
  10. package/dist/client-router/events.js +114 -0
  11. package/dist/client-router/events.js.map +1 -0
  12. package/dist/client-router/index.d.ts +9 -0
  13. package/dist/client-router/index.d.ts.map +1 -0
  14. package/dist/client-router/index.js +18 -0
  15. package/dist/client-router/index.js.map +1 -0
  16. package/dist/client-router/prefetch.d.ts +29 -0
  17. package/dist/client-router/prefetch.d.ts.map +1 -0
  18. package/dist/client-router/prefetch.js +288 -0
  19. package/dist/client-router/prefetch.js.map +1 -0
  20. package/dist/client-router/router.d.ts +17 -0
  21. package/dist/client-router/router.d.ts.map +1 -0
  22. package/dist/client-router/router.js +739 -0
  23. package/dist/client-router/router.js.map +1 -0
  24. package/dist/client-router/swap-functions.d.ts +22 -0
  25. package/dist/client-router/swap-functions.d.ts.map +1 -0
  26. package/dist/client-router/swap-functions.js +252 -0
  27. package/dist/client-router/swap-functions.js.map +1 -0
  28. package/dist/client-router/types.d.ts +11 -0
  29. package/dist/client-router/types.d.ts.map +1 -0
  30. package/dist/client-router/types.js +3 -0
  31. package/dist/client-router/types.js.map +1 -0
  32. package/dist/client-router.d.ts +36 -0
  33. package/dist/client-router.d.ts.map +1 -0
  34. package/dist/client-router.js +117 -0
  35. package/dist/client-router.js.map +1 -0
  36. package/dist/framework.d.ts +17 -0
  37. package/dist/framework.d.ts.map +1 -0
  38. package/dist/framework.js +17 -0
  39. package/dist/framework.js.map +1 -0
  40. package/dist/index.d.ts +14 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +29 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/router.d.ts +97 -0
  45. package/dist/router.d.ts.map +1 -0
  46. package/dist/router.js +318 -0
  47. package/dist/router.js.map +1 -0
  48. package/dist/snapshot.d.ts +38 -0
  49. package/dist/snapshot.d.ts.map +1 -0
  50. package/dist/snapshot.js +16 -0
  51. package/dist/snapshot.js.map +1 -0
  52. package/dist/view-transitions.d.ts +34 -0
  53. package/dist/view-transitions.d.ts.map +1 -0
  54. package/dist/view-transitions.js +54 -0
  55. package/dist/view-transitions.js.map +1 -0
  56. package/package.json +78 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,8DAA8D;AAC9D,uEAAuE;AACvE,EAAE;AACF,8DAA8D;AAC9D,EAAE;AACF,sCAAsC;AACtC,oBAAoB;AACpB,4EAA4E;AAC5E,iFAAiF;AACjF,QAAQ;AACR,EAAE;AACF,sCAAsC;AACtC,EAAE;AACF,wEAAwE;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAU/C,OAAO,EAAE,eAAe,EAA+B,MAAM,uBAAuB,CAAC;AAErF,2FAA2F;AAC3F,2CAA2C;AAC3C,OAAO,EAAE,YAAY,EAA0B,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EACL,QAAQ,EACR,uBAAuB,EACvB,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AAEnC,kCAAkC;AAClC,8EAA8E;AAC9E,4BAA4B;AAC5B,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAM7E,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,EAC7B,gCAAgC,EAChC,yBAAyB,EACzB,kCAAkC,EAClC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,97 @@
1
+ import type { FrameworkAdapter } from "./framework.js";
2
+ import type { ContentSnapshot } from "./snapshot.js";
3
+ /**
4
+ * Heading metadata emitted by the MDX `headings` export (T4). Cross-ref:
5
+ * `crates/zfb-content/src/mdx_jsx_emit.rs`. Optional on the page-module
6
+ * shape — non-MDX pages won't carry it.
7
+ */
8
+ export interface PageHeading {
9
+ readonly depth: number;
10
+ readonly slug: string;
11
+ readonly text: string;
12
+ }
13
+ /**
14
+ * The shape every page module must export.
15
+ *
16
+ * - `default`: the JSX page component. Called with the props returned by
17
+ * `getStaticProps` (if exported) or the `props` from the matching
18
+ * `paths()` entry (for dynamic routes). The return value is fed straight
19
+ * to the framework adapter's `renderToString`.
20
+ * - `prerender`: literal `false` opts a route OUT of build-time SSG (T5
21
+ * contract). The page router still serves it under the embedded V8 host
22
+ * so dev mode behaves identically; SSG callers filter the route list before
23
+ * driving the renderer.
24
+ * - `contentType`: optional override for non-HTML routes (e.g.
25
+ * `application/xml` for `rss.xml.tsx`). Default is
26
+ * `text/html; charset=utf-8`. Cross-ref shipped #49.
27
+ * - `headings`: optional list emitted by MDX (T4).
28
+ * - `paths`: optional dynamic-route enumerator. Called at build time by
29
+ * the `__paths__` synthetic endpoint to produce the concrete URL list
30
+ * for this route template. May be async. Returns an array of
31
+ * `{ params, props? }` objects identical in shape to the Astro/zfb
32
+ * `paths()` contract.
33
+ * - `getStaticProps`: optional async function for static routes that need
34
+ * to fetch data at build/render time. Called once per request (before
35
+ * `default`). Must return `{ props: Record<string, unknown> }`. The
36
+ * returned `props` are spread into the `default` component's props.
37
+ */
38
+ export interface PageModule {
39
+ readonly default: (props: Record<string, unknown>) => unknown;
40
+ readonly prerender?: boolean;
41
+ readonly contentType?: string;
42
+ readonly headings?: readonly PageHeading[];
43
+ readonly paths?: () => unknown[] | Promise<unknown[]>;
44
+ readonly getStaticProps?: () => Promise<{
45
+ props: Record<string, unknown>;
46
+ }>;
47
+ }
48
+ /**
49
+ * One page registered with the router.
50
+ *
51
+ * `route` is a Hono path pattern (e.g. `/`, `/blog/:slug`,
52
+ * `/blog/page/:page`). `module` is a thunk so the bundle can use code
53
+ * splitting if it wants to — today the bundler emits everything as one
54
+ * ESM file and the thunk simply returns the already-loaded module.
55
+ */
56
+ export interface PageDefinition {
57
+ readonly route: string;
58
+ readonly module: () => Promise<PageModule>;
59
+ }
60
+ /** Options accepted by [`createPageRouter`]. */
61
+ export interface CreatePageRouterOptions {
62
+ /** Pages to register. Order does not affect routing — Hono dispatches by path. */
63
+ readonly pages: readonly PageDefinition[];
64
+ /**
65
+ * In-memory content snapshot. Embedded into the bundle by T3; the
66
+ * router hands it to `zfb/content` so user pages reading content via
67
+ * `getCollection(...)` resolve synchronously from memory.
68
+ */
69
+ readonly contentSnapshot: ContentSnapshot;
70
+ /** Framework adapter pinning the SSR call. */
71
+ readonly framework: FrameworkAdapter;
72
+ }
73
+ /**
74
+ * Fetch-handler shape returned by [`createPageRouter`]. Shaped as a plain
75
+ * function (not a Hono `app`) so the consumer's contract is exactly
76
+ * "Worker-style fetch handler" with no leaked framework types.
77
+ */
78
+ export type PageRouter = (request: Request) => Promise<Response>;
79
+ /**
80
+ * Build a page router for the SSG-first architecture (ADR-005).
81
+ *
82
+ * Side effects:
83
+ * 1. Registers `opts.contentSnapshot` with the `zfb/content` module so
84
+ * `getCollection(name)` resolves from memory. Idempotent across
85
+ * calls — the latest snapshot wins (matches the documented dev-mode
86
+ * live-reload contract).
87
+ * 2. Constructs an internal Hono app and registers a GET handler per
88
+ * `pages[i].route`. The handler imports the page module, calls
89
+ * `framework.renderToString(module.default({}))`, and returns the
90
+ * string in a `Response` with the appropriate `Content-Type`.
91
+ *
92
+ * The returned function is a plain `(request) => Promise<Response>` so a
93
+ * Worker entry point can `export default { fetch: createPageRouter(...) }`
94
+ * directly.
95
+ */
96
+ export declare function createPageRouter(opts: CreatePageRouterOptions): PageRouter;
97
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAMrD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACtD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;CAC7E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;CAC5C;AAED,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAejE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,UAAU,CA0P1E"}
package/dist/router.js ADDED
@@ -0,0 +1,318 @@
1
+ // `@takazudo/zfb-runtime` — Hono-based page router.
2
+ //
3
+ // `createPageRouter` is the JS-side entry point for ADR-007's SSG-first
4
+ // architecture. The pipeline goes:
5
+ //
6
+ // user pages/ + content/ + layouts/ + components/
7
+ // → esbuild bundle (T3) // single ESM file
8
+ // → embedded V8 host (T6) // same WinterCG surface as CF Workers
9
+ // → createPageRouter({ pages, contentSnapshot, framework })
10
+ // → (request) => Promise<Response>
11
+ //
12
+ // The bundle's Worker entry point shape is documented in the package
13
+ // README. The contract is intentionally minimal: one factory call returns
14
+ // one fetch handler. Hono is an implementation detail — callers should
15
+ // not depend on the Hono types leaking through. The exposed surface is
16
+ // the four types here plus the `createPageRouter` function.
17
+ //
18
+ // Side effect on init: registers the supplied `ContentSnapshot` with
19
+ // `zfb/content`'s module-level snapshot bridge so any page module
20
+ // importing `getCollection("...")` resolves from memory rather than
21
+ // touching the Node `fs` API (the Worker runtime has no `fs`).
22
+ //
23
+ // ## Synthetic `__paths__` endpoint
24
+ //
25
+ // The Rust build pipeline needs to evaluate non-literal `paths()` exports
26
+ // (e.g. those that `await import("@takazudo/zfb/content")` and call `getCollection`)
27
+ // at runtime against the running embedded host. The router exposes a
28
+ // synthetic internal endpoint:
29
+ //
30
+ // GET /__paths__/<percent-encoded-route-key>
31
+ //
32
+ // When a page registered at `route` has a `paths` export, the handler calls
33
+ // it and returns the JSON-serialized array as `application/json`. If the
34
+ // `paths` export is missing or throws, the response is a descriptive 500.
35
+ // This endpoint is only meant for the build pipeline — it is safe to leave
36
+ // registered in production because no user-authored route should start with
37
+ // `/__paths__/` (the build pipeline rejects any route that conflicts).
38
+ import { Hono } from "hono";
39
+ import { setContentSnapshot } from "@takazudo/zfb/content";
40
+ // ---------------------------------------------------------------------------
41
+ // Implementation
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Default content-type when a page module does not override.
45
+ *
46
+ * Aligned with #49's per-page `contentType` convention: the default
47
+ * served for HTML pages is `text/html; charset=utf-8`. Tests pin this
48
+ * verbatim because the embedded V8 host does NOT auto-set a charset.
49
+ */
50
+ const DEFAULT_CONTENT_TYPE = "text/html; charset=utf-8";
51
+ /**
52
+ * Build a page router for the SSG-first architecture (ADR-005).
53
+ *
54
+ * Side effects:
55
+ * 1. Registers `opts.contentSnapshot` with the `zfb/content` module so
56
+ * `getCollection(name)` resolves from memory. Idempotent across
57
+ * calls — the latest snapshot wins (matches the documented dev-mode
58
+ * live-reload contract).
59
+ * 2. Constructs an internal Hono app and registers a GET handler per
60
+ * `pages[i].route`. The handler imports the page module, calls
61
+ * `framework.renderToString(module.default({}))`, and returns the
62
+ * string in a `Response` with the appropriate `Content-Type`.
63
+ *
64
+ * The returned function is a plain `(request) => Promise<Response>` so a
65
+ * Worker entry point can `export default { fetch: createPageRouter(...) }`
66
+ * directly.
67
+ */
68
+ export function createPageRouter(opts) {
69
+ setContentSnapshot(opts.contentSnapshot);
70
+ const app = new Hono();
71
+ // Build a lookup map: Hono route pattern → PageDefinition, for the
72
+ // `__paths__` synthetic endpoint below. The map is keyed on the `route`
73
+ // string exactly as the caller supplied it (e.g. "/blog/:slug").
74
+ const pagesByRoute = new Map();
75
+ for (const page of opts.pages) {
76
+ pagesByRoute.set(page.route, page);
77
+ }
78
+ // Sanity check: a user-authored route that happens to start with
79
+ // `/__paths__` (or a top-level catchall like `/:slug{.+}`) would
80
+ // shadow the synthetic endpoint registered below if Hono dispatched
81
+ // by registration order. We register `/__paths__/:routeKey{.+}` first
82
+ // (see directly below) but still warn on collisions so users do not
83
+ // ship a page that conflicts with the build pipeline's wire format.
84
+ for (const page of opts.pages) {
85
+ if (routeShadowsPathsEndpoint(page.route)) {
86
+ // Use console.warn so the message reaches the host's tail logs
87
+ // without bringing down the worker. The build pipeline's
88
+ // /__paths__ requests still resolve correctly because the
89
+ // synthetic handler is registered first.
90
+ // eslint-disable-next-line no-console
91
+ console.warn(`[zfb-runtime] route "${page.route}" may shadow the synthetic /__paths__ endpoint; rename the page or use a more specific pattern`);
92
+ }
93
+ }
94
+ // -------------------------------------------------------------------------
95
+ // Synthetic `/__paths__/<encoded-route-key>` endpoint.
96
+ //
97
+ // Called by the Rust build pipeline (crates/zfb/src/render_pipeline.rs)
98
+ // to evaluate non-literal `paths()` exports at runtime. The route key is
99
+ // the Hono pattern for the page (e.g. `/blog/:slug`) percent-encoded so
100
+ // it survives in the URL path segment. The response is a JSON array of
101
+ // `{ params, props? }` objects identical to the `paths()` contract.
102
+ //
103
+ // Pattern: `/__paths__/:routeKey{.+}` — the `{.+}` quantifier (Hono's
104
+ // regex-segment syntax) allows slashes inside the route key so
105
+ // `/blog/:slug` decodes correctly from `/__paths__/%2Fblog%2F%3Aslug`.
106
+ //
107
+ // IMPORTANT: this handler is registered BEFORE user routes so a
108
+ // user-authored top-level catchall (e.g. `/:wildcard{.+}`) cannot
109
+ // shadow it — Hono dispatches in registration order.
110
+ // -------------------------------------------------------------------------
111
+ app.get("/__paths__/:routeKey{.+}", async (c) => {
112
+ // Hono's `c.req.param("routeKey")` already URL-decodes the captured
113
+ // segment when it contains a `%`, so a single decode is correct
114
+ // here — no explicit `decodeURIComponent` (that would be a
115
+ // double-decode and break literal `%` characters in route keys).
116
+ const routeKey = c.req.param("routeKey");
117
+ const page = pagesByRoute.get(routeKey);
118
+ if (!page) {
119
+ return c.body(`[zfb-runtime] /__paths__: no page registered for route key "${routeKey}"`, 404, { "Content-Type": "text/plain; charset=utf-8" });
120
+ }
121
+ const mod = await page.module();
122
+ if (typeof mod.paths !== "function") {
123
+ return c.body(`[zfb-runtime] /__paths__: page module for "${routeKey}" has no paths() export`, 404, { "Content-Type": "text/plain; charset=utf-8" });
124
+ }
125
+ let result;
126
+ try {
127
+ result = await mod.paths();
128
+ }
129
+ catch (err) {
130
+ const msg = err instanceof Error ? err.message : String(err);
131
+ return c.body(`[zfb-runtime] /__paths__: paths() threw for "${routeKey}": ${msg}`, 500, {
132
+ "Content-Type": "text/plain; charset=utf-8",
133
+ });
134
+ }
135
+ return c.body(JSON.stringify(result), 200, {
136
+ "Content-Type": "application/json; charset=utf-8",
137
+ });
138
+ });
139
+ for (const page of opts.pages) {
140
+ // `app.all` (vs `app.get`) so SSR routes whose page handler dispatches
141
+ // by `request.method` (e.g. POST API endpoints like
142
+ // `pages/api/*.tsx`) actually reach the handler. The handler is then
143
+ // responsible for returning a method-appropriate status (e.g. 405 for
144
+ // an unsupported verb). With `app.get` the inner router would 404
145
+ // before the handler ever ran, leaving e.g. `POST /api/foo` looking
146
+ // identical to a missing route.
147
+ app.all(page.route, async (c) => {
148
+ const mod = await page.module();
149
+ if (typeof mod.default !== "function") {
150
+ // Surface as a 500 with a well-known message rather than letting
151
+ // Hono swallow the error into a generic body. T6's embedded V8
152
+ // host log-tail / source-map plumbing is what eventually projects
153
+ // page-side errors back to the user's TSX line; until then the
154
+ // pinned message is the contract this layer ships.
155
+ return c.body(`[zfb-runtime] page module for "${page.route}" did not export a default component`, 500, { "Content-Type": "text/plain; charset=utf-8" });
156
+ }
157
+ // For dynamic routes that export `paths()`, look up the concrete
158
+ // entry for this URL by matching the URL params against the
159
+ // paths() results. This implements the ADR-002 contract:
160
+ // paths() → [{ params, props? }]
161
+ // render(url) → find matching entry → pass { params, props } to default()
162
+ //
163
+ // For static routes (no `paths()` export, no URL params), we pass
164
+ // an empty object — the component signature has no required props.
165
+ // For dynamic routes whose URL params do not match any paths()
166
+ // entry, we return a 404 rather than rendering with empty props.
167
+ const rawUrlParams = c.req.param();
168
+ const urlParams = (rawUrlParams ?? {});
169
+ const hasDynamicParams = Object.keys(urlParams).length > 0;
170
+ let componentInput = {};
171
+ if (hasDynamicParams && typeof mod.paths === "function") {
172
+ let pathsResult;
173
+ try {
174
+ pathsResult = await mod.paths();
175
+ }
176
+ catch (err) {
177
+ const msg = err instanceof Error ? err.message : String(err);
178
+ return c.body(`[zfb-runtime] paths() threw for "${page.route}": ${msg}`, 500, {
179
+ "Content-Type": "text/plain; charset=utf-8",
180
+ });
181
+ }
182
+ if (!Array.isArray(pathsResult)) {
183
+ return c.body(`[zfb-runtime] paths() for "${page.route}" did not return an array`, 500, {
184
+ "Content-Type": "text/plain; charset=utf-8",
185
+ });
186
+ }
187
+ // Validate each entry's shape per-entry rather than using a bare
188
+ // cast — matches the strictness the Rust pipeline applies on the
189
+ // same wire format. Any malformed entry surfaces as a 500.
190
+ for (const entry of pathsResult) {
191
+ if (!isPathsEntry(entry)) {
192
+ return c.body(`[zfb-runtime] paths() for "${page.route}" returned an entry without a valid params object`, 500, { "Content-Type": "text/plain; charset=utf-8" });
193
+ }
194
+ }
195
+ // Find the entry whose params match the URL params for this
196
+ // request. For catchall params (e.g. slug for
197
+ // /docs/[...slug]), Hono returns a slash-joined string (e.g.
198
+ // "guides/install"), so we compare against the paths() entry's
199
+ // params.slug joined with "/".
200
+ const match = pathsResult.find((entry) => {
201
+ return Object.entries(urlParams).every(([k, v]) => {
202
+ const paramVal = entry.params[k];
203
+ if (Array.isArray(paramVal)) {
204
+ // catchall: paths() emits slug as string[] but Hono
205
+ // provides it as a "/"-joined string
206
+ return paramVal.join("/") === v;
207
+ }
208
+ return String(paramVal) === v;
209
+ });
210
+ });
211
+ if (!match) {
212
+ // The URL params do not correspond to any paths() entry —
213
+ // this is the dev-mode equivalent of a build-time miss.
214
+ // Hono's `c.notFound()` returns the framework's default 404,
215
+ // which is cleaner than fabricating an empty-props render.
216
+ return c.notFound();
217
+ }
218
+ // Pass the paths() entry's props directly as component props
219
+ // (spread to top level, matching the Astro/zfb convention).
220
+ // Also include `params` so components can access URL params if
221
+ // needed, but individual prop keys from `props` win on collision.
222
+ componentInput = {
223
+ params: match.params,
224
+ ...(match.props ?? {}),
225
+ };
226
+ }
227
+ else if (!hasDynamicParams && typeof mod.getStaticProps === "function") {
228
+ // Static route with `getStaticProps`: call it to fetch build-time
229
+ // data and pass the returned props to the default component. This
230
+ // supports the `export async function getStaticProps()` pattern
231
+ // used by static pages that need to query content collections (e.g.
232
+ // a homepage listing all blog posts via `getCollection("blog")`).
233
+ let staticPropsResult;
234
+ try {
235
+ staticPropsResult = await mod.getStaticProps();
236
+ }
237
+ catch (err) {
238
+ const msg = err instanceof Error ? err.message : String(err);
239
+ return c.body(`[zfb-runtime] getStaticProps() threw for "${page.route}": ${msg}`, 500, {
240
+ "Content-Type": "text/plain; charset=utf-8",
241
+ });
242
+ }
243
+ if (typeof staticPropsResult !== "object" ||
244
+ staticPropsResult === null ||
245
+ !("props" in staticPropsResult)) {
246
+ return c.body(`[zfb-runtime] getStaticProps() for "${page.route}" must return { props: {...} }`, 500, { "Content-Type": "text/plain; charset=utf-8" });
247
+ }
248
+ componentInput = staticPropsResult.props;
249
+ }
250
+ // `await` so async page modules (e.g. API routes typed as
251
+ // `(): Promise<Response>`) resolve before we inspect the value.
252
+ // For sync pages that return a VNode/string the await is a no-op.
253
+ const result = await mod.default(componentInput);
254
+ // API route short-circuit: a page module that returns a Response
255
+ // directly (e.g. `pages/api/*.tsx` handlers that use Web Fetch
256
+ // primitives instead of returning JSX) is responsible for its own
257
+ // status, headers, and body — return it as-is rather than running
258
+ // it through the framework SSR path.
259
+ if (result instanceof Response) {
260
+ return result;
261
+ }
262
+ // Non-HTML routes (e.g. `sitemap.xml.tsx`, `feed.xml.tsx`) commonly
263
+ // return their body as a pre-serialised `string` instead of a
264
+ // VNode. Routing those through `framework.renderToString` would
265
+ // HTML-escape the angle brackets and ampersands, producing
266
+ // garbage XML. Pass strings through verbatim; only wrap actual
267
+ // VNodes.
268
+ const html = typeof result === "string" ? result : opts.framework.renderToString(result);
269
+ const contentType = mod.contentType ?? DEFAULT_CONTENT_TYPE;
270
+ return c.body(html, 200, { "Content-Type": contentType });
271
+ });
272
+ }
273
+ // Hono's `app.fetch` returns `Response | Promise<Response>`. The
274
+ // public router contract is unconditionally async; using an `async`
275
+ // wrapper (rather than `Promise.resolve(...)`) ensures any
276
+ // synchronous throw inside `app.fetch` is converted to a rejected
277
+ // promise instead of escaping the caller's `await`.
278
+ return async (request) => await app.fetch(request);
279
+ }
280
+ /**
281
+ * Type guard for one `paths()` entry. Mirrors the strictness of the
282
+ * Rust pipeline's `paths()` resolver — every entry must be a non-null
283
+ * object whose `params` is itself a non-null object.
284
+ */
285
+ function isPathsEntry(x) {
286
+ if (typeof x !== "object" || x === null)
287
+ return false;
288
+ const params = x.params;
289
+ return typeof params === "object" && params !== null;
290
+ }
291
+ /**
292
+ * Heuristic check for user-authored routes that may shadow the
293
+ * synthetic `/__paths__/<encoded-route-key>` endpoint.
294
+ *
295
+ * Returns true when the route literal contains `/__paths__` (an
296
+ * obvious collision) or when its first segment is a Hono catchall
297
+ * (`:name{.+}`) or a file-system catchall (`[...name]`) at the root —
298
+ * those would match `/__paths__/...` once Hono dispatches to them.
299
+ */
300
+ function routeShadowsPathsEndpoint(route) {
301
+ if (route.includes("/__paths__")) {
302
+ return true;
303
+ }
304
+ // Strip the leading slash and look at the first segment only —
305
+ // anything deeper cannot match `/__paths__` because the literal
306
+ // first segment differs.
307
+ const firstSeg = route.replace(/^\/+/, "").split("/")[0] ?? "";
308
+ // Hono regex-quantifier catchall: `:name{.+}`.
309
+ if (/^:[A-Za-z_][\w]*\{\.[+*]\}$/.test(firstSeg)) {
310
+ return true;
311
+ }
312
+ // File-system catchall (pre-bracket-to-hono): `[...name]`.
313
+ if (/^\[\.\.\.[A-Za-z_][\w]*\]$/.test(firstSeg)) {
314
+ return true;
315
+ }
316
+ return false;
317
+ }
318
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,wEAAwE;AACxE,mCAAmC;AACnC,EAAE;AACF,oDAAoD;AACpD,0DAA0D;AAC1D,8EAA8E;AAC9E,gEAAgE;AAChE,uCAAuC;AACvC,EAAE;AACF,qEAAqE;AACrE,0EAA0E;AAC1E,uEAAuE;AACvE,uEAAuE;AACvE,4DAA4D;AAC5D,EAAE;AACF,qEAAqE;AACrE,kEAAkE;AAClE,oEAAoE;AACpE,+DAA+D;AAC/D,EAAE;AACF,oCAAoC;AACpC,EAAE;AACF,0EAA0E;AAC1E,qFAAqF;AACrF,qEAAqE;AACrE,+BAA+B;AAC/B,EAAE;AACF,+CAA+C;AAC/C,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,uEAAuE;AAEvE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAwF3D,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAExD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAA6B;IAC5D,kBAAkB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAEzC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,mEAAmE;IACnE,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,YAAY,GAAG,IAAI,GAAG,EAA0B,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,iEAAiE;IACjE,iEAAiE;IACjE,oEAAoE;IACpE,sEAAsE;IACtE,oEAAoE;IACpE,oEAAoE;IACpE,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,+DAA+D;YAC/D,yDAAyD;YACzD,0DAA0D;YAC1D,yCAAyC;YACzC,sCAAsC;YACtC,OAAO,CAAC,IAAI,CACV,wBAAwB,IAAI,CAAC,KAAK,gGAAgG,CACnI,CAAC;QACJ,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,uDAAuD;IACvD,EAAE;IACF,wEAAwE;IACxE,yEAAyE;IACzE,wEAAwE;IACxE,uEAAuE;IACvE,oEAAoE;IACpE,EAAE;IACF,sEAAsE;IACtE,+DAA+D;IAC/D,uEAAuE;IACvE,EAAE;IACF,gEAAgE;IAChE,kEAAkE;IAClE,qDAAqD;IACrD,4EAA4E;IAC5E,GAAG,CAAC,GAAG,CAAC,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9C,oEAAoE;QACpE,gEAAgE;QAChE,2DAA2D;QAC3D,iEAAiE;QACjE,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAEzC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,CAAC,IAAI,CACX,+DAA+D,QAAQ,GAAG,EAC1E,GAAG,EACH,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAChD,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACpC,OAAO,CAAC,CAAC,IAAI,CACX,8CAA8C,QAAQ,yBAAyB,EAC/E,GAAG,EACH,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAChD,CAAC;QACJ,CAAC;QAED,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC,IAAI,CAAC,gDAAgD,QAAQ,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE;gBACtF,cAAc,EAAE,2BAA2B;aAC5C,CAAC,CAAC;QACL,CAAC;QAED,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE;YACzC,cAAc,EAAE,iCAAiC;SAClD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,uEAAuE;QACvE,oDAAoD;QACpD,qEAAqE;QACrE,sEAAsE;QACtE,kEAAkE;QAClE,oEAAoE;QACpE,gCAAgC;QAChC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC9B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;gBACtC,iEAAiE;gBACjE,+DAA+D;gBAC/D,kEAAkE;gBAClE,+DAA+D;gBAC/D,mDAAmD;gBACnD,OAAO,CAAC,CAAC,IAAI,CACX,kCAAkC,IAAI,CAAC,KAAK,sCAAsC,EAClF,GAAG,EACH,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAChD,CAAC;YACJ,CAAC;YAED,iEAAiE;YACjE,4DAA4D;YAC5D,yDAAyD;YACzD,mCAAmC;YACnC,4EAA4E;YAC5E,EAAE;YACF,kEAAkE;YAClE,mEAAmE;YACnE,+DAA+D;YAC/D,iEAAiE;YACjE,MAAM,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,SAAS,GAAG,CAAC,YAAY,IAAI,EAAE,CAA2B,CAAC;YACjE,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAE3D,IAAI,cAAc,GAA4B,EAAE,CAAC;YAEjD,IAAI,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;gBACxD,IAAI,WAAoB,CAAC;gBACzB,IAAI,CAAC;oBACH,WAAW,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;gBAClC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC7D,OAAO,CAAC,CAAC,IAAI,CAAC,oCAAoC,IAAI,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE;wBAC5E,cAAc,EAAE,2BAA2B;qBAC5C,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;oBAChC,OAAO,CAAC,CAAC,IAAI,CAAC,8BAA8B,IAAI,CAAC,KAAK,2BAA2B,EAAE,GAAG,EAAE;wBACtF,cAAc,EAAE,2BAA2B;qBAC5C,CAAC,CAAC;gBACL,CAAC;gBAED,iEAAiE;gBACjE,iEAAiE;gBACjE,2DAA2D;gBAC3D,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;oBAChC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;wBACzB,OAAO,CAAC,CAAC,IAAI,CACX,8BAA8B,IAAI,CAAC,KAAK,mDAAmD,EAC3F,GAAG,EACH,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAChD,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,4DAA4D;gBAC5D,8CAA8C;gBAC9C,6DAA6D;gBAC7D,+DAA+D;gBAC/D,+BAA+B;gBAC/B,MAAM,KAAK,GAAI,WAA4B,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;oBACzD,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;wBAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;wBACjC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC5B,oDAAoD;4BACpD,qCAAqC;4BACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;wBAClC,CAAC;wBACD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAChC,CAAC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;gBAEH,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,0DAA0D;oBAC1D,wDAAwD;oBACxD,6DAA6D;oBAC7D,2DAA2D;oBAC3D,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACtB,CAAC;gBAED,6DAA6D;gBAC7D,4DAA4D;gBAC5D,+DAA+D;gBAC/D,kEAAkE;gBAClE,cAAc,GAAG;oBACf,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;iBACvB,CAAC;YACJ,CAAC;iBAAM,IAAI,CAAC,gBAAgB,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,UAAU,EAAE,CAAC;gBACzE,kEAAkE;gBAClE,kEAAkE;gBAClE,gEAAgE;gBAChE,oEAAoE;gBACpE,kEAAkE;gBAClE,IAAI,iBAA0B,CAAC;gBAC/B,IAAI,CAAC;oBACH,iBAAiB,GAAG,MAAM,GAAG,CAAC,cAAc,EAAE,CAAC;gBACjD,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC7D,OAAO,CAAC,CAAC,IAAI,CAAC,6CAA6C,IAAI,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE;wBACrF,cAAc,EAAE,2BAA2B;qBAC5C,CAAC,CAAC;gBACL,CAAC;gBACD,IACE,OAAO,iBAAiB,KAAK,QAAQ;oBACrC,iBAAiB,KAAK,IAAI;oBAC1B,CAAC,CAAC,OAAO,IAAI,iBAAiB,CAAC,EAC/B,CAAC;oBACD,OAAO,CAAC,CAAC,IAAI,CACX,uCAAuC,IAAI,CAAC,KAAK,gCAAgC,EACjF,GAAG,EACH,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAChD,CAAC;gBACJ,CAAC;gBACD,cAAc,GAAI,iBAAwD,CAAC,KAAK,CAAC;YACnF,CAAC;YAED,0DAA0D;YAC1D,gEAAgE;YAChE,kEAAkE;YAClE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YACjD,iEAAiE;YACjE,+DAA+D;YAC/D,kEAAkE;YAClE,kEAAkE;YAClE,qCAAqC;YACrC,IAAI,MAAM,YAAY,QAAQ,EAAE,CAAC;gBAC/B,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,oEAAoE;YACpE,8DAA8D;YAC9D,gEAAgE;YAChE,2DAA2D;YAC3D,+DAA+D;YAC/D,UAAU;YACV,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACzF,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,oBAAoB,CAAC;YAC5D,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,iEAAiE;IACjE,oEAAoE;IACpE,2DAA2D;IAC3D,kEAAkE;IAClE,oDAAoD;IACpD,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACrD,CAAC;AAaD;;;;GAIG;AACH,SAAS,YAAY,CAAC,CAAU;IAC9B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,MAAM,GAAI,CAA0B,CAAC,MAAM,CAAC;IAClD,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC;AACvD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,yBAAyB,CAAC,KAAa;IAC9C,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,+DAA+D;IAC/D,gEAAgE;IAChE,yBAAyB;IACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,+CAA+C;IAC/C,IAAI,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,2DAA2D;IAC3D,IAAI,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * One entry in a content collection, in the shape the JS bridge sees.
3
+ *
4
+ * Mirrors `crates/zfb-content/src/content_bridge.rs::EntrySnapshot`.
5
+ *
6
+ * - `slug`: filename stem (no extension).
7
+ * - `frontmatter`: parsed frontmatter — `null` when the source had none.
8
+ * Type-erased to `unknown` here; user pages narrow via the generic on
9
+ * `getCollection<T>()`.
10
+ * - `body`: markdown body for `.md` / `.mdx` entries; empty string for
11
+ * `.tsx` entries (TSX has no separate markdown body).
12
+ * - `module_specifier`: stable specifier addressing the compiled module
13
+ * (`mdx://collection/slug#hash` / `tsx://collection/slug#hash`). The
14
+ * bridge resolver matches either the full-with-hash form or the
15
+ * no-hash form `mdx://collection/slug`.
16
+ * - `rel_path`: path relative to the collection root, normalized to
17
+ * forward slashes so JSON is platform-stable.
18
+ */
19
+ export interface EntrySnapshot {
20
+ readonly slug: string;
21
+ readonly frontmatter: unknown;
22
+ readonly body: string;
23
+ readonly module_specifier: string;
24
+ readonly rel_path: string;
25
+ }
26
+ /**
27
+ * Point-in-time snapshot of every configured collection.
28
+ *
29
+ * Mirrors `crates/zfb-content/src/content_bridge.rs::ContentSnapshot`.
30
+ *
31
+ * Iteration order is documented as deterministic on the Rust side
32
+ * (collections sorted by name, entries sorted by slug). The snapshot
33
+ * delivered to JS preserves that order via stable JSON serialization.
34
+ */
35
+ export interface ContentSnapshot {
36
+ readonly collections: Readonly<Record<string, readonly EntrySnapshot[]>>;
37
+ }
38
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC,CAAC,CAAC;CAC1E"}
@@ -0,0 +1,16 @@
1
+ // `@takazudo/zfb-runtime/snapshot` — TypeScript mirror of the Rust
2
+ // `ContentSnapshot` contract.
3
+ //
4
+ // The canonical shape lives in Rust at `crates/zfb-content/src/content_bridge.rs`
5
+ // (see `ContentSnapshot` and `EntrySnapshot`). The build-time pipeline
6
+ // constructs the snapshot, serializes it to JSON, and embeds it in the
7
+ // Worker bundle that the embedded V8 host loads. At Worker boot the embedded value
8
+ // is handed to [`createPageRouter`] (re-exported from the package root),
9
+ // which registers it with the `zfb/content` module so user pages calling
10
+ // `getCollection("blog")` resolve from memory rather than from the
11
+ // filesystem.
12
+ //
13
+ // Keep this in sync with the Rust struct. Field names are snake_case to
14
+ // match the JSON serialization (`module_specifier`, `rel_path`).
15
+ export {};
16
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,8BAA8B;AAC9B,EAAE;AACF,kFAAkF;AAClF,uEAAuE;AACvE,uEAAuE;AACvE,mFAAmF;AACnF,yEAAyE;AACzE,yEAAyE;AACzE,mEAAmE;AACnE,cAAc;AACd,EAAE;AACF,wEAAwE;AACxE,iEAAiE"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Public element shape — kept structural so consumers don't infer through
3
+ * either framework's internal VNode type. Matches the shape `Island`
4
+ * returns from `@takazudo/zfb`.
5
+ */
6
+ export type ViewTransitionsElement = {
7
+ readonly type: string;
8
+ readonly props: Readonly<Record<string, unknown>>;
9
+ readonly key: unknown;
10
+ };
11
+ /**
12
+ * `<ViewTransitions />` — DEPRECATED: this component is now a typed
13
+ * no-op. Cross-document View Transitions are opted in via the
14
+ * `@view-transition { navigation: auto; }` CSS at-rule, NOT via this
15
+ * component. Add the at-rule to your top-level stylesheet (outside
16
+ * any `@layer` block — see https://developer.mozilla.org/en-US/docs/Web/CSS/@view-transition).
17
+ *
18
+ * The export is kept so consumers' existing `<ViewTransitions />`
19
+ * mounts compile unchanged.
20
+ *
21
+ * The previous implementation injected an inline router IIFE that
22
+ * called `event.preventDefault()` and `document.startViewTransition`
23
+ * around `window.location.href = url`. That pattern is INCOMPATIBLE
24
+ * with cross-document VT: Chromium treats the script reload as
25
+ * excluded from `auto`, so no `::view-transition-*` pseudo-elements
26
+ * ever materialize. See
27
+ * https://developer.chrome.com/docs/web-platform/view-transitions/cross-document.
28
+ *
29
+ * @deprecated The runtime injection is removed. Use the
30
+ * `@view-transition` CSS at-rule on both source and destination
31
+ * documents.
32
+ */
33
+ export declare function ViewTransitions(): readonly ViewTransitionsElement[];
34
+ //# sourceMappingURL=view-transitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-transitions.d.ts","sourceRoot":"","sources":["../src/view-transitions.ts"],"names":[],"mappings":"AA6BA;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,IAAI,SAAS,sBAAsB,EAAE,CAEnE"}
@@ -0,0 +1,54 @@
1
+ // `@takazudo/zfb-runtime` — `<ViewTransitions />` component (typed no-op).
2
+ //
3
+ // For SPA soft-swap navigation with view-transition animation, use `<ClientRouter />`
4
+ // from this package — see `./client-router.ts`.
5
+ //
6
+ // Originally mirrored Astro's `<ViewTransitions />` integration by injecting
7
+ // (a) a `<meta name="view-transition" content="same-origin">` opt-in tag and
8
+ // (b) an inline client-router IIFE that intercepted same-origin `<a>` clicks
9
+ // and ran navigations through `document.startViewTransition`.
10
+ //
11
+ // Both pieces have since been deleted. The browser story moved on:
12
+ //
13
+ // - The meta-tag opt-in was a temporary experiment during Chromium's
14
+ // cross-document VT spec development. It has been superseded by the
15
+ // `@view-transition { navigation: auto; }` CSS at-rule (per MDN and
16
+ // https://developer.chrome.com/docs/web-platform/view-transitions/cross-document)
17
+ // and is no longer honoured by browsers that ship cross-document VT.
18
+ // - The click-intercept IIFE was actively harmful: it called
19
+ // `event.preventDefault()` and ran `window.location.href = url` inside
20
+ // `document.startViewTransition`. Chromium treats that script reload as
21
+ // EXCLUDED from the `auto` navigation type, so no `::view-transition-*`
22
+ // pseudo-elements ever materialise. The "router" prevented the very
23
+ // feature it claimed to enable.
24
+ //
25
+ // Cross-document View Transitions are now opted in via the
26
+ // `@view-transition { navigation: auto; }` CSS at-rule on both the source
27
+ // and destination documents. This component is a typed no-op kept so that
28
+ // existing `<ViewTransitions />` mounts compile unchanged.
29
+ /**
30
+ * `<ViewTransitions />` — DEPRECATED: this component is now a typed
31
+ * no-op. Cross-document View Transitions are opted in via the
32
+ * `@view-transition { navigation: auto; }` CSS at-rule, NOT via this
33
+ * component. Add the at-rule to your top-level stylesheet (outside
34
+ * any `@layer` block — see https://developer.mozilla.org/en-US/docs/Web/CSS/@view-transition).
35
+ *
36
+ * The export is kept so consumers' existing `<ViewTransitions />`
37
+ * mounts compile unchanged.
38
+ *
39
+ * The previous implementation injected an inline router IIFE that
40
+ * called `event.preventDefault()` and `document.startViewTransition`
41
+ * around `window.location.href = url`. That pattern is INCOMPATIBLE
42
+ * with cross-document VT: Chromium treats the script reload as
43
+ * excluded from `auto`, so no `::view-transition-*` pseudo-elements
44
+ * ever materialize. See
45
+ * https://developer.chrome.com/docs/web-platform/view-transitions/cross-document.
46
+ *
47
+ * @deprecated The runtime injection is removed. Use the
48
+ * `@view-transition` CSS at-rule on both source and destination
49
+ * documents.
50
+ */
51
+ export function ViewTransitions() {
52
+ return [];
53
+ }
54
+ //# sourceMappingURL=view-transitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-transitions.js","sourceRoot":"","sources":["../src/view-transitions.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,sFAAsF;AACtF,gDAAgD;AAChD,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,8DAA8D;AAC9D,EAAE;AACF,mEAAmE;AACnE,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,sFAAsF;AACtF,yEAAyE;AACzE,+DAA+D;AAC/D,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,oCAAoC;AACpC,EAAE;AACF,2DAA2D;AAC3D,0EAA0E;AAC1E,0EAA0E;AAC1E,2DAA2D;AAa3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,EAAE,CAAC;AACZ,CAAC"}