void-plugin-hono-jsx 0.1.0-alpha.1 → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +8 -2
  3. package/dist/browser/client.d.ts +1 -0
  4. package/dist/browser/client.d.ts.map +1 -0
  5. package/dist/browser/client.js +1 -0
  6. package/dist/browser/client.js.map +1 -0
  7. package/dist/browser/deferred.d.ts +1 -0
  8. package/dist/browser/deferred.d.ts.map +1 -0
  9. package/dist/browser/deferred.js +1 -0
  10. package/dist/browser/deferred.js.map +1 -0
  11. package/dist/browser/document-head.d.ts +1 -0
  12. package/dist/browser/document-head.d.ts.map +1 -0
  13. package/dist/browser/document-head.js +1 -0
  14. package/dist/browser/document-head.js.map +1 -0
  15. package/dist/browser/form.d.ts +1 -0
  16. package/dist/browser/form.d.ts.map +1 -0
  17. package/dist/browser/form.js +1 -0
  18. package/dist/browser/form.js.map +1 -0
  19. package/dist/browser/pages.d.ts +1 -0
  20. package/dist/browser/pages.d.ts.map +1 -0
  21. package/dist/browser/pages.js +1 -0
  22. package/dist/browser/pages.js.map +1 -0
  23. package/dist/plugins/compatibility.d.ts +1 -0
  24. package/dist/plugins/compatibility.d.ts.map +1 -0
  25. package/dist/plugins/compatibility.js +1 -0
  26. package/dist/plugins/compatibility.js.map +1 -0
  27. package/dist/plugins/hono-islands.d.ts +1 -0
  28. package/dist/plugins/hono-islands.d.ts.map +1 -0
  29. package/dist/plugins/hono-islands.js +1 -0
  30. package/dist/plugins/hono-islands.js.map +1 -0
  31. package/dist/plugins/hono-jsx.d.ts +1 -0
  32. package/dist/plugins/hono-jsx.d.ts.map +1 -0
  33. package/dist/plugins/hono-jsx.js +1 -0
  34. package/dist/plugins/hono-jsx.js.map +1 -0
  35. package/dist/plugins/hono-pages.d.ts +1 -0
  36. package/dist/plugins/hono-pages.d.ts.map +1 -0
  37. package/dist/plugins/hono-pages.js +1 -0
  38. package/dist/plugins/hono-pages.js.map +1 -0
  39. package/dist/plugins/runtime-paths.d.ts +1 -0
  40. package/dist/plugins/runtime-paths.d.ts.map +1 -0
  41. package/dist/plugins/runtime-paths.js +13 -6
  42. package/dist/plugins/runtime-paths.js.map +1 -0
  43. package/dist/server/form.d.ts +1 -0
  44. package/dist/server/form.d.ts.map +1 -0
  45. package/dist/server/form.js +1 -0
  46. package/dist/server/form.js.map +1 -0
  47. package/dist/server/pages.d.ts +1 -0
  48. package/dist/server/pages.d.ts.map +1 -0
  49. package/dist/server/pages.js +1 -0
  50. package/dist/server/pages.js.map +1 -0
  51. package/package.json +2 -1
  52. package/src/plugins/compatibility.ts +27 -0
  53. package/src/plugins/hono-islands.ts +105 -0
  54. package/src/plugins/hono-jsx.ts +20 -0
  55. package/src/plugins/hono-pages.ts +142 -0
  56. package/src/plugins/runtime-paths.ts +14 -0
  57. package/src/runtime/client.tsx +83 -0
  58. package/src/runtime/deferred.ts +34 -0
  59. package/src/runtime/document-head.ts +44 -0
  60. package/src/runtime/form.ts +71 -0
  61. package/src/runtime/pages.tsx +45 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.0-alpha.2](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-alpha.1...v0.1.0-alpha.2) (2026-10-12)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * include package sources and valid debug maps ([#42](https://github.com/ts-76/void-plugin-hono-jsx/issues/42)) ([2a69fa5](https://github.com/ts-76/void-plugin-hono-jsx/commit/2a69fa59d903f150e7b9906419283a5906282b62))
9
+
10
+
11
+ ### Documentation
12
+
13
+ * distinguish future candidate archives from published alpha ([#45](https://github.com/ts-76/void-plugin-hono-jsx/issues/45)) ([d2740cb](https://github.com/ts-76/void-plugin-hono-jsx/commit/d2740cbb0dfff652fa17b10ff0504f5e353b4aaf))
14
+ * record published alpha as the default npm tag ([#44](https://github.com/ts-76/void-plugin-hono-jsx/issues/44)) ([8c8ea9a](https://github.com/ts-76/void-plugin-hono-jsx/commit/8c8ea9aa1d10e7ee2ff8946dea789d6b407d1680))
15
+
3
16
  ## [0.1.0-alpha.1](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-alpha.0...v0.1.0-alpha.1) (2026-10-11)
4
17
 
5
18
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Experimental Hono Pages adapter for Void
2
2
 
3
- This experimental package integrates Hono JSX with Void Pages. The package name is `void-plugin-hono-jsx`. `0.1.0-alpha.0` is published on the `next` dist-tag under the [MIT license](LICENSE). Use `@next`; `latest` remains a registration placeholder. It is not an official Void adapter.
3
+ This experimental package integrates Hono JSX with Void Pages. The package name is `void-plugin-hono-jsx`. Alpha releases are published on the `next` dist-tag under the [MIT license](LICENSE). Use `@next` or an explicit alpha version. The maintainer also assigned `latest` to the published `0.1.0-alpha.1`; an unqualified install currently selects this experimental alpha, not a stable release. It is not an official Void adapter.
4
4
 
5
5
  ## Supported versions
6
6
 
@@ -25,7 +25,7 @@ npm install --save-dev void@0.26.1 vite@8.3.3 typescript@7.0.2
25
25
  For a local validation tarball, in the repository, run `npm ci`, `npm run build:package`, then `npm pack ./packages/hono-pages`. Install the resulting tarball in your project alongside the supported peer versions:
26
26
 
27
27
  ```sh
28
- npm install ./void-plugin-hono-jsx-0.1.0-alpha.0.tgz hono@4.13.13
28
+ npm install ./void-plugin-hono-jsx-<version>.tgz hono@4.13.13
29
29
  npm install --save-dev void@0.26.1 vite@8.3.3 typescript@7.0.2
30
30
  ```
31
31
 
@@ -44,6 +44,12 @@ Configure project settings in `void.config.ts` using `defineConfig` from `void/c
44
44
 
45
45
  Use `jsx: "react-jsx"` and `jsxImportSource: "hono/jsx"` in TypeScript. The plugin chooses the server or DOM factory for application JSX; the plugin resolves package runtime exports using Vite's actual consumer environment. Cloudflare worker environments may enable the browser condition, so that condition alone cannot select the renderer.
46
46
 
47
+ ## Source and debugging files
48
+
49
+ The next alpha candidate includes the original `src/plugins/*.ts` and `src/runtime/*.{ts,tsx}` alongside compiled `dist` entries. Every JavaScript file has a `.js.map` with embedded original source; every declaration has a `.d.ts.map` pointing to the same packaged TypeScript files. Build-time import rewriting composes its map with the compiler map, so generated locations still refer to the original source. These additions require a new release; alpha.0 and alpha.1 remain unchanged.
50
+
51
+ Read source under `node_modules/void-plugin-hono-jsx/src`. Editors supporting declaration maps can navigate from exported types to those files, and debuggers/bundlers supporting source maps can show the original source. Application imports continue to use `/plugin`, `/pages` and `/form`; `src` is supplied for inspection and debugging, not as an additional runtime entry point. Candidate and clean-consumer checks reject missing/stale maps, external source references, changed source bytes and unexpected archive files.
52
+
47
53
  ## Runtime exports
48
54
 
49
55
  ```tsx
@@ -2,3 +2,4 @@ import { type VoidRouterConfig } from 'void/pages-client';
2
2
  type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
3
3
  export declare function startHonoPages(manifest: Manifest): Promise<void>;
4
4
  export {};
5
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM5E,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,iBAkEtD"}
@@ -75,3 +75,4 @@ export async function startHonoPages(manifest) {
75
75
  root.dataset.navigation = 'idle';
76
76
  root.dataset.honoPages = 'mounted';
77
77
  }
78
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B;AAC9C,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU;AACpD,OAAO,EAAE,gBAAgB,EAAyB,MAAM,mBAAmB;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB;AACnD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,4BAAa;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB;AACvD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,eAAe;AAIjH,SAAS,aAAa,CAAC,SAAkB;IACvC,IAAI,OAAO,SAAS,KAAK,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC;IAC5G,OAAO,SAAS;AAClB;AAEA,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAkB;IACrD,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC;IAC3C,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC;IAE9D,IAAI,MAA4C;IAChD,IAAI,QAAQ,GAAG,CAAC;IAChB,IAAI,iBAAoE;IACxE,IAAI,aAAkD;IACtD,IAAI,cAAsE;IAC1E,MAAM,cAAc,GAAG,gBAAgB,CAAC;QACtC,GAAG,QAAQ;QACX,OAAO,EAAE;YACP,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS;YAC1D,gBAAgB,CAAC,KAAK;gBACpB,IAAI,KAAK,KAAK,aAAa;oBAAE,cAAc,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;YAC7D,CAAC;YACD,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO;gBACjD,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;gBAC9B,aAAa,CAAC,SAAS,CAAC;gBACxB,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC;gBAC3E,IAAI,CAAC,OAAO,CAAC,aAAa;oBAAE,QAAQ,EAAE;gBACtC,aAAa,GAAG,IAAI,CAAC,KAAK;gBAC1B,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;gBACrF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC5E,iBAAiB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YAChC,CAAC;SACF;QACD,eAAe,EAAE,KAAK;QACtB,kBAAkB,EAAE,EAAE;QACtB,uBAAuB,EAAE,aAAa,CAAC,KAAK,CAAC;QAC7C,oBAAoB,EAAE,KAAK;QAC3B,kBAAkB,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;KACrE,CAAC;IACF,MAAM,aAAa,GAAG,qBAAqB,EAAE;IAC7C,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC;IAC9D,aAAa,GAAG,UAAU,CAAC,eAAe,CAAC,KAAK;IAChD,iBAAiB,GAAG,kBAAkB,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC;IAEvE,SAAS,GAAG;QACV,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,UAAU,CAAC,eAAe,EAAE,KAAK,EAAE,EAAE,GAAG,UAAU,CAAC,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,gBAAgB,EAAE,OAAO,EAAE,UAAU,CAAC,cAAc,EAAE,QAAQ,EAAE,CAAC;QAC5N,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC3C,eAAe,CAAC,GAAG,EAAE;YACnB,cAAc,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC/F,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC;YACrC,MAAM,CAAC,gBAAgB,CAAC,6BAA6B,EAAE,OAAO,CAAC;YAC/D,OAAO,GAAG,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACtI,CAAC,EAAE,EAAE,CAAC;QACN,IAAI,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3F,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;QAC3D,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;YAC9D,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACvF;QACA,OAAO,KAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,UAAU,CAAC,MAAM,YACrD,MAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,CAAC,IAAI,aACpC,MAAM,IAAI,YAAG,IAAI,EAAC,OAAO,gEAAoD,EAC7E,OAAO,IACa,GACA;IAC3B;IAEA,MAAM,CAAC,KAAC,GAAG,KAAG,EAAE,IAAI,CAAC;IACrB,UAAU,CAAC,KAAK,EAAE;IAClB,UAAU,CAAC,mBAAmB,EAAE;IAChC,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,MAAM;IAChC,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,SAAS;AACpC","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { createVoidRouter, type VoidRouterConfig } from 'void/pages-client';\nimport { parseCacheFor } from 'void/pages-prefetch';\nimport { PageContext, RouterContext } from './pages.tsx';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\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) {\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 createVoidRouter>>['initialPageData']; component: unknown; layouts: unknown[]; revision: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\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 = createVoidRouter({\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 update({ page: { ...page, props: { ...page.props } }, component, layouts, revision });\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n applyDocumentHead?.(page.head);\n },\n },\n viewTransitions: false,\n prefetchHoverDelay: 75,\n prefetchDefaultCacheFor: parseCacheFor('30s'),\n cacheVisitedPageData: false,\n onNavigationChange(state) { root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n function App() {\n const [frame, setFrame] = useState<Frame>({ page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision });\n const [failed, setFailed] = useState(false);\n useLayoutEffect(() => {\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 () => { update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\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 <RouterContext.Provider value={navigation.router}>\n <PageContext.Provider value={frame.page}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n {content}\n </PageContext.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"]}
@@ -11,3 +11,4 @@ declare global {
11
11
  }
12
12
  }
13
13
  export declare function bufferInitialDeferred(): () => void;
14
+ //# 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,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"}
@@ -20,3 +20,4 @@ export function bufferInitialDeferred() {
20
20
  window.__rejectDeferred = reject;
21
21
  };
22
22
  }
23
+ //# sourceMappingURL=deferred.js.map
@@ -0,0 +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,3 +1,4 @@
1
1
  import type { HeadDescriptor } from 'void';
2
2
  /** Complements Void's title/meta/link updates without executing navigation scripts. */
3
3
  export declare function createDocumentHead(initial: HeadDescriptor | undefined): (head: HeadDescriptor | undefined) => void;
4
+ //# sourceMappingURL=document-head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-head.d.ts","sourceRoot":"","sources":["../../src/runtime/document-head.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAY3C,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,UAgBtD,cAAc,GAAG,SAAS,UAazC"}
@@ -42,3 +42,4 @@ export function createDocumentHead(initial) {
42
42
  script.remove();
43
43
  };
44
44
  }
45
+ //# sourceMappingURL=document-head.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-head.js","sourceRoot":"","sources":["../../src/runtime/document-head.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHeadToString } from 'void/pages-head';\nimport type { HeadDescriptor } from 'void';\n\nfunction scriptSignature(script: HTMLScriptElement) {\n return JSON.stringify([Array.from(script.attributes, ({ name, value }) => [name, value]).sort(), script.textContent]);\n}\n\nfunction scriptElements(head: HeadDescriptor | undefined) {\n const template = document.createElement('template');\n template.innerHTML = renderHeadToString({ script: head?.script });\n return Array.from(template.content.querySelectorAll('script'));\n}\n\n/** Complements Void's title/meta/link updates without executing navigation scripts. */\nexport function createDocumentHead(initial: HeadDescriptor | undefined) {\n let htmlKeys = Object.keys(initial?.htmlAttrs ?? {});\n let bodyKeys = Object.keys(initial?.bodyAttrs ?? {});\n let scripts: HTMLScriptElement[] = [];\n const existing = Array.from(document.head.querySelectorAll('script'));\n for (const desired of scriptElements(initial)) {\n const index = existing.findIndex((script) => scriptSignature(script) === scriptSignature(desired));\n if (index >= 0) scripts.push(...existing.splice(index, 1));\n }\n\n function attributes(element: HTMLElement, previous: string[], next: Record<string, string> = {}) {\n for (const key of previous) if (!(key in next)) element.removeAttribute(key);\n for (const [key, value] of Object.entries(next)) element.setAttribute(key, value);\n return Object.keys(next);\n }\n\n return (head: HeadDescriptor | undefined) => {\n htmlKeys = attributes(document.documentElement, htmlKeys, head?.htmlAttrs);\n bodyKeys = attributes(document.body, bodyKeys, head?.bodyAttrs);\n const remaining = [...scripts];\n scripts = scriptElements(head).map((desired) => {\n const index = remaining.findIndex((script) => scriptSignature(script) === scriptSignature(desired));\n if (index >= 0) return remaining.splice(index, 1)[0];\n // Template-parsed scripts remain inert when inserted. Head changes are metadata, not script execution.\n document.head.appendChild(desired);\n return desired;\n });\n for (const script of remaining) script.remove();\n };\n}\n"]}
@@ -14,3 +14,4 @@ export declare function useForm<T extends Record<string, unknown>>(initialData:
14
14
  patch: (url: string) => Promise<void>;
15
15
  delete: (url: string) => Promise<void>;
16
16
  };
17
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/runtime/form.ts"],"names":[],"mappings":"AACA,OAAO,EAA+C,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AASjG,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;;;;;;;qBAmBzC,UAAU,OAAO,MAAM;;;gBAoCvC,MAAM;eACP,MAAM;iBACJ,MAAM;kBACL,MAAM;EAEvB"}
@@ -78,3 +78,4 @@ export function useForm(initialData) {
78
78
  delete: (url) => submit('delete', url),
79
79
  };
80
80
  }
81
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/form.ts"],"sourcesContent":["import { useContext, useRef, useState } from 'hono/jsx';\nimport { isAbortError, submitAction, VoidActionError, type FormMethod } from 'void/pages-client';\nimport { RouterContext, useErrors, useRouter } from './pages.tsx';\n\nfunction fieldErrors(error: VoidActionError): Record<string, string> {\n const body = error.body;\n if (typeof body !== 'object' || body === null || !('errors' in body) || typeof body.errors !== 'object' || body.errors === null) return {};\n return Object.fromEntries(Object.entries(body.errors).filter((entry): entry is [string, string] => typeof entry[1] === 'string'));\n}\n\nexport function useForm<T extends Record<string, unknown>>(initialData: T) {\n if (!useContext(RouterContext)) throw new Error('Hono Pages: useForm requires the full Pages renderer; island form helpers are unsupported.');\n const router = useRouter();\n const initialErrors = useErrors();\n const [data, updateData] = useState(initialData);\n const [errors, setErrors] = useState(initialErrors);\n const [pending, setPending] = useState(false);\n const [wasSuccessful, setSuccessful] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const active = useRef(false);\n const generation = useRef(0);\n\n const setData: typeof updateData = (next) => {\n updateData(next);\n setSuccessful(false);\n setErrors({});\n setError(null);\n };\n\n async function submit(method: FormMethod, url: string) {\n if (active.current) return;\n active.current = true;\n const id = ++generation.current;\n setPending(true);\n setSuccessful(false);\n setError(null);\n setErrors({});\n try {\n const result = await submitAction(router, url, { method: method.toUpperCase(), data, preserveScroll: true });\n if (id !== generation.current) return;\n if (result.ok) setSuccessful(true);\n else { setError(result.error); setErrors(fieldErrors(result.error)); }\n } catch (failure) {\n if (id === generation.current && !isAbortError(failure)) {\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n }\n } finally {\n if (id === generation.current) { active.current = false; setPending(false); }\n }\n }\n\n function cancel() {\n if (!active.current) return;\n const id = ++generation.current;\n active.current = false;\n setPending(false);\n setSuccessful(false);\n void router.refresh().catch((failure: unknown) => {\n if (id === generation.current) setError(failure instanceof Error ? failure : new Error(String(failure)));\n });\n }\n\n return {\n data, setData, errors, pending, wasSuccessful, error, submit, cancel,\n reset() { setData(initialData); },\n post: (url: string) => submit('post', url),\n put: (url: string) => submit('put', url),\n patch: (url: string) => submit('patch', url),\n delete: (url: string) => submit('delete', url),\n };\n}\n"]}
@@ -15,3 +15,4 @@ type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {
15
15
  onClick?: (event: MouseEvent) => void;
16
16
  };
17
17
  export declare function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps): import("hono/jsx/dom/jsx-dev-runtime").JSX.Element;
18
+ //# sourceMappingURL=pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEtD,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,KAAK,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,EAAE,SAAS,sDAaxF"}
@@ -34,3 +34,4 @@ export function Link({ href, reloadDocument, replace, onClick, ...attributes })
34
34
  });
35
35
  } });
