void-plugin-hono-jsx 0.1.0-rc.0 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.0](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-rc.1...v0.1.0) (2026-10-18)
4
+
5
+
6
+ ### Documentation
7
+
8
+ * prepare grouped 0.1.0 normal release ([3d1c3b8](https://github.com/ts-76/void-plugin-hono-jsx/commit/3d1c3b8a323103bcd78ed2716f4d4ecaa5dcf6dd))
9
+ * record RC.1 Workers verification and cleanup ([#109](https://github.com/ts-76/void-plugin-hono-jsx/issues/109)) ([54c0441](https://github.com/ts-76/void-plugin-hono-jsx/commit/54c0441a1d70fee55cad36a41f30f3308048e1f2))
10
+
11
+ ## [0.1.0-rc.1](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-rc.0...v0.1.0-rc.1) (2026-10-17)
12
+
13
+
14
+ ### Features
15
+
16
+ * add navigation fallback and Hono deferred rendering ([8475a73](https://github.com/ts-76/void-plugin-hono-jsx/commit/8475a737931df4bfb62b9d32c877eb03c76ef644))
17
+
3
18
  ## [0.1.0-rc.0](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-alpha.4...v0.1.0-rc.0) (2026-10-17)
4
19
 
5
20
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Experimental Hono Pages adapter for Void
1
+ # Hono JSX adapter for Void Pages
2
2
 
3
- This package integrates Hono JSX with Void Pages. This source documents the upcoming 0.1.0 RC/normal release; published alpha.4 has a different compatibility contract. Prereleases use `next`; normal releases move to `latest` after public verification. Before registry approval, use a local tarball. The package is [MIT licensed](LICENSE) and is not an official Void adapter.
3
+ This package integrates Hono JSX with Void Pages. This source prepares the first normal release, 0.1.0. RC.1 is published and verified; 0.1.0 is not public yet. Published alpha.4 has a different compatibility contract. Prereleases use `next`; normal releases move to `latest` after public verification. As checked on 2026-10-18, `next` selects RC.1 and `latest` still selects the historical alpha.1; use RC.1 explicitly or `@next` until normal-release verification and tag promotion. The package is [MIT licensed](LICENSE) and is not an official Void adapter.
4
4
 
5
5
  ## Supported versions
6
6
 
@@ -13,18 +13,18 @@ This package integrates Hono JSX with Void Pages. This source documents the upco
13
13
  | Vite Plus | Host Vite must satisfy the Vite range | 1.3.0 |
14
14
  | TypeScript | Project tooling | 7.0.2 |
15
15
 
16
- The upcoming RC targets Void 1.1 and Node 24 only. Published alpha.4 retains its earlier Void 0.x contract; it does not provide this support change or multipart transport. Old Void/launcher manifests remain historical comparison records, not release-selectable configurations. The two supported Hono-only consumers use Void 1.1.11 with plain Vite 8.3.4 or aligned Vite Plus 1.3.0 (host Vite 8.3.4). Ranges admit stable updates, but only locked fixtures are observed test results. New upstream releases require refreshed fixtures, full checks and audit review; prereleases and other Void minors are excluded.
16
+ The published RC.1 and normal-release preparation target Void 1.1 and Node 24 only. Published alpha.4 retains its earlier Void 0.x contract; it does not provide this support change or multipart transport. Old Void/launcher manifests remain historical comparison records, not release-selectable configurations. The two supported Hono-only consumers use Void 1.1.11 with plain Vite 8.3.4 or aligned Vite Plus 1.3.0 (host Vite 8.3.4). Ranges admit stable updates, but only locked fixtures are observed test results. New upstream releases require refreshed fixtures, full checks and audit review; prereleases and other Void minors are excluded.
17
17
 
18
- Alpha.4 introduced the expanded Link/Form APIs, island forms and graphs, deferred contracts, page options and optional Markdown. This source adds the Void 1.1 contract and multipart transport for the RC; use the local tarball until the RC is approved. Do not combine the RC setup instructions with alpha.4.
18
+ Alpha.4 introduced the expanded Link/Form APIs, island forms and graphs, deferred contracts, page options and optional Markdown. RC.1 includes the Void 1.1 contract, multipart transport, navigation fallback and deferredResult/use/Suspense support. Use the published RC.1 while 0.1.0 is being prepared; do not combine these instructions with alpha.4.
19
19
 
20
20
  ## Install
21
21
 
22
22
  Use Node 24.21.0 or newer within Node 24:
23
23
 
24
- The commands below target the RC line. Check registry availability after owner approval. Published alpha.4 does not accept Void 1.1; use a local tarball until the RC has been approved. Use Node >=24.21.0 <25.0.0.
24
+ The commands below install the publicly available RC.1. Published alpha.4 does not accept Void 1.1. Local tarballs remain available for source verification. Use Node >=24.21.0 <25.0.0.
25
25
 
26
26
  ```sh
27
- npm install void-plugin-hono-jsx@0.1.0-rc.0 hono@4.13.13
27
+ npm install void-plugin-hono-jsx@0.1.0-rc.1 hono@4.13.13
28
28
  npm install --save-dev void@1.1.11 vite@8.3.4 typescript@7.0.2
29
29
  ```
30
30
 
@@ -37,7 +37,7 @@ npm install --save-dev void@1.1.11 vite@8.3.4 typescript@7.0.2
37
37
 
38
38
  ## Configure
39
39
 
40
- `voidHonoJsx()` and `HonoJsxOptions` replace the earlier `voidHonoPages()` and `HonoPagesOptions` names. This is a breaking alpha API change; the old names are not exported. Alpha.3 uses the earlier names. Use a local tarball or a release containing this rename for the configuration below.
40
+ `voidHonoJsx()` and `HonoJsxOptions` replace the earlier `voidHonoPages()` and `HonoPagesOptions` names. This is a breaking alpha API change; the old names are not exported. Alpha.3 uses the earlier names; RC.1 exports the new names shown below.
41
41
 
42
42
  ```ts
43
43
  // vite.config.ts
@@ -110,7 +110,7 @@ The adapter snapshots FormData at submission and leaves `Content-Type` unset so
110
110
 
111
111
  Full Pages multipart uses a dedicated same-origin mutation request followed by **one explicit GET** through Void's public router on success. Void's public engine cannot consume a raw multipart body or an externally fetched page shell. The GET commits through normal Hono rendering, history, layout/head, navigation state and cancellation checks while preserving component state. It also reruns loaders and may re-evaluate deferred data; the resolved-deferred retention contract for JSON mutations does not apply to multipart. The destination must support a GET. Island multipart retains its existing success behavior: reload or redirect the document.
112
112
 
113
- This API is part of the release preparation branch and is not in published alpha.4. It does not add a multipart-capable public transport hook to Void or change the one-shot `action()` helper's body contract.
113
+ This API is included in RC.1 and is not in published alpha.4. It does not add a multipart-capable public transport hook to Void or change the one-shot `action()` helper's body contract.
114
114
 
115
115
  ## Static output and prerendering
116
116
 
@@ -171,7 +171,7 @@ The `load`, `visible`, `idle` and `media:(query)` policies use Void's shared sch
171
171
 
172
172
  ## Optional Markdown
173
173
 
174
- For this source and its Void 1.1 baseline, use the RC after approval or the local tarball steps above. Published alpha.4 has the Markdown exports but retains its earlier Void 0.x contract; alpha.3 predates this API. Add parser peers explicitly only when using Markdown:
174
+ For this source and its Void 1.1 baseline, use the published RC.1 or a local tarball. Published alpha.4 has the Markdown exports but retains its earlier Void 0.x contract; alpha.3 predates this API. Add parser peers explicitly only when using Markdown:
175
175
 
176
176
  ```sh
177
177
  npm install markdown-exit@1.3.0 yaml@2.9.1
@@ -192,7 +192,7 @@ Create `.md` files in the Pages directory. Standard Markdown, tables, authored H
192
192
 
193
193
  Markdown routes use document navigation, and static-only pages emit no executable script. Interactive/script pages reload on development edits; zero-script pages need a normal refresh. Raw HTML is preserved for repository-authored content, without sanitization for untrusted input. Markdown layout files, JSX-expression/tag-child island props, Shiki themes, footnotes, custom containers and a page-catalog virtual module are unsupported. Do not also configure `@void/md/plugin`. Ordinary Pages users do not need these parser peers. See the repository's [Markdown guide](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/markdown.md) for page examples, metadata scoping and the complete contract.
194
194
 
195
- ## Experimental limitations
195
+ ## Compatibility and rendering limits
196
196
 
197
197
  The virtual renderer/client entries follow version-specific conventions observed in Void's official adapter rather than a documented third-party registration API. Browser mounting redraws the SSR page; DOM reuse is not guaranteed. Local ISR uses Void's native direct-worker KV/Cache API runtime; managed edge behavior remains unverified. Unsupported modes fail clearly. Package publication and repository visibility are separate maintainer decisions.
198
198
 
@@ -230,8 +230,87 @@ The fixture binds local `ISR_CACHE` storage for Void production preview. Real de
230
230
 
231
231
  ## Known local development limitation
232
232
 
233
- On the tested macOS Void/Miniflare development runtime, a POST to an undefined named action can reset the next request on a reused connection. Declared-action browser behavior is verified; this transport edge case remains unresolved upstream. Managed runtime behavior for the edge case is unverified. This historical local limitation must be rechecked on the selected RC baseline; it is not evidence about managed production behavior.
233
+ On the tested macOS Void/Miniflare development runtime, a POST to an undefined named action can reset the next request on a reused connection. Declared-action browser behavior is verified; this transport edge case remains unresolved upstream. Managed runtime behavior for the edge case is unverified. On the RC.1 D1 fixture, an oversized-body rejection followed by another pooled request also failed locally; consuming the response body did not prevent it. Local negative checks isolate connections as a test workaround, not a repair. On 2026-10-18, direct Cloudflare HTTPS with RC.1 passed rejection/undefined-action requests followed by healthy GETs through the normal pool, without retries or Connection: close. That does not prove every environment or a forced single TCP socket. The [dated Workers record](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/cloudflare-rc1-verification.md) and [limitations ledger](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/known-limitations.md) separate observed behavior from remaining upstream diagnosis.
234
234
 
235
235
  ## RC and normal-release policy
236
236
 
237
- The planned first candidate is 0.1.0-rc.0 on next, followed by 0.1.0 after public-consumer and real Workers verification. It is not yet a published-release claim. Production ISR remains outside the initial guarantee. Patches in 0.1.x preserve documented APIs; breaking changes move to 0.2.0 or later. Read the [release contract](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/release-contract.md) and [security policy](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/SECURITY.md). Report vulnerabilities [privately](https://github.com/ts-76/void-plugin-hono-jsx/security/advisories/new).
237
+ RC.1 public bytes/signatures/provenance and registry consumers have been verified. Its direct Workers/D1 migration, redeployment and cleanup exercise is complete. The next target is 0.1.0 with a normal GitHub Release; that version still requires its own final candidate CI/audits, stage, owner approval and public verification before latest/next promotion. Production ISR remains outside the initial guarantee. Patches in 0.1.x preserve documented APIs; breaking changes move to 0.2.0 or later. Read the [release contract](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/release-contract.md) and [security policy](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/SECURITY.md). Report vulnerabilities [privately](https://github.com/ts-76/void-plugin-hono-jsx/security/advisories/new).
238
+
239
+
240
+ ### Common navigation fallback (included in RC.1)
241
+
242
+ Register a default-exported local TSX/JSX module by path. The plugin imports the
243
+ component into its client entry; it does not serialize a function in Vite config.
244
+
245
+ ```ts
246
+ voidHonoJsx({ navigationFallback: { component: './components/NavigationFallback.tsx', delay: 150 } })
247
+ ```
248
+
249
+ ```tsx
250
+ import type { NavigationFallbackProps } from 'void-plugin-hono-jsx/pages';
251
+ export default function Fallback({ navigation }: NavigationFallbackProps) {
252
+ return <p>Loading {navigation.location?.pathname}…</p>;
253
+ }
254
+ ```
255
+
256
+ The optional fallback appears after 150 ms by default, only while a GET visit is
257
+ loading. Fast/cache/prefetch visits that finish before the delay show nothing.
258
+ It is an additional live status region: the existing page, input DOM and layout
259
+ remain mounted and interactive. It never replaces that tree, commits navigation
260
+ or changes history/scroll. Completion, failure and superseding visits remove it;
261
+ a new slow visit starts its own delay. If the fallback component throws, it is
262
+ hidden for that visit and reported through the existing navigation-error event;
263
+ the page tree remains mounted, and a new visit can try the fallback again.
264
+ JSON/multipart submission UI remains under
265
+ `useNavigation()`/form pending state. SSR stays idle and emits no fallback.
266
+ Without this option, existing behavior is unchanged. The normal page reset and
267
+ preserveState/preserveScroll rules still apply when the destination commits.
268
+ This addition shipped in RC.1; RC.0 does not include it.
269
+
270
+
271
+ ### Hono use() / Suspense for deferred props (included in RC.1)
272
+
273
+ `deferredResult(state)` gives Hono a stable, render-only Promise. Void still runs
274
+ the resolver, delivers HTML callbacks/NDJSON and manages prefetch/navigation.
275
+ The existing `Deferred<T>` loading/value/error API remains available.
276
+
277
+ ```tsx
278
+ import { ErrorBoundary, Suspense, use, useState } from 'hono/jsx';
279
+ import { deferredResult, type Deferred, type DeferredResult } from 'void-plugin-hono-jsx/pages';
280
+ function Result({ result }: { result: DeferredResult<string> }) {
281
+ if (result.error) throw result.error;
282
+ return <p>{result.value}</p>;
283
+ }
284
+ function Value({ slow }: { slow: Deferred<string> }) {
285
+ const [failed, setFailed] = useState<DeferredResult<string> | null>(null);
286
+ const result = use(deferredResult(slow));
287
+ const fallback = <p role="alert">Could not load data.</p>;
288
+ if (failed === result) return fallback;
289
+ return <ErrorBoundary fallback={fallback}
290
+ onError={() => queueMicrotask(() => setFailed(result))}>
291
+ <Result result={result} />
292
+ </ErrorBoundary>;
293
+ }
294
+ export default function Page({ slow }: { slow: Deferred<string> }) {
295
+ return <Suspense fallback={<p>Loading…</p>}><Value slow={slow} /></Suspense>;
296
+ }
297
+ ```
298
+
299
+ Results fulfill with `{ value, error }`. Throw the error in a child of
300
+ ErrorBoundary, after `use()` returns. The example remembers that result after
301
+ `onError`: Hono 4 can leave an incomplete tree if the same failed child is thrown
302
+ again during a parent's navigation-state update. This also keeps its async SSR
303
+ ErrorBoundary out of the pending shell. The Promise itself never rejects,
304
+ avoiding an unhandled derived rejection from Hono Suspense's `finally(retry)`.
305
+ The Promise is allocated on first use and remains identical across Void's ref
306
+ replacement and JSON action retention. Each navigation/prop owns a separate
307
+ weakly held resource; cancellation/disposal is reported through Void's existing
308
+ reject callback. Do not cache a resource outside its page or start another fetch.
309
+
310
+ SSR deliberately uses an inert pending Promise so Hono emits its initial
311
+ fallback immediately; never await this helper on the server. Void alone delivers
312
+ the later result to the browser. The adapter does not send Hono replacement HTML
313
+ or wait for deferred data in its server renderer. Only full Pages are supported;
314
+ deferred islands/static remain unsupported. Upstream failed-prefetch null values
315
+ remain null (the success value type includes null); this helper does not repair
316
+ that upstream limitation. This API shipped in RC.1; RC.0 does not include it.
@@ -1,5 +1,8 @@
1
1
  import { type VoidRouterConfig } from 'void/pages-client';
2
- type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'>;
2
+ import { type NavigationFallbackOptions } from './navigation-fallback.tsx';
3
+ type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'> & {
4
+ navigationFallback?: NavigationFallbackOptions;
5
+ };
3
6
  type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
4
7
  export declare function startHonoPages(manifest: Manifest, options: NavigationOptions): Promise<void>;
5
8
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAMrG,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,yBAAyB,CAAC,CAAC;AAEtH,KAAK,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,gBAAgB,GAAG,wBAAwB,CAAC,CAAC;AAO/I,wBAAsB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,iBA0GlF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErG,OAAO,EAAsB,KAAK,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAK/F,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,yBAAyB,CAAC,GAAG;IAAE,kBAAkB,CAAC,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAE3K,KAAK,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,gBAAgB,GAAG,wBAAwB,CAAC,CAAC;AAO/I,wBAAsB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,iBA4GlF"}
@@ -4,6 +4,7 @@ import { jsx } from 'hono/jsx/dom/jsx-runtime';
4
4
  import { useLayoutEffect, useState } from 'hono/jsx';
5
5
  import { idleNavigationState } from 'void/pages-client';
6
6
  import { PageContext, RouterContext, NavigationContext, setActionRouter } from "void-plugin-hono-jsx/pages";
7
+ import { NavigationFallback } from './navigation-fallback.js';
7
8
  import { createHonoRouter } from './navigation.js';
8
9
  import { createDocumentHead } from './document-head.js';
9
10
  import { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.js';
@@ -13,6 +14,8 @@ function pageComponent(component) {
13
14
  return component;
14
15
  }
15
16
  export async function startHonoPages(manifest, options) {
17
+ if (options.navigationFallback && typeof options.navigationFallback.component !== 'function')
18
+ throw new Error('Hono Pages: navigationFallback must default-export a component function.');
16
19
  const root = document.getElementById('app');
17
20
  if (!root)
18
21
  throw new Error('Hono Pages: app root is missing.');
@@ -121,7 +124,7 @@ export async function startHonoPages(manifest, options) {
121
124
  }
122
125
  });
123
126
  };
124
- return _jsx(RouterContext.Provider, { value: navigation.router, children: _jsxs(NavigationContext.Provider, { value: pendingNavigation, children: [failed && _jsx("p", { role: "alert", children: "The page could not be loaded. Please try again." }), _jsx(ErrorBoundary, { onError: renderFailed, fallback: _jsx(_Fragment, {}), children: _jsx(PageFrame, { frame: frame }) }, recovery)] }) });
127
+ return _jsx(RouterContext.Provider, { value: navigation.router, children: _jsxs(NavigationContext.Provider, { value: pendingNavigation, children: [failed && _jsx("p", { role: "alert", children: "The page could not be loaded. Please try again." }), _jsx(ErrorBoundary, { onError: renderFailed, fallback: _jsx(_Fragment, {}), children: _jsx(PageFrame, { frame: frame }) }, recovery), options.navigationFallback && _jsx(NavigationFallback, { state: pendingNavigation, options: options.navigationFallback })] }) });
125
128
  }
126
129
  render(_jsx(App, {}), root);
127
130
  navigation.start();
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { ErrorBoundary, render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';\nimport { createHonoRouter } from './navigation.ts';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\n\ntype NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'>;\n\ntype Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;\n\nfunction pageComponent(component: unknown) {\n if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n return component;\n}\n\nexport async function startHonoPages(manifest: Manifest, options: NavigationOptions) {\n const root = document.getElementById('app');\n if (!root) throw new Error('Hono Pages: app root is missing.');\n type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\n let commit = 0;\n const pendingCommits = new Map<number, { resolve(): void; reject(error: unknown): void }>();\n let committedFrame: Frame | undefined;\n const failedFrames = new Set<number>();\n let navigationState = idleNavigationState();\n let updateNavigation: ((state: NavigationState) => void) | undefined;\n let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;\n let renderedProps: Record<string, unknown> | undefined;\n let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;\n const initialization = createHonoRouter({\n ...manifest,\n adapter: {\n createDeferred, resolveDeferred, rejectDeferred, isLoading,\n onDeferredUpdate(props) {\n if (props === renderedProps) updateDeferred?.({ ...props });\n },\n async applyUpdate(page, component, layouts, options) {\n layouts.forEach(pageComponent);\n pageComponent(component);\n if (!update) throw new Error('Hono Pages: page rendering has not started.');\n if (!options.preserveState) revision++;\n renderedProps = page.props;\n const nextCommit = ++commit;\n const committed = new Promise<void>((resolve, reject) => pendingCommits.set(nextCommit, { resolve, reject }));\n update({ page: { ...page, props: { ...page.props } }, sourceProps: page.props, component, layouts, revision, commit: nextCommit });\n await committed;\n },\n },\n ...options,\n cacheVisitedPageData: false,\n onNavigationChange(state) { navigationState = state; updateNavigation?.(state); root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n setActionRouter(navigation.router);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n const initialFrame: Frame = { page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, sourceProps: navigation.initialPageData.props, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision, commit };\n function PageFrame({ frame }: { frame: Frame }) {\n useLayoutEffect(() => {\n if (failedFrames.has(frame.commit)) return;\n if (frame.commit > 0) applyDocumentHead?.(frame.page.head);\n committedFrame = frame;\n for (const id of failedFrames) if (id < frame.commit) failedFrames.delete(id);\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.resolve(); }\n }, [frame]);\n let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));\n const ids = manifest.layoutTree[frame.page.component] ?? [];\n for (let index = frame.layouts.length - 1; index >= 0; index--) {\n content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);\n }\n return <PageContext.Provider value={frame.page}>{content}</PageContext.Provider>;\n }\n\n function App() {\n const [frame, setFrame] = useState<Frame>(initialFrame);\n const [pendingNavigation, setNavigation] = useState(navigationState);\n const [failed, setFailed] = useState(false);\n const [recovery, setRecovery] = useState(0);\n useLayoutEffect(() => {\n updateNavigation = setNavigation;\n setNavigation(navigationState);\n updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));\n update = (next) => { setFailed(false); setFrame(next); };\n const onError = () => setFailed(true);\n window.addEventListener('hono-pages:navigation-error', onError);\n return () => { for (const pending of pendingCommits.values()) pending.reject(new DOMException('Hono Pages: renderer unmounted.', 'AbortError')); pendingCommits.clear(); updateNavigation = undefined; update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\n const renderFailed = (error: unknown) => {\n if (failedFrames.has(frame.commit)) return;\n failedFrames.add(frame.commit);\n queueMicrotask(() => {\n // A rejected child never reaches PageFrame's commit effect. Roll back\n // outside the render traversal, then reject every coalesced waiter.\n if (commit === frame.commit) {\n if (committedFrame) { renderedProps = committedFrame.sourceProps; setFrame(committedFrame); }\n // Discard the partially built Hono tree only after a render failure.\n // Successful navigations keep the same boundary and layout state.\n setRecovery(value => value + 1);\n setFailed(true);\n }\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.reject(error); }\n });\n };\n return <RouterContext.Provider value={navigation.router}>\n <NavigationContext.Provider value={pendingNavigation}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n <ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>\n <PageFrame frame={frame} />\n </ErrorBoundary>\n </NavigationContext.Provider>\n </RouterContext.Provider>;\n }\n\n render(<App />, root);\n navigation.start();\n navigation.commitInitialRender();\n root.dataset.navigation = 'idle';\n root.dataset.honoPages = 'mounted';\n}\n"]}
1
+ {"version":3,"file":"client.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { ErrorBoundary, render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';\nimport { NavigationFallback, type NavigationFallbackOptions } from './navigation-fallback.tsx';\nimport { createHonoRouter } from './navigation.ts';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\n\ntype NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'> & { navigationFallback?: NavigationFallbackOptions };\n\ntype Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;\n\nfunction pageComponent(component: unknown) {\n if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n return component;\n}\n\nexport async function startHonoPages(manifest: Manifest, options: NavigationOptions) {\n if (options.navigationFallback && typeof options.navigationFallback.component !== 'function') throw new Error('Hono Pages: navigationFallback must default-export a component function.');\n const root = document.getElementById('app');\n if (!root) throw new Error('Hono Pages: app root is missing.');\n type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\n let commit = 0;\n const pendingCommits = new Map<number, { resolve(): void; reject(error: unknown): void }>();\n let committedFrame: Frame | undefined;\n const failedFrames = new Set<number>();\n let navigationState = idleNavigationState();\n let updateNavigation: ((state: NavigationState) => void) | undefined;\n let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;\n let renderedProps: Record<string, unknown> | undefined;\n let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;\n const initialization = createHonoRouter({\n ...manifest,\n adapter: {\n createDeferred, resolveDeferred, rejectDeferred, isLoading,\n onDeferredUpdate(props) {\n if (props === renderedProps) updateDeferred?.({ ...props });\n },\n async applyUpdate(page, component, layouts, options) {\n layouts.forEach(pageComponent);\n pageComponent(component);\n if (!update) throw new Error('Hono Pages: page rendering has not started.');\n if (!options.preserveState) revision++;\n renderedProps = page.props;\n const nextCommit = ++commit;\n const committed = new Promise<void>((resolve, reject) => pendingCommits.set(nextCommit, { resolve, reject }));\n update({ page: { ...page, props: { ...page.props } }, sourceProps: page.props, component, layouts, revision, commit: nextCommit });\n await committed;\n },\n },\n ...options,\n cacheVisitedPageData: false,\n onNavigationChange(state) { navigationState = state; updateNavigation?.(state); root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n setActionRouter(navigation.router);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n const initialFrame: Frame = { page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, sourceProps: navigation.initialPageData.props, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision, commit };\n function PageFrame({ frame }: { frame: Frame }) {\n useLayoutEffect(() => {\n if (failedFrames.has(frame.commit)) return;\n if (frame.commit > 0) applyDocumentHead?.(frame.page.head);\n committedFrame = frame;\n for (const id of failedFrames) if (id < frame.commit) failedFrames.delete(id);\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.resolve(); }\n }, [frame]);\n let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));\n const ids = manifest.layoutTree[frame.page.component] ?? [];\n for (let index = frame.layouts.length - 1; index >= 0; index--) {\n content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);\n }\n return <PageContext.Provider value={frame.page}>{content}</PageContext.Provider>;\n }\n\n function App() {\n const [frame, setFrame] = useState<Frame>(initialFrame);\n const [pendingNavigation, setNavigation] = useState(navigationState);\n const [failed, setFailed] = useState(false);\n const [recovery, setRecovery] = useState(0);\n useLayoutEffect(() => {\n updateNavigation = setNavigation;\n setNavigation(navigationState);\n updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));\n update = (next) => { setFailed(false); setFrame(next); };\n const onError = () => setFailed(true);\n window.addEventListener('hono-pages:navigation-error', onError);\n return () => { for (const pending of pendingCommits.values()) pending.reject(new DOMException('Hono Pages: renderer unmounted.', 'AbortError')); pendingCommits.clear(); updateNavigation = undefined; update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\n const renderFailed = (error: unknown) => {\n if (failedFrames.has(frame.commit)) return;\n failedFrames.add(frame.commit);\n queueMicrotask(() => {\n // A rejected child never reaches PageFrame's commit effect. Roll back\n // outside the render traversal, then reject every coalesced waiter.\n if (commit === frame.commit) {\n if (committedFrame) { renderedProps = committedFrame.sourceProps; setFrame(committedFrame); }\n // Discard the partially built Hono tree only after a render failure.\n // Successful navigations keep the same boundary and layout state.\n setRecovery(value => value + 1);\n setFailed(true);\n }\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.reject(error); }\n });\n };\n return <RouterContext.Provider value={navigation.router}>\n <NavigationContext.Provider value={pendingNavigation}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n <ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>\n <PageFrame frame={frame} />\n </ErrorBoundary>\n {options.navigationFallback && <NavigationFallback state={pendingNavigation} options={options.navigationFallback} />}\n </NavigationContext.Provider>\n </RouterContext.Provider>;\n }\n\n render(<App />, root);\n navigation.start();\n navigation.commitInitialRender();\n root.dataset.navigation = 'idle';\n root.dataset.honoPages = 'mounted';\n}\n"]}
@@ -1,7 +1,17 @@
1
1
  import type { DeferredState } from 'void';
2
+ /** Null from an upstream completed prefetch remains null, not a repaired error. */
3
+ export type DeferredResult<T> = {
4
+ value: T | null;
5
+ error: null;
6
+ } | {
7
+ value: null;
8
+ error: Error;
9
+ };
10
+ /** A stable, render-only Promise; Void still owns all execution and delivery. */
11
+ export declare function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>>;
2
12
  export declare function createDeferred(): DeferredState<never>;
3
- export declare function resolveDeferred(_ref: unknown, value: unknown): DeferredState<unknown>;
4
- export declare function rejectDeferred(_ref: unknown, message: string): DeferredState<never>;
13
+ export declare function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown>;
14
+ export declare function rejectDeferred(ref: unknown, message: string): DeferredState<never>;
5
15
  export declare function isLoading(ref: unknown): boolean;
6
16
  declare global {
7
17
  interface Window {
@@ -1 +1 @@
1
- {"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,wBAAgB,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAErD;AACD,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAErF;AACD,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAEnF;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QAC3D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAC1D,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KAClE;CACF;AACD,wBAAgB,qBAAqB,eASpC"}
1
+ {"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,mFAAmF;AACnF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAejG,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAQrF;AAWD,wBAAgB,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAErD;AACD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAEpF;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAElF;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QAC3D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAC1D,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KAClE;CACF;AACD,wBAAgB,qBAAqB,eASpC"}
@@ -1,11 +1,42 @@
1
+ const resources = new WeakMap();
2
+ function resourceFor(ref) {
3
+ if (typeof ref !== 'object' || ref === null)
4
+ throw new Error('Hono Pages: deferredResult requires a Deferred state.');
5
+ let resource = resources.get(ref);
6
+ if (!resource)
7
+ resources.set(ref, resource = {});
8
+ return resource;
9
+ }
10
+ /** A stable, render-only Promise; Void still owns all execution and delivery. */
11
+ export function deferredResult(state) {
12
+ const resource = resourceFor(state);
13
+ // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR
14
+ // HTML callback to client-owned completion or wait for it on the server.
15
+ if (typeof window === 'undefined')
16
+ return (resource.serverPromise ??= new Promise(() => { }));
17
+ if (!state.loading && !resource.result)
18
+ resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };
19
+ resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });
20
+ return resource.promise;
21
+ }
22
+ function complete(ref, next) {
23
+ const resource = resourceFor(ref);
24
+ resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };
25
+ resource.resolve?.(resource.result);
26
+ resource.resolve = undefined;
27
+ // Void replaces its state object on completion. Both objects refer to the
28
+ // same lazy Promise, including completion before component import/use().
29
+ resources.set(next, resource);
30
+ return next;
31
+ }
1
32
  export function createDeferred() {
2
33
  return { loading: true, value: null, error: null };
3
34
  }
4
- export function resolveDeferred(_ref, value) {
5
- return { loading: false, value, error: null };
35
+ export function resolveDeferred(ref, value) {
36
+ return complete(ref, { loading: false, value, error: null });
6
37
  }
7
- export function rejectDeferred(_ref, message) {
8
- return { loading: false, value: null, error: new Error(message) };
38
+ export function rejectDeferred(ref, message) {
39
+ return complete(ref, { loading: false, value: null, error: new Error(message) });
9
40
  }
10
41
  export function isLoading(ref) {
11
42
  return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
@@ -1 +1 @@
1
- {"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc;IAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC;AACD,MAAM,UAAU,eAAe,CAAC,IAAa,EAAE,KAAc;IAC3D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAChD,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,OAAe;IAC3D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;AACpE,CAAC;AACD,MAAM,UAAU,SAAS,CAAC,GAAY;IACpC,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;AAC7F,CAAC;AAWD,MAAM,UAAU,qBAAqB;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,iBAAiB,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACvC,MAAM,CAAC,iBAAiB,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,eAAe,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAChG,MAAM,CAAC,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,eAAe,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACpG,OAAO,GAAG,EAAE;QACV,MAAM,CAAC,iBAAiB,GAAG,OAAO,CAAC;QACnC,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC;IACnC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { DeferredState } from 'void';\n\nexport function createDeferred(): DeferredState<never> {\n return { loading: true, value: null, error: null };\n}\nexport function resolveDeferred(_ref: unknown, value: unknown): DeferredState<unknown> {\n return { loading: false, value, error: null };\n}\nexport function rejectDeferred(_ref: unknown, message: string): DeferredState<never> {\n return { loading: false, value: null, error: new Error(message) };\n}\nexport function isLoading(ref: unknown): boolean {\n return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;\n}\n\n// Void installs its HTML callbacks before awaiting component imports. Keep early\n// messages in its existing queue until the initial deferred registry is ready.\ndeclare global {\n interface Window {\n __resolveDeferred?: (group: string, data: unknown) => void;\n __rejectDeferred?: (group: string, error: string) => void;\n __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;\n }\n}\nexport function bufferInitialDeferred() {\n const resolve = window.__resolveDeferred;\n const reject = window.__rejectDeferred;\n window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);\n window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);\n return () => {\n window.__resolveDeferred = resolve;\n window.__rejectDeferred = reject;\n };\n}\n"]}
1
+ {"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DeferredState } from 'void';\n\n/** Null from an upstream completed prefetch remains null, not a repaired error. */\nexport type DeferredResult<T> = { value: T | null; error: null } | { value: null; error: Error };\ntype Resource = {\n result?: DeferredResult<unknown>;\n promise?: Promise<DeferredResult<unknown>>;\n serverPromise?: Promise<DeferredResult<unknown>>;\n resolve?: (result: DeferredResult<unknown>) => void;\n};\nconst resources = new WeakMap<object, Resource>();\nfunction resourceFor(ref: unknown): Resource {\n if (typeof ref !== 'object' || ref === null) throw new Error('Hono Pages: deferredResult requires a Deferred state.');\n let resource = resources.get(ref);\n if (!resource) resources.set(ref, resource = {});\n return resource;\n}\n\n/** A stable, render-only Promise; Void still owns all execution and delivery. */\nexport function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>> {\n const resource = resourceFor(state);\n // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR\n // HTML callback to client-owned completion or wait for it on the server.\n if (typeof window === 'undefined') return (resource.serverPromise ??= new Promise(() => {})) as Promise<DeferredResult<T>>;\n if (!state.loading && !resource.result) resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };\n resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });\n return resource.promise as Promise<DeferredResult<T>>;\n}\nfunction complete(ref: unknown, next: DeferredState<unknown>) {\n const resource = resourceFor(ref);\n resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };\n resource.resolve?.(resource.result);\n resource.resolve = undefined;\n // Void replaces its state object on completion. Both objects refer to the\n // same lazy Promise, including completion before component import/use().\n resources.set(next, resource);\n return next;\n}\nexport function createDeferred(): DeferredState<never> {\n return { loading: true, value: null, error: null };\n}\nexport function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown> {\n return complete(ref, { loading: false, value, error: null });\n}\nexport function rejectDeferred(ref: unknown, message: string): DeferredState<never> {\n return complete(ref, { loading: false, value: null, error: new Error(message) }) as DeferredState<never>;\n}\nexport function isLoading(ref: unknown): boolean {\n return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;\n}\n\n// Void installs its HTML callbacks before awaiting component imports. Keep early\n// messages in its existing queue until the initial deferred registry is ready.\ndeclare global {\n interface Window {\n __resolveDeferred?: (group: string, data: unknown) => void;\n __rejectDeferred?: (group: string, error: string) => void;\n __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;\n }\n}\nexport function bufferInitialDeferred() {\n const resolve = window.__resolveDeferred;\n const reject = window.__rejectDeferred;\n window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);\n window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);\n return () => {\n window.__resolveDeferred = resolve;\n window.__rejectDeferred = reject;\n };\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { type FC } from 'hono/jsx';
2
+ import type { NavigationState } from 'void/pages-client';
3
+ import type { NavigationFallbackProps } from './pages.tsx';
4
+ export type NavigationFallbackOptions = {
5
+ component: FC<NavigationFallbackProps>;
6
+ delay: number;
7
+ };
8
+ /** Presentation only: it neither replaces the page nor acknowledges its commit. */
9
+ export declare function NavigationFallback({ state, options }: {
10
+ state: NavigationState;
11
+ options: NavigationFallbackOptions;
12
+ }): import("hono/jsx/dom/jsx-dev-runtime").JSX.Element | null;
13
+ //# sourceMappingURL=navigation-fallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-fallback.d.ts","sourceRoot":"","sources":["../../src/runtime/navigation-fallback.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,UAAU,CAAC;AAGxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,yBAAyB,GAAG;IAAE,SAAS,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,yBAAyB,CAAA;CAAE,6DAqBpH"}
@@ -0,0 +1,28 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "hono/jsx/dom/jsx-runtime";
2
+ import { useEffect, useState } from 'hono/jsx';
3
+ import { ErrorBoundary } from 'hono/jsx/dom';
4
+ import { jsx } from 'hono/jsx/dom/jsx-runtime';
5
+ /** Presentation only: it neither replaces the page nor acknowledges its commit. */
6
+ export function NavigationFallback({ state, options }) {
7
+ const [visibleFor, setVisibleFor] = useState(null);
8
+ const [failedFor, setFailedFor] = useState(null);
9
+ const loading = state.state === 'loading' && state.method === 'GET';
10
+ useEffect(() => {
11
+ setVisibleFor(null);
12
+ if (!loading)
13
+ return;
14
+ const timer = setTimeout(() => setVisibleFor(state), options.delay);
15
+ return () => clearTimeout(timer);
16
+ }, [state]);
17
+ // Identity hides the old fallback immediately, before effect cleanup, on every
18
+ // new navigation/idle state. A queued old timer cannot affect another visit.
19
+ if (!loading || visibleFor !== state || failedFor === state)
20
+ return null;
21
+ return _jsx(ErrorBoundary, { fallback: _jsx(_Fragment, {}), onError: error => queueMicrotask(() => {
22
+ // Hono retries a failed child on parent updates. Remove this presentation
23
+ // subtree before reporting the error; a later navigation may try again.
24
+ setFailedFor(state);
25
+ window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
26
+ }), children: _jsx("div", { "data-hono-navigation-fallback": true, role: "status", "aria-live": "polite", children: jsx(options.component, { navigation: state }) }) });
27
+ }
28
+ //# sourceMappingURL=navigation-fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-fallback.js","sourceRoot":"","sources":["../../src/runtime/navigation-fallback.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAW,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAM/C,mFAAmF;AACnF,MAAM,UAAU,kBAAkB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAkE;IACnH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAC;IAC3E,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC;IACpE,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACpE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACZ,+EAA+E;IAC/E,6EAA6E;IAC7E,IAAI,CAAC,OAAO,IAAI,UAAU,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACzE,OAAO,KAAC,aAAa,IAAC,QAAQ,EAAE,mBAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE;YAC3E,0EAA0E;YAC1E,wEAAwE;YACxE,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1F,CAAC,CAAC,YACA,qDAAmC,IAAI,EAAC,QAAQ,eAAW,QAAQ,YAAE,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,GAAO,GAC3G,CAAC;AACnB,CAAC","sourcesContent":["import { useEffect, useState, type FC } from 'hono/jsx';\nimport { ErrorBoundary } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport type { NavigationState } from 'void/pages-client';\nimport type { NavigationFallbackProps } from './pages.tsx';\n\nexport type NavigationFallbackOptions = { component: FC<NavigationFallbackProps>; delay: number };\n\n/** Presentation only: it neither replaces the page nor acknowledges its commit. */\nexport function NavigationFallback({ state, options }: { state: NavigationState; options: NavigationFallbackOptions }) {\n const [visibleFor, setVisibleFor] = useState<NavigationState | null>(null);\n const [failedFor, setFailedFor] = useState<NavigationState | null>(null);\n const loading = state.state === 'loading' && state.method === 'GET';\n useEffect(() => {\n setVisibleFor(null);\n if (!loading) return;\n const timer = setTimeout(() => setVisibleFor(state), options.delay);\n return () => clearTimeout(timer);\n }, [state]);\n // Identity hides the old fallback immediately, before effect cleanup, on every\n // new navigation/idle state. A queued old timer cannot affect another visit.\n if (!loading || visibleFor !== state || failedFor === state) return null;\n return <ErrorBoundary fallback={<></>} onError={error => queueMicrotask(() => {\n // Hono retries a failed child on parent updates. Remove this presentation\n // subtree before reporting the error; a later navigation may try again.\n setFailedFor(state);\n window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n })}>\n <div data-hono-navigation-fallback role=\"status\" aria-live=\"polite\">{jsx(options.component, { navigation: state })}</div>\n </ErrorBoundary>;\n}\n"]}
@@ -3,6 +3,10 @@ import { type NavigationState, type NavigationMethod, type VoidRouter } from 'vo
3
3
  import type { CacheForInput } from 'void/pages-prefetch';
4
4
  import type { PageObject } from 'void/pages-protocol';
5
5
  export type { DeferredState as Deferred } from 'void';
6
+ export { deferredResult, type DeferredResult } from './deferred.ts';
7
+ export type NavigationFallbackProps = {
8
+ navigation: NavigationState;
9
+ };
6
10
  export declare const action: <U extends import("void/routes").ActionUrl & string>(url: U, ...args: ([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? [options: {
7
11
  data?: import("void/routes").ResolveActionBody<U> | undefined;
8
12
  method?: "DELETE" | "PATCH" | "POST" | "PUT";
@@ -1 +1 @@
1
- {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAGtD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,sDAoD3B"}
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,MAAM,MAAM,uBAAuB,GAAG;IAAE,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAGtE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,sDAoD3B"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "hono/jsx/dom/jsx-runtime";
2
2
  import { createContext, useContext, useEffect, useRef } from 'hono/jsx';
3
3
  import { createActionClient, mergeDataIntoHref } from 'void/pages-client';
4
+ export { deferredResult } from './deferred.js';
4
5
  const actionClient = createActionClient();
5
6
  export const action = actionClient.action;
6
7
  export const setActionRouter = actionClient.setActionRouter;
@@ -1 +1 @@
1
- {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\nexport { deferredResult, type DeferredResult } from './deferred.ts';\nexport type NavigationFallbackProps = { navigation: NavigationState };\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
@@ -2,6 +2,11 @@ import type { Plugin } from 'vite';
2
2
  import { type CacheForInput } from 'void/pages-prefetch';
3
3
  export type HonoJsxOptions = {
4
4
  viewTransitions?: boolean;
5
+ /** A default-exported local TSX/JSX component; keeps the current page mounted. */
6
+ navigationFallback?: {
7
+ component: string;
8
+ delay?: number;
9
+ };
5
10
  prefetch?: {
6
11
  hoverDelay?: number;
7
12
  cacheFor?: CacheForInput;
@@ -1 +1 @@
1
- {"version":3,"file":"hono-jsx.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC;CAC9D,CAAC;AAcF,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,EAAE,CA2IlE"}
1
+ {"version":3,"file":"hono-jsx.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kFAAkF;IAClF,kBAAkB,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,QAAQ,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC;CAC9D,CAAC;AAcF,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,EAAE,CAqJlE"}
@@ -1,4 +1,4 @@
1
- import { realpathSync } from 'node:fs';
1
+ import { realpathSync, statSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { normalizePath } from 'vite';
4
4
  import { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.js';
@@ -38,6 +38,18 @@ function clientOptions(options) {
38
38
  export function voidHonoJsx(options = {}) {
39
39
  const navigationOptions = clientOptions(options);
40
40
  const root = process.cwd();
41
+ const fallback = options.navigationFallback;
42
+ let fallbackPath;
43
+ const fallbackDelay = fallback?.delay ?? 150;
44
+ if (fallback !== undefined) {
45
+ if (!fallback || typeof fallback.component !== 'string' || !fallback.component.trim() || !/\.[jt]sx$/.test(fallback.component))
46
+ throw new Error('Hono Pages: navigationFallback.component must name a local TSX/JSX file.');
47
+ if (!Number.isSafeInteger(fallbackDelay) || fallbackDelay < 0 || fallbackDelay > 2147483647)
48
+ throw new Error('Hono Pages: navigationFallback.delay must be an integer from 0 to 2147483647 milliseconds.');
49
+ fallbackPath = normalizePath(realpathSync(resolve(root, fallback.component)));
50
+ if (!statSync(fallbackPath).isFile())
51
+ throw new Error('Hono Pages: navigationFallback.component must be a file.');
52
+ }
41
53
  const pagesDir = resolvePagesDir(root);
42
54
  const staticData = resolveStaticPageDataBuildOptions(root);
43
55
  let scan;
@@ -177,8 +189,9 @@ export async function renderPage(pageObj, assetTags) {
177
189
  }
178
190
  return `
179
191
  import { startHonoPages } from ${JSON.stringify(clientRuntimePath)};
192
+ ${fallbackPath ? `import __HonoNavigationFallback from ${JSON.stringify(fallbackPath)};` : ''}
180
193
  ${manifest}
181
- await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, ${JSON.stringify(navigationOptions)});
194
+ await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, { ...${JSON.stringify(navigationOptions)}${fallbackPath ? `, navigationFallback: { component: __HonoNavigationFallback, delay: ${fallbackDelay} }` : ''} });
182
195
  `;
183
196
  },
184
197
  }];
@@ -1 +1 @@
1
- {"version":3,"file":"hono-jsx.js","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { parseCacheFor, type CacheForInput } from 'void/pages-prefetch';\nimport { honoJsxTransform } from './jsx-transform.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\nfunction assertComponentFile(file: string, kind: 'page' | 'layout', markdown = false) {\n if (/\\.md$/.test(file)) { if (markdown && kind === 'page') return; if (markdown) throw new Error('Hono Markdown: layouts must remain TSX/JSX: ' + file); throw new Error(`${markdownDiagnostic} ${kind}: ${file}`); }\n if (!/\\.[jt]sx$/.test(file)) throw new Error(`Hono Pages: only standard TSX/JSX ${kind}s are supported: ${file}.`);\n}\n\n\nexport type HonoJsxOptions = {\n viewTransitions?: boolean;\n prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };\n};\n\nfunction clientOptions(options: HonoJsxOptions) {\n const viewTransitions = options.viewTransitions ?? false;\n const prefetchHoverDelay = options.prefetch?.hoverDelay ?? 75;\n if (typeof viewTransitions !== 'boolean') throw new Error('Hono Pages: viewTransitions must be a boolean.');\n if (!Number.isFinite(prefetchHoverDelay) || prefetchHoverDelay < 0) throw new Error('Hono Pages: prefetch.hoverDelay must be a finite non-negative number.');\n const prefetchDefaultCacheFor = parseCacheFor(options.prefetch?.cacheFor ?? '30s');\n if (![prefetchDefaultCacheFor.stale, prefetchDefaultCacheFor.expires].every(value => Number.isFinite(value) && value >= 0) || prefetchDefaultCacheFor.stale > prefetchDefaultCacheFor.expires) {\n throw new Error('Hono Pages: prefetch.cacheFor must have finite non-negative durations, with stale <= expires.');\n }\n return { viewTransitions, prefetchHoverDelay, prefetchDefaultCacheFor };\n}\n\n/** Compose Hono JSX transformation, Pages and islands using verified Void contracts. */\nexport function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {\n const navigationOptions = clientOptions(options);\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n assertComponentFile(layout.filePath, 'layout');\n }\n for (const page of scan.pages) {\n assertComponentFile(page.componentPath, 'page', Boolean(markdown));\n if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {\n throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);\n }\n }\n return scan;\n }\n\n return [honoIslands(), honoJsxTransform(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config(config) {\n assertSupportedFrameworks({ root: resolve(config.root ?? root), viteVersion: this?.meta?.viteVersion });\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\n };\n },\n configResolved: {\n order: 'pre',\n handler(config) {\n markdown = markdownApi(config.plugins);\n },\n },\n configEnvironment() {\n const modules = Object.keys(publicRuntimeModules);\n const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];\n return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };\n },\n async buildStart() {\n await rescan();\n },\n configureServer(server) {\n const clear = (file: string) => {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;\n };\n server.watcher.on('add', clear);\n server.watcher.on('unlink', clear);\n server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });\n },\n async hotUpdate({ file, type, modules, timestamp }) {\n if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n await rescan();\n if (type !== 'update') return [];\n const invalidated = new Set<(typeof modules)[number]>();\n for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n for (const id of [rendererId, clientId]) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n this.environment.hot.send({ type: 'full-reload' });\n return [];\n },\n resolveId(id) {\n if (id === rendererId || id === clientId) return `\\0${id}`;\n if (id === pagesRuntimePath || id === clientRuntimePath || id === markdownRuntimePath) return { id: realpathSync(id), external: false };\n const runtime = publicRuntimeModules[id];\n if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };\n },\n async load(id) {\n if (id !== `\\0${rendererId}` && id !== `\\0${clientId}`) return;\n const currentScan = scan ?? await rescan();\n const serverSnapshot = id === `\\0${rendererId}` && this.environment.mode === 'dev';\n const manifestScan = id === `\\0${clientId}`\n ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island), layouts: currentScan.layouts.filter((layout) => !layout.island), namedLayouts: currentScan.namedLayouts.filter((layout) => !layout.island) }\n : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;\n let manifest = generateComponentManifest(manifestScan, pagesDir);\n if (serverSnapshot) {\n // A request can retain the old renderer while the worker module runner\n // reloads. Capture components with its providers instead of importing\n // a new generation into an in-flight render. Browser-only pages remain\n // absent from this server graph; production keeps lazy imports.\n const imports: string[] = [];\n manifest = manifest.replace(/\\(\\) => import\\((\"(?:[^\"\\\\]|\\\\.)*\")\\)/g, (_, path: string) => {\n const name = `__honoPageSnapshot${imports.length}`;\n imports.push(`import * as ${name} from ${path};`);\n return `() => ${name}`;\n });\n manifest = imports.join('\\n') + '\\n' + manifest;\n }\n if (id === `\\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';\n if (id === `\\0${rendererId}`) {\n const markdownScriptIds = [...(markdown?.getClientScripts().keys() ?? [])];\n return `\nimport { jsx } from 'hono/jsx';\n${markdown ? `import { MarkdownContext } from ${JSON.stringify(markdownRuntimePath)};` : ''}\nconst markdownScriptIds = new Set(${JSON.stringify(markdownScriptIds)});\nimport { createSsrRouter, idleNavigationState } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext } from ${JSON.stringify(pagesRuntimePath)};\nimport { serializePageData } from 'void/pages-server';\nimport { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';\n${manifest}\nexport async function renderPage(pageObj, assetTags) {\n if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');\n const load = components[pageObj.component];\n if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);\n const { default: Page, frontmatter = {}, headings = [] } = await load();\n if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n let content = jsx(Page, pageObj.props);\n const ids = layoutTree[pageObj.component] ?? [];\n const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));\n for (const Layout of layouts.reverse()) {\n if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');\n content = jsx(Layout, { children: content });\n }\n ${markdown ? 'content = jsx(MarkdownContext.Provider, { value: { frontmatter, headings, props: pageObj.props }, children: content });' : ''}\n const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: jsx(NavigationContext.Provider, { value: idleNavigationState(), children: content }) }) }).toString();\n const appHtml = await jsx('div', { id: 'app', 'data-md-script': markdownScriptIds.has(pageObj.component) ? pageObj.component : undefined, ${markdown ? \"'data-hono-markdown': JSON.stringify({ frontmatter, headings }),\" : ''} dangerouslySetInnerHTML: { __html: markup } }).toString();\n const head = pageObj.head;\n const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type=\"module\"', '<script async type=\"module\"') : assetTags.body;\n return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'\n + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads\n + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'\n + '<script id=\"__VOID_PAGE_DATA__\" type=\"application/json\">' + serializePageData(pageObj) + '</script>'\n + appHtml + body + '</body></html>';\n}\n`;\n }\n return `\nimport { startHonoPages } from ${JSON.stringify(clientRuntimePath)};\n${manifest}\nawait startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, ${JSON.stringify(navigationOptions)});\n`;\n },\n }];\n}\n"]}
1
+ {"version":3,"file":"hono-jsx.js","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync, statSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { parseCacheFor, type CacheForInput } from 'void/pages-prefetch';\nimport { honoJsxTransform } from './jsx-transform.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\nfunction assertComponentFile(file: string, kind: 'page' | 'layout', markdown = false) {\n if (/\\.md$/.test(file)) { if (markdown && kind === 'page') return; if (markdown) throw new Error('Hono Markdown: layouts must remain TSX/JSX: ' + file); throw new Error(`${markdownDiagnostic} ${kind}: ${file}`); }\n if (!/\\.[jt]sx$/.test(file)) throw new Error(`Hono Pages: only standard TSX/JSX ${kind}s are supported: ${file}.`);\n}\n\n\nexport type HonoJsxOptions = {\n viewTransitions?: boolean;\n /** A default-exported local TSX/JSX component; keeps the current page mounted. */\n navigationFallback?: { component: string; delay?: number };\n prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };\n};\n\nfunction clientOptions(options: HonoJsxOptions) {\n const viewTransitions = options.viewTransitions ?? false;\n const prefetchHoverDelay = options.prefetch?.hoverDelay ?? 75;\n if (typeof viewTransitions !== 'boolean') throw new Error('Hono Pages: viewTransitions must be a boolean.');\n if (!Number.isFinite(prefetchHoverDelay) || prefetchHoverDelay < 0) throw new Error('Hono Pages: prefetch.hoverDelay must be a finite non-negative number.');\n const prefetchDefaultCacheFor = parseCacheFor(options.prefetch?.cacheFor ?? '30s');\n if (![prefetchDefaultCacheFor.stale, prefetchDefaultCacheFor.expires].every(value => Number.isFinite(value) && value >= 0) || prefetchDefaultCacheFor.stale > prefetchDefaultCacheFor.expires) {\n throw new Error('Hono Pages: prefetch.cacheFor must have finite non-negative durations, with stale <= expires.');\n }\n return { viewTransitions, prefetchHoverDelay, prefetchDefaultCacheFor };\n}\n\n/** Compose Hono JSX transformation, Pages and islands using verified Void contracts. */\nexport function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {\n const navigationOptions = clientOptions(options);\n const root = process.cwd();\n const fallback = options.navigationFallback;\n let fallbackPath: string | undefined;\n const fallbackDelay = fallback?.delay ?? 150;\n if (fallback !== undefined) {\n if (!fallback || typeof fallback.component !== 'string' || !fallback.component.trim() || !/\\.[jt]sx$/.test(fallback.component)) throw new Error('Hono Pages: navigationFallback.component must name a local TSX/JSX file.');\n if (!Number.isSafeInteger(fallbackDelay) || fallbackDelay < 0 || fallbackDelay > 2147483647) throw new Error('Hono Pages: navigationFallback.delay must be an integer from 0 to 2147483647 milliseconds.');\n fallbackPath = normalizePath(realpathSync(resolve(root, fallback.component)));\n if (!statSync(fallbackPath).isFile()) throw new Error('Hono Pages: navigationFallback.component must be a file.');\n }\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n assertComponentFile(layout.filePath, 'layout');\n }\n for (const page of scan.pages) {\n assertComponentFile(page.componentPath, 'page', Boolean(markdown));\n if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {\n throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);\n }\n }\n return scan;\n }\n\n return [honoIslands(), honoJsxTransform(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config(config) {\n assertSupportedFrameworks({ root: resolve(config.root ?? root), viteVersion: this?.meta?.viteVersion });\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\n };\n },\n configResolved: {\n order: 'pre',\n handler(config) {\n markdown = markdownApi(config.plugins);\n },\n },\n configEnvironment() {\n const modules = Object.keys(publicRuntimeModules);\n const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];\n return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };\n },\n async buildStart() {\n await rescan();\n },\n configureServer(server) {\n const clear = (file: string) => {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;\n };\n server.watcher.on('add', clear);\n server.watcher.on('unlink', clear);\n server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });\n },\n async hotUpdate({ file, type, modules, timestamp }) {\n if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n await rescan();\n if (type !== 'update') return [];\n const invalidated = new Set<(typeof modules)[number]>();\n for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n for (const id of [rendererId, clientId]) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n this.environment.hot.send({ type: 'full-reload' });\n return [];\n },\n resolveId(id) {\n if (id === rendererId || id === clientId) return `\\0${id}`;\n if (id === pagesRuntimePath || id === clientRuntimePath || id === markdownRuntimePath) return { id: realpathSync(id), external: false };\n const runtime = publicRuntimeModules[id];\n if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };\n },\n async load(id) {\n if (id !== `\\0${rendererId}` && id !== `\\0${clientId}`) return;\n const currentScan = scan ?? await rescan();\n const serverSnapshot = id === `\\0${rendererId}` && this.environment.mode === 'dev';\n const manifestScan = id === `\\0${clientId}`\n ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island), layouts: currentScan.layouts.filter((layout) => !layout.island), namedLayouts: currentScan.namedLayouts.filter((layout) => !layout.island) }\n : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;\n let manifest = generateComponentManifest(manifestScan, pagesDir);\n if (serverSnapshot) {\n // A request can retain the old renderer while the worker module runner\n // reloads. Capture components with its providers instead of importing\n // a new generation into an in-flight render. Browser-only pages remain\n // absent from this server graph; production keeps lazy imports.\n const imports: string[] = [];\n manifest = manifest.replace(/\\(\\) => import\\((\"(?:[^\"\\\\]|\\\\.)*\")\\)/g, (_, path: string) => {\n const name = `__honoPageSnapshot${imports.length}`;\n imports.push(`import * as ${name} from ${path};`);\n return `() => ${name}`;\n });\n manifest = imports.join('\\n') + '\\n' + manifest;\n }\n if (id === `\\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';\n if (id === `\\0${rendererId}`) {\n const markdownScriptIds = [...(markdown?.getClientScripts().keys() ?? [])];\n return `\nimport { jsx } from 'hono/jsx';\n${markdown ? `import { MarkdownContext } from ${JSON.stringify(markdownRuntimePath)};` : ''}\nconst markdownScriptIds = new Set(${JSON.stringify(markdownScriptIds)});\nimport { createSsrRouter, idleNavigationState } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext } from ${JSON.stringify(pagesRuntimePath)};\nimport { serializePageData } from 'void/pages-server';\nimport { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';\n${manifest}\nexport async function renderPage(pageObj, assetTags) {\n if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');\n const load = components[pageObj.component];\n if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);\n const { default: Page, frontmatter = {}, headings = [] } = await load();\n if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n let content = jsx(Page, pageObj.props);\n const ids = layoutTree[pageObj.component] ?? [];\n const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));\n for (const Layout of layouts.reverse()) {\n if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');\n content = jsx(Layout, { children: content });\n }\n ${markdown ? 'content = jsx(MarkdownContext.Provider, { value: { frontmatter, headings, props: pageObj.props }, children: content });' : ''}\n const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: jsx(NavigationContext.Provider, { value: idleNavigationState(), children: content }) }) }).toString();\n const appHtml = await jsx('div', { id: 'app', 'data-md-script': markdownScriptIds.has(pageObj.component) ? pageObj.component : undefined, ${markdown ? \"'data-hono-markdown': JSON.stringify({ frontmatter, headings }),\" : ''} dangerouslySetInnerHTML: { __html: markup } }).toString();\n const head = pageObj.head;\n const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type=\"module\"', '<script async type=\"module\"') : assetTags.body;\n return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'\n + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads\n + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'\n + '<script id=\"__VOID_PAGE_DATA__\" type=\"application/json\">' + serializePageData(pageObj) + '</script>'\n + appHtml + body + '</body></html>';\n}\n`;\n }\n return `\nimport { startHonoPages } from ${JSON.stringify(clientRuntimePath)};\n${fallbackPath ? `import __HonoNavigationFallback from ${JSON.stringify(fallbackPath)};` : ''}\n${manifest}\nawait startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, { ...${JSON.stringify(navigationOptions)}${fallbackPath ? `, navigationFallback: { component: __HonoNavigationFallback, delay: ${fallbackDelay} }` : ''} });\n`;\n },\n }];\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import type { DeferredState } from 'void';
2
+ /** Null from an upstream completed prefetch remains null, not a repaired error. */
3
+ export type DeferredResult<T> = {
4
+ value: T | null;
5
+ error: null;
6
+ } | {
7
+ value: null;
8
+ error: Error;
9
+ };
10
+ /** A stable, render-only Promise; Void still owns all execution and delivery. */
11
+ export declare function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>>;
12
+ export declare function createDeferred(): DeferredState<never>;
13
+ export declare function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown>;
14
+ export declare function rejectDeferred(ref: unknown, message: string): DeferredState<never>;
15
+ export declare function isLoading(ref: unknown): boolean;
16
+ declare global {
17
+ interface Window {
18
+ __resolveDeferred?: (group: string, data: unknown) => void;
19
+ __rejectDeferred?: (group: string, error: string) => void;
20
+ __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;
21
+ }
22
+ }
23
+ export declare function bufferInitialDeferred(): () => void;
24
+ //# sourceMappingURL=deferred.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,mFAAmF;AACnF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAejG,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAQrF;AAWD,wBAAgB,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAErD;AACD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAEpF;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAElF;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QAC3D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAC1D,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KAClE;CACF;AACD,wBAAgB,qBAAqB,eASpC"}
@@ -0,0 +1,54 @@
1
+ const resources = new WeakMap();
2
+ function resourceFor(ref) {
3
+ if (typeof ref !== 'object' || ref === null)
4
+ throw new Error('Hono Pages: deferredResult requires a Deferred state.');
5
+ let resource = resources.get(ref);
6
+ if (!resource)
7
+ resources.set(ref, resource = {});
8
+ return resource;
9
+ }
10
+ /** A stable, render-only Promise; Void still owns all execution and delivery. */
11
+ export function deferredResult(state) {
12
+ const resource = resourceFor(state);
13
+ // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR
14
+ // HTML callback to client-owned completion or wait for it on the server.
15
+ if (typeof window === 'undefined')
16
+ return (resource.serverPromise ??= new Promise(() => { }));
17
+ if (!state.loading && !resource.result)
18
+ resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };
19
+ resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });
20
+ return resource.promise;
21
+ }
22
+ function complete(ref, next) {
23
+ const resource = resourceFor(ref);
24
+ resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };
25
+ resource.resolve?.(resource.result);
26
+ resource.resolve = undefined;
27
+ // Void replaces its state object on completion. Both objects refer to the
28
+ // same lazy Promise, including completion before component import/use().
29
+ resources.set(next, resource);
30
+ return next;
31
+ }
32
+ export function createDeferred() {
33
+ return { loading: true, value: null, error: null };
34
+ }
35
+ export function resolveDeferred(ref, value) {
36
+ return complete(ref, { loading: false, value, error: null });
37
+ }
38
+ export function rejectDeferred(ref, message) {
39
+ return complete(ref, { loading: false, value: null, error: new Error(message) });
40
+ }
41
+ export function isLoading(ref) {
42
+ return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
43
+ }
44
+ export function bufferInitialDeferred() {
45
+ const resolve = window.__resolveDeferred;
46
+ const reject = window.__rejectDeferred;
47
+ window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);
48
+ window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);
49
+ return () => {
50
+ window.__resolveDeferred = resolve;
51
+ window.__rejectDeferred = reject;
52
+ };
53
+ }
54
+ //# sourceMappingURL=deferred.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DeferredState } from 'void';\n\n/** Null from an upstream completed prefetch remains null, not a repaired error. */\nexport type DeferredResult<T> = { value: T | null; error: null } | { value: null; error: Error };\ntype Resource = {\n result?: DeferredResult<unknown>;\n promise?: Promise<DeferredResult<unknown>>;\n serverPromise?: Promise<DeferredResult<unknown>>;\n resolve?: (result: DeferredResult<unknown>) => void;\n};\nconst resources = new WeakMap<object, Resource>();\nfunction resourceFor(ref: unknown): Resource {\n if (typeof ref !== 'object' || ref === null) throw new Error('Hono Pages: deferredResult requires a Deferred state.');\n let resource = resources.get(ref);\n if (!resource) resources.set(ref, resource = {});\n return resource;\n}\n\n/** A stable, render-only Promise; Void still owns all execution and delivery. */\nexport function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>> {\n const resource = resourceFor(state);\n // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR\n // HTML callback to client-owned completion or wait for it on the server.\n if (typeof window === 'undefined') return (resource.serverPromise ??= new Promise(() => {})) as Promise<DeferredResult<T>>;\n if (!state.loading && !resource.result) resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };\n resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });\n return resource.promise as Promise<DeferredResult<T>>;\n}\nfunction complete(ref: unknown, next: DeferredState<unknown>) {\n const resource = resourceFor(ref);\n resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };\n resource.resolve?.(resource.result);\n resource.resolve = undefined;\n // Void replaces its state object on completion. Both objects refer to the\n // same lazy Promise, including completion before component import/use().\n resources.set(next, resource);\n return next;\n}\nexport function createDeferred(): DeferredState<never> {\n return { loading: true, value: null, error: null };\n}\nexport function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown> {\n return complete(ref, { loading: false, value, error: null });\n}\nexport function rejectDeferred(ref: unknown, message: string): DeferredState<never> {\n return complete(ref, { loading: false, value: null, error: new Error(message) }) as DeferredState<never>;\n}\nexport function isLoading(ref: unknown): boolean {\n return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;\n}\n\n// Void installs its HTML callbacks before awaiting component imports. Keep early\n// messages in its existing queue until the initial deferred registry is ready.\ndeclare global {\n interface Window {\n __resolveDeferred?: (group: string, data: unknown) => void;\n __rejectDeferred?: (group: string, error: string) => void;\n __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;\n }\n}\nexport function bufferInitialDeferred() {\n const resolve = window.__resolveDeferred;\n const reject = window.__rejectDeferred;\n window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);\n window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);\n return () => {\n window.__resolveDeferred = resolve;\n window.__rejectDeferred = reject;\n };\n}\n"]}
@@ -3,6 +3,10 @@ import { type NavigationState, type NavigationMethod, type VoidRouter } from 'vo
3
3
  import type { CacheForInput } from 'void/pages-prefetch';
4
4
  import type { PageObject } from 'void/pages-protocol';
5
5
  export type { DeferredState as Deferred } from 'void';
6
+ export { deferredResult, type DeferredResult } from './deferred.ts';
7
+ export type NavigationFallbackProps = {
8
+ navigation: NavigationState;
9
+ };
6
10
  export declare const action: <U extends import("void/routes").ActionUrl & string>(url: U, ...args: ([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? [options: {
7
11
  data?: import("void/routes").ResolveActionBody<U> | undefined;
8
12
  method?: "DELETE" | "PATCH" | "POST" | "PUT";
@@ -1 +1 @@
1
- {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAGtD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,kDAoD3B"}
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,MAAM,MAAM,uBAAuB,GAAG;IAAE,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAGtE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,kDAoD3B"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "hono/jsx/jsx-runtime";
2
2
  import { createContext, useContext, useEffect, useRef } from 'hono/jsx';
3
3
  import { createActionClient, mergeDataIntoHref } from 'void/pages-client';
4
+ export { deferredResult } from './deferred.js';
4
5
  const actionClient = createActionClient();
5
6
  export const action = actionClient.action;
6
7
  export const setActionRouter = actionClient.setActionRouter;
@@ -1 +1 @@
1
- {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\nexport { deferredResult, type DeferredResult } from './deferred.ts';\nexport type NavigationFallbackProps = { navigation: NavigationState };\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void-plugin-hono-jsx",
3
- "version": "0.1.0-rc.0",
3
+ "version": "0.1.0",
4
4
  "private": false,
5
5
  "description": "Hono JSX Pages adapter for Void",
6
6
  "type": "module",
@@ -1,4 +1,4 @@
1
- import { realpathSync } from 'node:fs';
1
+ import { realpathSync, statSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { normalizePath } from 'vite';
4
4
  import { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';
@@ -21,6 +21,8 @@ function assertComponentFile(file: string, kind: 'page' | 'layout', markdown = f
21
21
 
22
22
  export type HonoJsxOptions = {
23
23
  viewTransitions?: boolean;
24
+ /** A default-exported local TSX/JSX component; keeps the current page mounted. */
25
+ navigationFallback?: { component: string; delay?: number };
24
26
  prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };
25
27
  };
26
28
 
@@ -40,6 +42,15 @@ function clientOptions(options: HonoJsxOptions) {
40
42
  export function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {
41
43
  const navigationOptions = clientOptions(options);
42
44
  const root = process.cwd();
45
+ const fallback = options.navigationFallback;
46
+ let fallbackPath: string | undefined;
47
+ const fallbackDelay = fallback?.delay ?? 150;
48
+ if (fallback !== undefined) {
49
+ if (!fallback || typeof fallback.component !== 'string' || !fallback.component.trim() || !/\.[jt]sx$/.test(fallback.component)) throw new Error('Hono Pages: navigationFallback.component must name a local TSX/JSX file.');
50
+ if (!Number.isSafeInteger(fallbackDelay) || fallbackDelay < 0 || fallbackDelay > 2147483647) throw new Error('Hono Pages: navigationFallback.delay must be an integer from 0 to 2147483647 milliseconds.');
51
+ fallbackPath = normalizePath(realpathSync(resolve(root, fallback.component)));
52
+ if (!statSync(fallbackPath).isFile()) throw new Error('Hono Pages: navigationFallback.component must be a file.');
53
+ }
43
54
  const pagesDir = resolvePagesDir(root);
44
55
  const staticData = resolveStaticPageDataBuildOptions(root);
45
56
  let scan: PageScanResult | undefined;
@@ -171,8 +182,9 @@ export async function renderPage(pageObj, assetTags) {
171
182
  }
172
183
  return `
173
184
  import { startHonoPages } from ${JSON.stringify(clientRuntimePath)};
185
+ ${fallbackPath ? `import __HonoNavigationFallback from ${JSON.stringify(fallbackPath)};` : ''}
174
186
  ${manifest}
175
- await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, ${JSON.stringify(navigationOptions)});
187
+ await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, { ...${JSON.stringify(navigationOptions)}${fallbackPath ? `, navigationFallback: { component: __HonoNavigationFallback, delay: ${fallbackDelay} }` : ''} });
176
188
  `;
177
189
  },
178
190
  }];
@@ -3,11 +3,12 @@ import { jsx } from 'hono/jsx/dom/jsx-runtime';
3
3
  import { useLayoutEffect, useState } from 'hono/jsx';
4
4
  import { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';
5
5
  import { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';
6
+ import { NavigationFallback, type NavigationFallbackOptions } from './navigation-fallback.tsx';
6
7
  import { createHonoRouter } from './navigation.ts';
7
8
  import { createDocumentHead } from './document-head.ts';
8
9
  import { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';
9
10
 
10
- type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'>;
11
+ type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'> & { navigationFallback?: NavigationFallbackOptions };
11
12
 
12
13
  type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
13
14
 
@@ -17,6 +18,7 @@ function pageComponent(component: unknown) {
17
18
  }
18
19
 
19
20
  export async function startHonoPages(manifest: Manifest, options: NavigationOptions) {
21
+ if (options.navigationFallback && typeof options.navigationFallback.component !== 'function') throw new Error('Hono Pages: navigationFallback must default-export a component function.');
20
22
  const root = document.getElementById('app');
21
23
  if (!root) throw new Error('Hono Pages: app root is missing.');
22
24
  type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };
@@ -113,6 +115,7 @@ export async function startHonoPages(manifest: Manifest, options: NavigationOpti
113
115
  <ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>
114
116
  <PageFrame frame={frame} />
115
117
  </ErrorBoundary>
118
+ {options.navigationFallback && <NavigationFallback state={pendingNavigation} options={options.navigationFallback} />}
116
119
  </NavigationContext.Provider>
117
120
  </RouterContext.Provider>;
118
121
  }
@@ -1,13 +1,49 @@
1
1
  import type { DeferredState } from 'void';
2
2
 
3
+ /** Null from an upstream completed prefetch remains null, not a repaired error. */
4
+ export type DeferredResult<T> = { value: T | null; error: null } | { value: null; error: Error };
5
+ type Resource = {
6
+ result?: DeferredResult<unknown>;
7
+ promise?: Promise<DeferredResult<unknown>>;
8
+ serverPromise?: Promise<DeferredResult<unknown>>;
9
+ resolve?: (result: DeferredResult<unknown>) => void;
10
+ };
11
+ const resources = new WeakMap<object, Resource>();
12
+ function resourceFor(ref: unknown): Resource {
13
+ if (typeof ref !== 'object' || ref === null) throw new Error('Hono Pages: deferredResult requires a Deferred state.');
14
+ let resource = resources.get(ref);
15
+ if (!resource) resources.set(ref, resource = {});
16
+ return resource;
17
+ }
18
+
19
+ /** A stable, render-only Promise; Void still owns all execution and delivery. */
20
+ export function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>> {
21
+ const resource = resourceFor(state);
22
+ // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR
23
+ // HTML callback to client-owned completion or wait for it on the server.
24
+ if (typeof window === 'undefined') return (resource.serverPromise ??= new Promise(() => {})) as Promise<DeferredResult<T>>;
25
+ if (!state.loading && !resource.result) resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };
26
+ resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });
27
+ return resource.promise as Promise<DeferredResult<T>>;
28
+ }
29
+ function complete(ref: unknown, next: DeferredState<unknown>) {
30
+ const resource = resourceFor(ref);
31
+ resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };
32
+ resource.resolve?.(resource.result);
33
+ resource.resolve = undefined;
34
+ // Void replaces its state object on completion. Both objects refer to the
35
+ // same lazy Promise, including completion before component import/use().
36
+ resources.set(next, resource);
37
+ return next;
38
+ }
3
39
  export function createDeferred(): DeferredState<never> {
4
40
  return { loading: true, value: null, error: null };
5
41
  }
6
- export function resolveDeferred(_ref: unknown, value: unknown): DeferredState<unknown> {
7
- return { loading: false, value, error: null };
42
+ export function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown> {
43
+ return complete(ref, { loading: false, value, error: null });
8
44
  }
9
- export function rejectDeferred(_ref: unknown, message: string): DeferredState<never> {
10
- return { loading: false, value: null, error: new Error(message) };
45
+ export function rejectDeferred(ref: unknown, message: string): DeferredState<never> {
46
+ return complete(ref, { loading: false, value: null, error: new Error(message) }) as DeferredState<never>;
11
47
  }
12
48
  export function isLoading(ref: unknown): boolean {
13
49
  return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
@@ -0,0 +1,31 @@
1
+ import { useEffect, useState, type FC } from 'hono/jsx';
2
+ import { ErrorBoundary } from 'hono/jsx/dom';
3
+ import { jsx } from 'hono/jsx/dom/jsx-runtime';
4
+ import type { NavigationState } from 'void/pages-client';
5
+ import type { NavigationFallbackProps } from './pages.tsx';
6
+
7
+ export type NavigationFallbackOptions = { component: FC<NavigationFallbackProps>; delay: number };
8
+
9
+ /** Presentation only: it neither replaces the page nor acknowledges its commit. */
10
+ export function NavigationFallback({ state, options }: { state: NavigationState; options: NavigationFallbackOptions }) {
11
+ const [visibleFor, setVisibleFor] = useState<NavigationState | null>(null);
12
+ const [failedFor, setFailedFor] = useState<NavigationState | null>(null);
13
+ const loading = state.state === 'loading' && state.method === 'GET';
14
+ useEffect(() => {
15
+ setVisibleFor(null);
16
+ if (!loading) return;
17
+ const timer = setTimeout(() => setVisibleFor(state), options.delay);
18
+ return () => clearTimeout(timer);
19
+ }, [state]);
20
+ // Identity hides the old fallback immediately, before effect cleanup, on every
21
+ // new navigation/idle state. A queued old timer cannot affect another visit.
22
+ if (!loading || visibleFor !== state || failedFor === state) return null;
23
+ return <ErrorBoundary fallback={<></>} onError={error => queueMicrotask(() => {
24
+ // Hono retries a failed child on parent updates. Remove this presentation
25
+ // subtree before reporting the error; a later navigation may try again.
26
+ setFailedFor(state);
27
+ window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
28
+ })}>
29
+ <div data-hono-navigation-fallback role="status" aria-live="polite">{jsx(options.component, { navigation: state })}</div>
30
+ </ErrorBoundary>;
31
+ }
@@ -3,6 +3,8 @@ import { createActionClient, mergeDataIntoHref, type NavigationState, type Navig
3
3
  import type { CacheForInput } from 'void/pages-prefetch';
4
4
  import type { PageObject } from 'void/pages-protocol';
5
5
  export type { DeferredState as Deferred } from 'void';
6
+ export { deferredResult, type DeferredResult } from './deferred.ts';
7
+ export type NavigationFallbackProps = { navigation: NavigationState };
6
8
 
7
9
  const actionClient = createActionClient();
8
10
  export const action = actionClient.action;