36
36
  }
37
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAY,MAAM,UAAU,CAAC;AAK/D,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AAElE,SAAS,OAAO;IACd,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;AAE9D,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC;AAChB,CAAC;AASD,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,UAAU,EAAa;IACvF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,OAAO,eAAO,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,KAAiB,EAAE,EAAE;YACnE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACjB,IAAI,KAAK,CAAC,gBAAgB,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC/I,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,CAAC,IAAI,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAAE,OAAO;YAC3J,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACjG,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC3D,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC1F,CAAC,CAAC,CAAC;QACL,CAAC,GAAI,CAAC;AACR,CAAC","sourcesContent":["import { createContext, useContext, type JSX } from 'hono/jsx';\nimport type { VoidRouter } from 'void/pages-client';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nexport const RouterContext = createContext<VoidRouter | 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 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\ntype LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n reloadDocument?: boolean;\n replace?: boolean;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps) {\n const router = useRouter();\n return <a {...attributes} href={href} onClick={(event: MouseEvent) => {\n onClick?.(event);\n if (event.defaultPrevented || reloadDocument || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n if (attributes.download !== undefined || (attributes.target && attributes.target !== '_self') || attributes.rel?.split(/\\s+/).includes('external')) return;\n const url = new URL(href, window.location.href);\n if (url.origin !== window.location.origin || !['http:', 'https:'].includes(url.protocol)) return;\n event.preventDefault();\n void router.visit(url, { replace }).catch((error: unknown) => {\n window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n });\n }} />;\n}\n"]}
@@ -1 +1,2 @@
1
1
  export declare function assertSupportedFrameworks(): void;
2
+ //# sourceMappingURL=compatibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/plugins/compatibility.ts"],"names":[],"mappings":"AAKA,wBAAgB,yBAAyB,SAqBxC"}
@@ -27,3 +27,4 @@ export function assertSupportedFrameworks() {
27
27
  throw new Error(`Hono Pages: ${name} ${version} is unverified; install ${name}@${expected}. The adapter requires void@0.26.1, hono@4.13.13 and vite@8.3.3.`);
28
28
  }
29
29
  }
30
+ //# sourceMappingURL=compatibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../../src/plugins/compatibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACrE,MAAM,UAAU,yBAAyB;IACvC,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACzD,IAAI,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/C,IAAI,OAA2B,CAAC;QAChC,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YAC7C,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,MAAM,QAAQ,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;gBACjE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,MAAM,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;oBACtG,IAAI,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ;wBAAE,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,8BAA8B,CAAC,CAAC;oBACzI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;oBAC3B,MAAM;gBACR,CAAC;YACH,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;YAClC,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,oBAAoB,CAAC,CAAC;YACjG,SAAS,GAAG,MAAM,CAAC;QACrB,CAAC;QACD,IAAI,OAAO,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,IAAI,OAAO,2BAA2B,IAAI,IAAI,QAAQ,kEAAkE,CAAC,CAAC;IACzL,CAAC;AACH,CAAC","sourcesContent":["import { createRequire } from 'node:module';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nconst supported = { void: '0.26.1', hono: '4.13.13', vite: '8.3.3' };\nexport function assertSupportedFrameworks() {\n const require = createRequire(import.meta.url);\n for (const [name, expected] of Object.entries(supported)) {\n let directory = dirname(require.resolve(name));\n let version: string | undefined;\n while (true) {\n const path = join(directory, 'package.json');\n if (existsSync(path)) {\n const metadata: unknown = JSON.parse(readFileSync(path, 'utf8'));\n if (typeof metadata === 'object' && metadata !== null && 'name' in metadata && metadata.name === name) {\n if (!('version' in metadata) || typeof metadata.version !== 'string') throw new Error(`Hono Pages: ${name} package version is missing.`);\n version = metadata.version;\n break;\n }\n }\n const parent = dirname(directory);\n if (parent === directory) throw new Error(`Hono Pages: cannot locate ${name} package metadata.`);\n directory = parent;\n }\n if (version !== expected) throw new Error(`Hono Pages: ${name} ${version} is unverified; install ${name}@${expected}. The adapter requires void@0.26.1, hono@4.13.13 and vite@8.3.3.`);\n }\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  import { type Plugin } from 'vite';
2
2
  /** Narrow adapter for Void's load-on-page-load island convention. */
3
3
  export declare function honoIslands(): Plugin;
4
+ //# sourceMappingURL=hono-islands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono-islands.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-islands.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAI7D,qEAAqE;AACrE,wBAAgB,WAAW,IAAI,MAAM,CAiGpC"}
@@ -110,3 +110,4 @@ initIslands({ ${loaders} }, (element, module, props) => {
110
110
  },
111
111
  };
112
112
  }
113
+ //# sourceMappingURL=hono-islands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono-islands.js","sourceRoot":"","sources":["../../src/plugins/hono-islands.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, realpathSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport { normalizePath, parseSync, type Plugin } from 'vite';\nimport { scanPages, resolvePagesDir, type PageScanResult } from 'void/pages';\nimport { findIslandImports, editIslandSource, resolveSpecifier, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';\n\n/** Narrow adapter for Void's load-on-page-load island convention. */\nexport function honoIslands(): Plugin {\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const islands = new Map<string, string>();\n const pageFiles = new Set<string>();\n let scan: PageScanResult | undefined;\n\n function islandImports(code: string, filename: string) {\n const found = findIslandImports(code, filename);\n const attributed = parseSync(filename, code).program.body.filter((node) => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));\n if (attributed.length !== found.length) throw new Error(`Hono islands: use one default import with exactly one island: 'load' attribute in ${filename}.`);\n return found;\n }\n\n function imports(code: string, filename: string) {\n const found = islandImports(code, filename);\n for (const entry of found) {\n if (entry.hydrate !== 'load') throw new Error(`Hono islands: unsupported policy '${entry.hydrate}' in ${filename}; use island: 'load'.`);\n if (!entry.specifier.startsWith('.')) throw new Error(`Hono islands: use a relative TSX/JSX component import in ${filename}.`);\n const path = resolveSpecifier(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);\n if (!path || !/\\.[jt]sx$/.test(path)) throw new Error(`Hono islands: cannot resolve TSX/JSX component ${entry.specifier} in ${filename}.`);\n const canonical = realpathSync(path);\n const id = normalizePath(relative(root, canonical));\n islands.set(id, canonical);\n }\n return found;\n }\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n islands.clear();\n pageFiles.clear();\n for (const page of scan.pages.filter((page) => page.island)) {\n const filename = realpathSync(join(pagesDir, page.componentPath));\n pageFiles.add(filename);\n imports(readFileSync(filename, 'utf8'), filename);\n }\n }\n\n return {\n name: 'void-hono:islands',\n enforce: 'pre',\n buildStart: rescan,\n async hotUpdate({ file }) {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) await rescan();\n },\n config() {\n return { build: { rollupOptions: { input: { 'islands-client': ISLANDS_CLIENT_ENTRY_ID } } } };\n },\n resolveId(id) {\n if (id === ISLANDS_RENDERER_ID || id === ISLANDS_CLIENT_ENTRY_ID) return `\\0${id}`;\n },\n transform(code, id) {\n const filename = id.split('?')[0];\n if (!/\\.[jt]sx$/.test(filename) || filename.includes('/node_modules/')) return;\n const canonical = realpathSync(filename);\n if ((pageFiles.has(canonical) || [...islands.values()].includes(canonical)) && parseSync(filename, code).program.body.some((node) => node.type === 'ImportDeclaration' && node.source.value === 'void-plugin-hono-jsx/form')) {\n throw new Error('Hono islands: form helpers are unsupported; use a full Pages component.');\n }\n const found = islandImports(code, filename);\n if (!found.length) return;\n if (!pageFiles.has(realpathSync(filename))) throw new Error('Hono islands: attributed imports are supported only directly in .island.tsx/.island.jsx pages.');\n imports(code, filename);\n return editIslandSource(code, found.map((entry) => {\n const path = resolveSpecifier(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);\n if (!path) throw new Error(`Hono islands: missing component ${entry.specifier}.`);\n const islandId = normalizePath(relative(root, realpathSync(path)));\n const component = `__honoIslandComponent${entry.start}`;\n return { start: entry.start, end: entry.end, text: `import ${component} from ${entry.specifierRaw};\nconst ${entry.importName} = (props) => __honoIslandJsx('div', { 'data-island': ${JSON.stringify(islandId)}, 'data-hydrate': 'load', 'data-props': JSON.stringify(props), children: __honoIslandJsx(${component}, props) });` };\n }), { prepend: \"import { jsx as __honoIslandJsx } from 'hono/jsx/jsx-runtime';\\n\" });\n },\n load(id) {\n if (id === `\\0${ISLANDS_RENDERER_ID}`) {\n if (!scan) throw new Error('Hono islands: page discovery has not completed.');\n const interactive = [...computePagesNeedingClientJS(scan, pagesDir, null)];\n return `import { renderPage } from 'virtual:void-pages-renderer';\nconst interactive = new Set(${JSON.stringify(interactive)});\nexport function renderIslandPage(page, assets) {\n if (page.deferred?.length || page.deferredKeys) throw new Error('Hono islands: deferred props are unsupported.');\n return renderPage(page, interactive.has(page.component) ? assets : { ...assets, preloads: '', body: '' });\n}`;\n }\n if (id === `\\0${ISLANDS_CLIENT_ENTRY_ID}`) {\n if (!islands.size) return 'export {};';\n const loaders = [...islands].map(([name, path]) => `${JSON.stringify(name)}: () => import(${JSON.stringify(path)})`).join(',\\n');\n return `import { initIslands } from 'void/pages-client';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { render } from 'hono/jsx/dom';\ninitIslands({ ${loaders} }, (element, module, props) => {\n if (typeof module.default !== 'function') throw new Error('Hono islands: a component must export a default function.');\n render(jsx(module.default, props), element);\n element.setAttribute('data-hono-island', 'mounted');\n});`;\n }\n },\n };\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  import { type Plugin } from 'vite';
2
2
  /** JSX factories differ by Vite environment; hooks can be shared via hono/jsx. */
3
3
  export declare function honoJsx(): Plugin;
4
+ //# sourceMappingURL=hono-jsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono-jsx.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAErD,kFAAkF;AAClF,wBAAgB,OAAO,IAAI,MAAM,CAgBhC"}
@@ -18,3 +18,4 @@ export function honoJsx() {
18
18
  },
19
19
  };
20
20
  }
21
+ //# sourceMappingURL=hono-jsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono-jsx.js","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,MAAM,MAAM,CAAC;AAErD,kFAAkF;AAClF,MAAM,UAAU,OAAO;IACrB,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,KAAK;QACd,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE;YACtB,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAAE,OAAO;YAC/E,OAAO,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE;gBACtC,GAAG,EAAE;oBACH,OAAO,EAAE,WAAW;oBACpB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU;oBACzF,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,KAAK;iBAC7C;aACF,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { transformWithOxc, type Plugin } from 'vite';\n\n/** JSX factories differ by Vite environment; hooks can be shared via hono/jsx. */\nexport function honoJsx(): Plugin {\n return {\n name: 'poc:hono-jsx',\n enforce: 'pre',\n async transform(code, id) {\n const filename = id.split('?')[0];\n if (!/\\.[jt]sx$/.test(filename) || filename.includes('/node_modules/')) return;\n return transformWithOxc(code, filename, {\n jsx: {\n runtime: 'automatic',\n importSource: this.environment.config.consumer === 'client' ? 'hono/jsx/dom' : 'hono/jsx',\n development: this.environment.mode === 'dev',\n },\n });\n },\n };\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  import type { Plugin } from 'vite';
2
2
  /** Experimental Pages contract verified against Void 0.26.1. */
3
3
  export declare function voidHonoPages(): Plugin[];
4
+ //# sourceMappingURL=hono-pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono-pages.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-pages.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAQnC,gEAAgE;AAChE,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAgIxC"}
@@ -146,3 +146,4 @@ await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPage
146
146
  },
147
147
  }];
148
148
  }
149
+ //# sourceMappingURL=hono-pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono-pages.js","sourceRoot":"","sources":["../../src/plugins/hono-pages.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync } from 'node:fs';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { honoJsx } from './hono-jsx.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\n/** Experimental Pages contract verified against Void 0.26.1. */\nexport function voidHonoPages(): Plugin[] {\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n if (layout.island || !/\\.[jt]sx$/.test(layout.filePath)) throw new Error('Hono Pages: only standard TSX/JSX layouts are supported.');\n }\n for (const page of scan.pages) {\n if (!/\\.[jt]sx$/.test(page.componentPath)) {\n throw new Error(`Hono Pages: only standard TSX/JSX pages are supported: ${page.componentPath}.`);\n }\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(), honoJsx(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config() {\n assertSupportedFrameworks();\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\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) 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) }\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 return `\nimport { jsx } from 'hono/jsx';\nimport { createSsrRouter } from 'void/pages-client';\nimport { PageContext, RouterContext } 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 } = 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 const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: content }) }).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 + '<div id=\"app\">' + markup + '</div>' + 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)} });\n`;\n },\n }];\n}\n"]}
@@ -4,3 +4,4 @@ export declare const publicRuntimeModules: Record<string, {
4
4
  server: string;
5
5
  client: string;
6
6
  }>;
7
+ //# sourceMappingURL=runtime-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-paths.d.ts","sourceRoot":"","sources":["../../src/plugins/runtime-paths.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,QAAoG,CAAC;AAClI,eAAO,MAAM,iBAAiB,QAAuG,CAAC;AACtI,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAM9E,CAAC"}
@@ -1,7 +1,14 @@
1
1
  import { fileURLToPath } from 'node:url';
2
- export const pagesRuntimePath = fileURLToPath(new URL('../server/pages.js', import.meta.url));
3
- export const clientRuntimePath = fileURLToPath(new URL('../browser/client.js', import.meta.url));
4
- export const publicRuntimeModules = {
5
- "void-plugin-hono-jsx/pages": { server: fileURLToPath(new URL('../server/pages.js', import.meta.url)), client: fileURLToPath(new URL('../browser/pages.js', import.meta.url)) },
6
- "void-plugin-hono-jsx/form": { server: fileURLToPath(new URL('../server/form.js', import.meta.url)), client: fileURLToPath(new URL('../browser/form.js', import.meta.url)) },
7
- };
2
+ // Source fixtures use TSX; npm consumers use the precompiled environment entries.
3
+ // Keep this adaptation in TypeScript so both emitted maps describe the actual code.
4
+ const compiled = new URL(import.meta.url).pathname.endsWith('.js');
5
+ export const pagesRuntimePath = fileURLToPath(new URL(compiled ? '../server/pages.js' : '../runtime/pages.tsx', import.meta.url));
6
+ export const clientRuntimePath = fileURLToPath(new URL(compiled ? '../browser/client.js' : '../runtime/client.tsx', import.meta.url));
7
+ export const publicRuntimeModules = compiled ? {
8
+ 'void-plugin-hono-jsx/pages': { server: pagesRuntimePath, client: fileURLToPath(new URL('../browser/pages.js', import.meta.url)) },
9
+ 'void-plugin-hono-jsx/form': {
10
+ server: fileURLToPath(new URL('../server/form.js', import.meta.url)),
11
+ client: fileURLToPath(new URL('../browser/form.js', import.meta.url)),
12
+ },
13
+ } : {};
14
+ //# sourceMappingURL=runtime-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-paths.js","sourceRoot":"","sources":["../../src/plugins/runtime-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,kFAAkF;AAClF,oFAAoF;AACpF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,sBAAsB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAClI,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,uBAAuB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACtI,MAAM,CAAC,MAAM,oBAAoB,GAAuD,QAAQ,CAAC,CAAC,CAAC;IACjG,4BAA4B,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,qBAAqB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;IAClI,2BAA2B,EAAE;QAC3B,MAAM,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,mBAAmB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACpE,MAAM,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;KACtE;CACF,CAAC,CAAC,CAAC,EAAE,CAAC","sourcesContent":["import { fileURLToPath } from 'node:url';\n\n// Source fixtures use TSX; npm consumers use the precompiled environment entries.\n// Keep this adaptation in TypeScript so both emitted maps describe the actual code.\nconst compiled = new URL(import.meta.url).pathname.endsWith('.js');\nexport const pagesRuntimePath = fileURLToPath(new URL(compiled ? '../server/pages.js' : '../runtime/pages.tsx', import.meta.url));\nexport const clientRuntimePath = fileURLToPath(new URL(compiled ? '../browser/client.js' : '../runtime/client.tsx', import.meta.url));\nexport const publicRuntimeModules: Record<string, { server: string; client: string }> = compiled ? {\n 'void-plugin-hono-jsx/pages': { server: pagesRuntimePath, client: fileURLToPath(new URL('../browser/pages.js', import.meta.url)) },\n 'void-plugin-hono-jsx/form': {\n server: fileURLToPath(new URL('../server/form.js', import.meta.url)),\n client: fileURLToPath(new URL('../browser/form.js', import.meta.url)),\n },\n} : {};\n"]}
@@ -14,3 +14,4 @@ export declare function useForm<T extends Record<string, unknown>>(initialData:
14
14
  patch: (url: string) => Promise<void>;
15
15
  delete: (url: string) => Promise<void>;
16
16
  };
17
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/runtime/form.ts"],"names":[],"mappings":"AACA,OAAO,EAA+C,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AASjG,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;;;;;;;qBAmBzC,UAAU,OAAO,MAAM;;;gBAoCvC,MAAM;eACP,MAAM;iBACJ,MAAM;kBACL,MAAM;EAEvB"}
@@ -78,3 +78,4 @@ export function useForm(initialData) {
78
78
  delete: (url) => submit('delete', url),
79
79
  };
80
80
  }
81
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/form.ts"],"sourcesContent":["import { useContext, useRef, useState } from 'hono/jsx';\nimport { isAbortError, submitAction, VoidActionError, type FormMethod } from 'void/pages-client';\nimport { RouterContext, useErrors, useRouter } from './pages.tsx';\n\nfunction fieldErrors(error: VoidActionError): Record<string, string> {\n const body = error.body;\n if (typeof body !== 'object' || body === null || !('errors' in body) || typeof body.errors !== 'object' || body.errors === null) return {};\n return Object.fromEntries(Object.entries(body.errors).filter((entry): entry is [string, string] => typeof entry[1] === 'string'));\n}\n\nexport function useForm<T extends Record<string, unknown>>(initialData: T) {\n if (!useContext(RouterContext)) throw new Error('Hono Pages: useForm requires the full Pages renderer; island form helpers are unsupported.');\n const router = useRouter();\n const initialErrors = useErrors();\n const [data, updateData] = useState(initialData);\n const [errors, setErrors] = useState(initialErrors);\n const [pending, setPending] = useState(false);\n const [wasSuccessful, setSuccessful] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const active = useRef(false);\n const generation = useRef(0);\n\n const setData: typeof updateData = (next) => {\n updateData(next);\n setSuccessful(false);\n setErrors({});\n setError(null);\n };\n\n async function submit(method: FormMethod, url: string) {\n if (active.current) return;\n active.current = true;\n const id = ++generation.current;\n setPending(true);\n setSuccessful(false);\n setError(null);\n setErrors({});\n try {\n const result = await submitAction(router, url, { method: method.toUpperCase(), data, preserveScroll: true });\n if (id !== generation.current) return;\n if (result.ok) setSuccessful(true);\n else { setError(result.error); setErrors(fieldErrors(result.error)); }\n } catch (failure) {\n if (id === generation.current && !isAbortError(failure)) {\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n }\n } finally {\n if (id === generation.current) { active.current = false; setPending(false); }\n }\n }\n\n function cancel() {\n if (!active.current) return;\n const id = ++generation.current;\n active.current = false;\n setPending(false);\n setSuccessful(false);\n void router.refresh().catch((failure: unknown) => {\n if (id === generation.current) setError(failure instanceof Error ? failure : new Error(String(failure)));\n });\n }\n\n return {\n data, setData, errors, pending, wasSuccessful, error, submit, cancel,\n reset() { setData(initialData); },\n post: (url: string) => submit('post', url),\n put: (url: string) => submit('put', url),\n patch: (url: string) => submit('patch', url),\n delete: (url: string) => submit('delete', url),\n };\n}\n"]}
@@ -15,3 +15,4 @@ type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {
15
15
  onClick?: (event: MouseEvent) => void;
16
16
  };
17
17
  export declare function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
18
+ //# sourceMappingURL=pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEtD,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,KAAK,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,EAAE,SAAS,kDAaxF"}
@@ -34,3 +34,4 @@ export function Link({ href, reloadDocument, replace, onClick, ...attributes })
34
34
  });
35
35
  } });
36
36
  }
37
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAY,MAAM,UAAU,CAAC;AAK/D,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AAElE,SAAS,OAAO;IACd,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;AAE9D,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC;AAChB,CAAC;AASD,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,UAAU,EAAa;IACvF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,OAAO,eAAO,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,KAAiB,EAAE,EAAE;YACnE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACjB,IAAI,KAAK,CAAC,gBAAgB,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC/I,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,CAAC,IAAI,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAAE,OAAO;YAC3J,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACjG,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC3D,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC1F,CAAC,CAAC,CAAC;QACL,CAAC,GAAI,CAAC;AACR,CAAC","sourcesContent":["import { createContext, useContext, type JSX } from 'hono/jsx';\nimport type { VoidRouter } from 'void/pages-client';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nexport const RouterContext = createContext<VoidRouter | 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 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\ntype LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n reloadDocument?: boolean;\n replace?: boolean;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps) {\n const router = useRouter();\n return <a {...attributes} href={href} onClick={(event: MouseEvent) => {\n onClick?.(event);\n if (event.defaultPrevented || reloadDocument || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n if (attributes.download !== undefined || (attributes.target && attributes.target !== '_self') || attributes.rel?.split(/\\s+/).includes('external')) return;\n const url = new URL(href, window.location.href);\n if (url.origin !== window.location.origin || !['http:', 'https:'].includes(url.protocol)) return;\n event.preventDefault();\n void router.visit(url, { replace }).catch((error: unknown) => {\n window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n });\n }} />;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void-plugin-hono-jsx",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0-alpha.2",
4
4
  "private": false,
5
5
  "description": "Experimental Hono JSX Pages adapter for Void 0.26.1",
6
6
  "type": "module",
@@ -10,6 +10,7 @@
10
10
  },
11
11
  "files": [
12
12
  "dist",
13
+ "src",
13
14
  "README.md",
14
15
  "THIRD_PARTY_NOTICES.md",
15
16
  "LICENSE",
@@ -0,0 +1,27 @@
1
+ import { createRequire } from 'node:module';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ const supported = { void: '0.26.1', hono: '4.13.13', vite: '8.3.3' };
6
+ export function assertSupportedFrameworks() {
7
+ const require = createRequire(import.meta.url);
8
+ for (const [name, expected] of Object.entries(supported)) {
9
+ let directory = dirname(require.resolve(name));
10
+ let version: string | undefined;
11
+ while (true) {
12
+ const path = join(directory, 'package.json');
13
+ if (existsSync(path)) {
14
+ const metadata: unknown = JSON.parse(readFileSync(path, 'utf8'));
15
+ if (typeof metadata === 'object' && metadata !== null && 'name' in metadata && metadata.name === name) {
16
+ if (!('version' in metadata) || typeof metadata.version !== 'string') throw new Error(`Hono Pages: ${name} package version is missing.`);
17
+ version = metadata.version;
18
+ break;
19
+ }
20
+ }
21
+ const parent = dirname(directory);
22
+ if (parent === directory) throw new Error(`Hono Pages: cannot locate ${name} package metadata.`);
23
+ directory = parent;
24
+ }
25
+ if (version !== expected) throw new Error(`Hono Pages: ${name} ${version} is unverified; install ${name}@${expected}. The adapter requires void@0.26.1, hono@4.13.13 and vite@8.3.3.`);
26
+ }
27
+ }
@@ -0,0 +1,105 @@
1
+ import { readFileSync, realpathSync } from 'node:fs';
2
+ import { join, relative } from 'node:path';
3
+ import { normalizePath, parseSync, type Plugin } from 'vite';
4
+ import { scanPages, resolvePagesDir, type PageScanResult } from 'void/pages';
5
+ import { findIslandImports, editIslandSource, resolveSpecifier, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';
6
+
7
+ /** Narrow adapter for Void's load-on-page-load island convention. */
8
+ export function honoIslands(): Plugin {
9
+ const root = process.cwd();
10
+ const pagesDir = resolvePagesDir(root);
11
+ const islands = new Map<string, string>();
12
+ const pageFiles = new Set<string>();
13
+ let scan: PageScanResult | undefined;
14
+
15
+ function islandImports(code: string, filename: string) {
16
+ const found = findIslandImports(code, filename);
17
+ const attributed = parseSync(filename, code).program.body.filter((node) => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));
18
+ if (attributed.length !== found.length) throw new Error(`Hono islands: use one default import with exactly one island: 'load' attribute in ${filename}.`);
19
+ return found;
20
+ }
21
+
22
+ function imports(code: string, filename: string) {
23
+ const found = islandImports(code, filename);
24
+ for (const entry of found) {
25
+ if (entry.hydrate !== 'load') throw new Error(`Hono islands: unsupported policy '${entry.hydrate}' in ${filename}; use island: 'load'.`);
26
+ if (!entry.specifier.startsWith('.')) throw new Error(`Hono islands: use a relative TSX/JSX component import in ${filename}.`);
27
+ const path = resolveSpecifier(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);
28
+ if (!path || !/\.[jt]sx$/.test(path)) throw new Error(`Hono islands: cannot resolve TSX/JSX component ${entry.specifier} in ${filename}.`);
29
+ const canonical = realpathSync(path);
30
+ const id = normalizePath(relative(root, canonical));
31
+ islands.set(id, canonical);
32
+ }
33
+ return found;
34
+ }
35
+
36
+ async function rescan() {
37
+ scan = await scanPages(root, { pagesDir });
38
+ islands.clear();
39
+ pageFiles.clear();
40
+ for (const page of scan.pages.filter((page) => page.island)) {
41
+ const filename = realpathSync(join(pagesDir, page.componentPath));
42
+ pageFiles.add(filename);
43
+ imports(readFileSync(filename, 'utf8'), filename);
44
+ }
45
+ }
46
+
47
+ return {
48
+ name: 'void-hono:islands',
49
+ enforce: 'pre',
50
+ buildStart: rescan,
51
+ async hotUpdate({ file }) {
52
+ if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) await rescan();
53
+ },
54
+ config() {
55
+ return { build: { rollupOptions: { input: { 'islands-client': ISLANDS_CLIENT_ENTRY_ID } } } };
56
+ },
57
+ resolveId(id) {
58
+ if (id === ISLANDS_RENDERER_ID || id === ISLANDS_CLIENT_ENTRY_ID) return `\0${id}`;
59
+ },
60
+ transform(code, id) {
61
+ const filename = id.split('?')[0];
62
+ if (!/\.[jt]sx$/.test(filename) || filename.includes('/node_modules/')) return;
63
+ const canonical = realpathSync(filename);
64
+ if ((pageFiles.has(canonical) || [...islands.values()].includes(canonical)) && parseSync(filename, code).program.body.some((node) => node.type === 'ImportDeclaration' && node.source.value === 'void-plugin-hono-jsx/form')) {
65
+ throw new Error('Hono islands: form helpers are unsupported; use a full Pages component.');
66
+ }
67
+ const found = islandImports(code, filename);
68
+ if (!found.length) return;
69
+ if (!pageFiles.has(realpathSync(filename))) throw new Error('Hono islands: attributed imports are supported only directly in .island.tsx/.island.jsx pages.');
70
+ imports(code, filename);
71
+ return editIslandSource(code, found.map((entry) => {
72
+ const path = resolveSpecifier(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);
73
+ if (!path) throw new Error(`Hono islands: missing component ${entry.specifier}.`);
74
+ const islandId = normalizePath(relative(root, realpathSync(path)));
75
+ const component = `__honoIslandComponent${entry.start}`;
76
+ return { start: entry.start, end: entry.end, text: `import ${component} from ${entry.specifierRaw};
77
+ const ${entry.importName} = (props) => __honoIslandJsx('div', { 'data-island': ${JSON.stringify(islandId)}, 'data-hydrate': 'load', 'data-props': JSON.stringify(props), children: __honoIslandJsx(${component}, props) });` };
78
+ }), { prepend: "import { jsx as __honoIslandJsx } from 'hono/jsx/jsx-runtime';\n" });
79
+ },
80
+ load(id) {
81
+ if (id === `\0${ISLANDS_RENDERER_ID}`) {
82
+ if (!scan) throw new Error('Hono islands: page discovery has not completed.');
83
+ const interactive = [...computePagesNeedingClientJS(scan, pagesDir, null)];
84
+ return `import { renderPage } from 'virtual:void-pages-renderer';
85
+ const interactive = new Set(${JSON.stringify(interactive)});
86
+ export function renderIslandPage(page, assets) {
87
+ if (page.deferred?.length || page.deferredKeys) throw new Error('Hono islands: deferred props are unsupported.');
88
+ return renderPage(page, interactive.has(page.component) ? assets : { ...assets, preloads: '', body: '' });
89
+ }`;
90
+ }
91
+ if (id === `\0${ISLANDS_CLIENT_ENTRY_ID}`) {
92
+ if (!islands.size) return 'export {};';
93
+ const loaders = [...islands].map(([name, path]) => `${JSON.stringify(name)}: () => import(${JSON.stringify(path)})`).join(',\n');
94
+ return `import { initIslands } from 'void/pages-client';
95
+ import { jsx } from 'hono/jsx/dom/jsx-runtime';
96
+ import { render } from 'hono/jsx/dom';
97
+ initIslands({ ${loaders} }, (element, module, props) => {
98
+ if (typeof module.default !== 'function') throw new Error('Hono islands: a component must export a default function.');
99
+ render(jsx(module.default, props), element);
100
+ element.setAttribute('data-hono-island', 'mounted');
101
+ });`;
102
+ }
103
+ },
104
+ };
105
+ }
@@ -0,0 +1,20 @@
1
+ import { transformWithOxc, type Plugin } from 'vite';
2
+
3
+ /** JSX factories differ by Vite environment; hooks can be shared via hono/jsx. */
4
+ export function honoJsx(): Plugin {
5
+ return {
6
+ name: 'poc:hono-jsx',
7
+ enforce: 'pre',
8
+ async transform(code, id) {
9
+ const filename = id.split('?')[0];
10
+ if (!/\.[jt]sx$/.test(filename) || filename.includes('/node_modules/')) return;
11
+ return transformWithOxc(code, filename, {
12
+ jsx: {
13
+ runtime: 'automatic',
14
+ importSource: this.environment.config.consumer === 'client' ? 'hono/jsx/dom' : 'hono/jsx',
15
+ development: this.environment.mode === 'dev',
16
+ },
17
+ });
18
+ },
19
+ };
20
+ }
@@ -0,0 +1,142 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import { normalizePath } from 'vite';
3
+ import { pagesRuntimePath, clientRuntimePath, publicRuntimeModules } from './runtime-paths.ts';
4
+ import { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';
5
+ import type { Plugin } from 'vite';
6
+ import { honoJsx } from './hono-jsx.ts';
7
+ import { honoIslands } from './hono-islands.ts';
8
+ import { assertSupportedFrameworks } from './compatibility.ts';
9
+
10
+ const rendererId = 'virtual:void-pages-renderer';
11
+ const clientId = 'virtual:void-pages-client';
12
+
13
+ /** Experimental Pages contract verified against Void 0.26.1. */
14
+ export function voidHonoPages(): Plugin[] {
15
+ const root = process.cwd();
16
+ const pagesDir = resolvePagesDir(root);
17
+ const staticData = resolveStaticPageDataBuildOptions(root);
18
+ let scan: PageScanResult | undefined;
19
+
20
+ async function rescan() {
21
+ scan = await scanPages(root, { pagesDir });
22
+ for (const layout of [...scan.layouts, ...scan.namedLayouts]) {
23
+ if (layout.island || !/\.[jt]sx$/.test(layout.filePath)) throw new Error('Hono Pages: only standard TSX/JSX layouts are supported.');
24
+ }
25
+ for (const page of scan.pages) {
26
+ if (!/\.[jt]sx$/.test(page.componentPath)) {
27
+ throw new Error(`Hono Pages: only standard TSX/JSX pages are supported: ${page.componentPath}.`);
28
+ }
29
+ if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {
30
+ throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);
31
+ }
32
+ }
33
+ return scan;
34
+ }
35
+
36
+ return [honoIslands(), honoJsx(), {
37
+ name: 'void-hono:pages',
38
+ enforce: 'pre',
39
+ config() {
40
+ assertSupportedFrameworks();
41
+ return {
42
+ resolve: { dedupe: ['hono'] },
43
+ build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },
44
+ };
45
+ },
46
+ configEnvironment() {
47
+ const modules = Object.keys(publicRuntimeModules);
48
+ const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];
49
+ return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };
50
+ },
51
+ async buildStart() {
52
+ await rescan();
53
+ },
54
+ configureServer(server) {
55
+ const clear = (file: string) => {
56
+ if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;
57
+ };
58
+ server.watcher.on('add', clear);
59
+ server.watcher.on('unlink', clear);
60
+ server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });
61
+ },
62
+ async hotUpdate({ file, type, modules, timestamp }) {
63
+ if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;
64
+ await rescan();
65
+ if (type !== 'update') return [];
66
+ const invalidated = new Set<(typeof modules)[number]>();
67
+ for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);
68
+ for (const id of [rendererId, clientId]) {
69
+ const module = this.environment.moduleGraph.getModuleById(`\0${id}`);
70
+ if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);
71
+ }
72
+ this.environment.hot.send({ type: 'full-reload' });
73
+ return [];
74
+ },
75
+ resolveId(id) {
76
+ if (id === rendererId || id === clientId) return `\0${id}`;
77
+ if (id === pagesRuntimePath || id === clientRuntimePath) return { id: realpathSync(id), external: false };
78
+ const runtime = publicRuntimeModules[id];
79
+ if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };
80
+ },
81
+ async load(id) {
82
+ if (id !== `\0${rendererId}` && id !== `\0${clientId}`) return;
83
+ const currentScan = scan ?? await rescan();
84
+ const serverSnapshot = id === `\0${rendererId}` && this.environment.mode === 'dev';
85
+ const manifestScan = id === `\0${clientId}`
86
+ ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island) }
87
+ : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;
88
+ let manifest = generateComponentManifest(manifestScan, pagesDir);
89
+ if (serverSnapshot) {
90
+ // A request can retain the old renderer while the worker module runner
91
+ // reloads. Capture components with its providers instead of importing
92
+ // a new generation into an in-flight render. Browser-only pages remain
93
+ // absent from this server graph; production keeps lazy imports.
94
+ const imports: string[] = [];
95
+ manifest = manifest.replace(/\(\) => import\(("(?:[^"\\]|\\.)*")\)/g, (_, path: string) => {
96
+ const name = `__honoPageSnapshot${imports.length}`;
97
+ imports.push(`import * as ${name} from ${path};`);
98
+ return `() => ${name}`;
99
+ });
100
+ manifest = imports.join('\n') + '\n' + manifest;
101
+ }
102
+ if (id === `\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';
103
+ if (id === `\0${rendererId}`) {
104
+ return `
105
+ import { jsx } from 'hono/jsx';
106
+ import { createSsrRouter } from 'void/pages-client';
107
+ import { PageContext, RouterContext } from ${JSON.stringify(pagesRuntimePath)};
108
+ import { serializePageData } from 'void/pages-server';
109
+ import { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';
110
+ ${manifest}
111
+ export async function renderPage(pageObj, assetTags) {
112
+ if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');
113
+ const load = components[pageObj.component];
114
+ if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);
115
+ const { default: Page } = await load();
116
+ if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');
117
+ let content = jsx(Page, pageObj.props);
118
+ const ids = layoutTree[pageObj.component] ?? [];
119
+ const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));
120
+ for (const Layout of layouts.reverse()) {
121
+ if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');
122
+ content = jsx(Layout, { children: content });
123
+ }
124
+ const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: content }) }).toString();
125
+ const head = pageObj.head;
126
+ const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type="module"', '<script async type="module"') : assetTags.body;
127
+ return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'
128
+ + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads
129
+ + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'
130
+ + '<script id="__VOID_PAGE_DATA__" type="application/json">' + serializePageData(pageObj) + '</script>'
131
+ + '<div id="app">' + markup + '</div>' + body + '</body></html>';
132
+ }
133
+ `;
134
+ }
135
+ return `
136
+ import { startHonoPages } from ${JSON.stringify(clientRuntimePath)};
137
+ ${manifest}
138
+ await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} });
139
+ `;
140
+ },
141
+ }];
142
+ }
@@ -0,0 +1,14 @@
1
+ import { fileURLToPath } from 'node:url';
2
+
3
+ // Source fixtures use TSX; npm consumers use the precompiled environment entries.
4
+ // Keep this adaptation in TypeScript so both emitted maps describe the actual code.
5
+ const compiled = new URL(import.meta.url).pathname.endsWith('.js');
6
+ export const pagesRuntimePath = fileURLToPath(new URL(compiled ? '../server/pages.js' : '../runtime/pages.tsx', import.meta.url));
7
+ export const clientRuntimePath = fileURLToPath(new URL(compiled ? '../browser/client.js' : '../runtime/client.tsx', import.meta.url));
8
+ export const publicRuntimeModules: Record<string, { server: string; client: string }> = compiled ? {
9
+ 'void-plugin-hono-jsx/pages': { server: pagesRuntimePath, client: fileURLToPath(new URL('../browser/pages.js', import.meta.url)) },
10
+ 'void-plugin-hono-jsx/form': {
11
+ server: fileURLToPath(new URL('../server/form.js', import.meta.url)),
12
+ client: fileURLToPath(new URL('../browser/form.js', import.meta.url)),
13
+ },
14
+ } : {};
@@ -0,0 +1,83 @@
1
+ import { render } from 'hono/jsx/dom';
2
+ import { jsx } from 'hono/jsx/dom/jsx-runtime';
3
+ import { useLayoutEffect, useState } from 'hono/jsx';
4
+ import { createVoidRouter, type VoidRouterConfig } from 'void/pages-client';
5
+ import { parseCacheFor } from 'void/pages-prefetch';
6
+ import { PageContext, RouterContext } from './pages.tsx';
7
+ import { createDocumentHead } from './document-head.ts';
8
+ import { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';
9
+
10
+ type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
11
+
12
+ function pageComponent(component: unknown) {
13
+ if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');
14
+ return component;
15
+ }
16
+
17
+ export async function startHonoPages(manifest: Manifest) {
18
+ const root = document.getElementById('app');
19
+ if (!root) throw new Error('Hono Pages: app root is missing.');
20
+ type Frame = { page: Awaited<ReturnType<typeof createVoidRouter>>['initialPageData']; component: unknown; layouts: unknown[]; revision: number };
21
+ let update: ((frame: Frame) => void) | undefined;
22
+ let revision = 0;
23
+ let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;
24
+ let renderedProps: Record<string, unknown> | undefined;
25
+ let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;
26
+ const initialization = createVoidRouter({
27
+ ...manifest,
28
+ adapter: {
29
+ createDeferred, resolveDeferred, rejectDeferred, isLoading,
30
+ onDeferredUpdate(props) {
31
+ if (props === renderedProps) updateDeferred?.({ ...props });
32
+ },
33
+ async applyUpdate(page, component, layouts, options) {
34
+ layouts.forEach(pageComponent);
35
+ pageComponent(component);
36
+ if (!update) throw new Error('Hono Pages: page rendering has not started.');
37
+ if (!options.preserveState) revision++;
38
+ renderedProps = page.props;
39
+ update({ page: { ...page, props: { ...page.props } }, component, layouts, revision });
40
+ await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));
41
+ applyDocumentHead?.(page.head);
42
+ },
43
+ },
44
+ viewTransitions: false,
45
+ prefetchHoverDelay: 75,
46
+ prefetchDefaultCacheFor: parseCacheFor('30s'),
47
+ cacheVisitedPageData: false,
48
+ onNavigationChange(state) { root.dataset.navigation = state.state; },
49
+ });
50
+ const releaseBuffer = bufferInitialDeferred();
51
+ const navigation = await initialization.finally(releaseBuffer);
52
+ renderedProps = navigation.initialPageData.props;
53
+ applyDocumentHead = createDocumentHead(navigation.initialPageData.head);
54
+
55
+ function App() {
56
+ const [frame, setFrame] = useState<Frame>({ page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision });
57
+ const [failed, setFailed] = useState(false);
58
+ useLayoutEffect(() => {
59
+ updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));
60
+ update = (next) => { setFailed(false); setFrame(next); };
61
+ const onError = () => setFailed(true);
62
+ window.addEventListener('hono-pages:navigation-error', onError);
63
+ return () => { update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };
64
+ }, []);
65
+ let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));
66
+ const ids = manifest.layoutTree[frame.page.component] ?? [];
67
+ for (let index = frame.layouts.length - 1; index >= 0; index--) {
68
+ content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);
69
+ }
70
+ return <RouterContext.Provider value={navigation.router}>
71
+ <PageContext.Provider value={frame.page}>
72
+ {failed && <p role="alert">The page could not be loaded. Please try again.</p>}
73
+ {content}
74
+ </PageContext.Provider>
75
+ </RouterContext.Provider>;
76
+ }
77
+
78
+ render(<App />, root);
79
+ navigation.start();
80
+ navigation.commitInitialRender();
81
+ root.dataset.navigation = 'idle';
82
+ root.dataset.honoPages = 'mounted';
83
+ }
@@ -0,0 +1,34 @@
1
+ import type { DeferredState } from 'void';
2
+
3
+ export function createDeferred(): DeferredState<never> {
4
+ return { loading: true, value: null, error: null };
5
+ }
6
+ export function resolveDeferred(_ref: unknown, value: unknown): DeferredState<unknown> {
7
+ return { loading: false, value, error: null };
8
+ }
9
+ export function rejectDeferred(_ref: unknown, message: string): DeferredState<never> {
10
+ return { loading: false, value: null, error: new Error(message) };
11
+ }
12
+ export function isLoading(ref: unknown): boolean {
13
+ return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
14
+ }
15
+
16
+ // Void installs its HTML callbacks before awaiting component imports. Keep early
17
+ // messages in its existing queue until the initial deferred registry is ready.
18
+ declare global {
19
+ interface Window {
20
+ __resolveDeferred?: (group: string, data: unknown) => void;
21
+ __rejectDeferred?: (group: string, error: string) => void;
22
+ __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;
23
+ }
24
+ }
25
+ export function bufferInitialDeferred() {
26
+ const resolve = window.__resolveDeferred;
27
+ const reject = window.__rejectDeferred;
28
+ window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);
29
+ window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);
30
+ return () => {
31
+ window.__resolveDeferred = resolve;
32
+ window.__rejectDeferred = reject;
33
+ };
34
+ }
@@ -0,0 +1,44 @@
1
+ import { renderHeadToString } from 'void/pages-head';
2
+ import type { HeadDescriptor } from 'void';
3
+
4
+ function scriptSignature(script: HTMLScriptElement) {
5
+ return JSON.stringify([Array.from(script.attributes, ({ name, value }) => [name, value]).sort(), script.textContent]);
6
+ }
7
+
8
+ function scriptElements(head: HeadDescriptor | undefined) {
9
+ const template = document.createElement('template');
10
+ template.innerHTML = renderHeadToString({ script: head?.script });
11
+ return Array.from(template.content.querySelectorAll('script'));
12
+ }
13
+
14
+ /** Complements Void's title/meta/link updates without executing navigation scripts. */
15
+ export function createDocumentHead(initial: HeadDescriptor | undefined) {
16
+ let htmlKeys = Object.keys(initial?.htmlAttrs ?? {});
17
+ let bodyKeys = Object.keys(initial?.bodyAttrs ?? {});
18
+ let scripts: HTMLScriptElement[] = [];
19
+ const existing = Array.from(document.head.querySelectorAll('script'));
20
+ for (const desired of scriptElements(initial)) {
21
+ const index = existing.findIndex((script) => scriptSignature(script) === scriptSignature(desired));
22
+ if (index >= 0) scripts.push(...existing.splice(index, 1));
23
+ }
24
+
25
+ function attributes(element: HTMLElement, previous: string[], next: Record<string, string> = {}) {
26
+ for (const key of previous) if (!(key in next)) element.removeAttribute(key);
27
+ for (const [key, value] of Object.entries(next)) element.setAttribute(key, value);
28
+ return Object.keys(next);
29
+ }
30
+
31
+ return (head: HeadDescriptor | undefined) => {
32
+ htmlKeys = attributes(document.documentElement, htmlKeys, head?.htmlAttrs);
33
+ bodyKeys = attributes(document.body, bodyKeys, head?.bodyAttrs);
34
+ const remaining = [...scripts];
35
+ scripts = scriptElements(head).map((desired) => {
36
+ const index = remaining.findIndex((script) => scriptSignature(script) === scriptSignature(desired));
37
+ if (index >= 0) return remaining.splice(index, 1)[0];
38
+ // Template-parsed scripts remain inert when inserted. Head changes are metadata, not script execution.
39
+ document.head.appendChild(desired);
40
+ return desired;
41
+ });
42
+ for (const script of remaining) script.remove();
43
+ };
44
+ }
@@ -0,0 +1,71 @@
1
+ import { useContext, useRef, useState } from 'hono/jsx';
2
+ import { isAbortError, submitAction, VoidActionError, type FormMethod } from 'void/pages-client';
3
+ import { RouterContext, useErrors, useRouter } from './pages.tsx';
4
+
5
+ function fieldErrors(error: VoidActionError): Record<string, string> {
6
+ const body = error.body;
7
+ if (typeof body !== 'object' || body === null || !('errors' in body) || typeof body.errors !== 'object' || body.errors === null) return {};
8
+ return Object.fromEntries(Object.entries(body.errors).filter((entry): entry is [string, string] => typeof entry[1] === 'string'));
9
+ }
10
+
11
+ export function useForm<T extends Record<string, unknown>>(initialData: T) {
12
+ if (!useContext(RouterContext)) throw new Error('Hono Pages: useForm requires the full Pages renderer; island form helpers are unsupported.');
13
+ const router = useRouter();
14
+ const initialErrors = useErrors();
15
+ const [data, updateData] = useState(initialData);
16
+ const [errors, setErrors] = useState(initialErrors);
17
+ const [pending, setPending] = useState(false);
18
+ const [wasSuccessful, setSuccessful] = useState(false);
19
+ const [error, setError] = useState<Error | null>(null);
20
+ const active = useRef(false);
21
+ const generation = useRef(0);
22
+
23
+ const setData: typeof updateData = (next) => {
24
+ updateData(next);
25
+ setSuccessful(false);
26
+ setErrors({});
27
+ setError(null);
28
+ };
29
+
30
+ async function submit(method: FormMethod, url: string) {
31
+ if (active.current) return;
32
+ active.current = true;
33
+ const id = ++generation.current;
34
+ setPending(true);
35
+ setSuccessful(false);
36
+ setError(null);
37
+ setErrors({});
38
+ try {
39
+ const result = await submitAction(router, url, { method: method.toUpperCase(), data, preserveScroll: true });
40
+ if (id !== generation.current) return;
41
+ if (result.ok) setSuccessful(true);
42
+ else { setError(result.error); setErrors(fieldErrors(result.error)); }
43
+ } catch (failure) {
44
+ if (id === generation.current && !isAbortError(failure)) {
45
+ setError(failure instanceof Error ? failure : new Error(String(failure)));
46
+ }
47
+ } finally {
48
+ if (id === generation.current) { active.current = false; setPending(false); }
49
+ }
50
+ }
51
+
52
+ function cancel() {
53
+ if (!active.current) return;
54
+ const id = ++generation.current;
55
+ active.current = false;
56
+ setPending(false);
57
+ setSuccessful(false);
58
+ void router.refresh().catch((failure: unknown) => {
59
+ if (id === generation.current) setError(failure instanceof Error ? failure : new Error(String(failure)));
60
+ });
61
+ }
62
+
63
+ return {
64
+ data, setData, errors, pending, wasSuccessful, error, submit, cancel,
65
+ reset() { setData(initialData); },
66
+ post: (url: string) => submit('post', url),
67
+ put: (url: string) => submit('put', url),
68
+ patch: (url: string) => submit('patch', url),
69
+ delete: (url: string) => submit('delete', url),
70
+ };
71
+ }
@@ -0,0 +1,45 @@
1
+ import { createContext, useContext, type JSX } from 'hono/jsx';
2
+ import type { VoidRouter } from 'void/pages-client';
3
+ import type { PageObject } from 'void/pages-protocol';
4
+ export type { DeferredState as Deferred } from 'void';
5
+
6
+ export const RouterContext = createContext<VoidRouter | null>(null);
7
+ export const PageContext = createContext<PageObject | null>(null);
8
+
9
+ function usePage() {
10
+ const page = useContext(PageContext);
11
+ if (!page) throw new Error('Hono Pages: page data requires a page provider.');
12
+ return page;
13
+ }
14
+
15
+ export function useShared() { return usePage().shared; }
16
+ export function useParams() { return usePage().params; }
17
+ export function useErrors() { return usePage().errors ?? {}; }
18
+
19
+ export function useRouter(): VoidRouter {
20
+ const router = useContext(RouterContext);
21
+ if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');
22
+ return router;
23
+ }
24
+
25
+ type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {
26
+ href: string;
27
+ reloadDocument?: boolean;
28
+ replace?: boolean;
29
+ onClick?: (event: MouseEvent) => void;
30
+ };
31
+
32
+ export function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps) {
33
+ const router = useRouter();
34
+ return <a {...attributes} href={href} onClick={(event: MouseEvent) => {
35
+ onClick?.(event);
36
+ if (event.defaultPrevented || reloadDocument || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
37
+ if (attributes.download !== undefined || (attributes.target && attributes.target !== '_self') || attributes.rel?.split(/\s+/).includes('external')) return;
38
+ const url = new URL(href, window.location.href);
39
+ if (url.origin !== window.location.origin || !['http:', 'https:'].includes(url.protocol)) return;
40
+ event.preventDefault();
41
+ void router.visit(url, { replace }).catch((error: unknown) => {
42
+ window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
43
+ });
44
+ }} />;
45
+ }