void-plugin-hono-jsx 0.1.0-alpha.4 → 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +51 -22
- package/dist/browser/form-view.d.ts +4 -3
- package/dist/browser/form-view.d.ts.map +1 -1
- package/dist/browser/form-view.js +6 -4
- package/dist/browser/form-view.js.map +1 -1
- package/dist/browser/form.d.ts +2 -2
- package/dist/browser/form.d.ts.map +1 -1
- package/dist/browser/form.js +13 -5
- package/dist/browser/form.js.map +1 -1
- package/dist/browser/navigation.d.ts.map +1 -1
- package/dist/browser/navigation.js +82 -21
- package/dist/browser/navigation.js.map +1 -1
- package/dist/plugins/compatibility.d.ts +2 -0
- package/dist/plugins/compatibility.d.ts.map +1 -1
- package/dist/plugins/compatibility.js +13 -4
- package/dist/plugins/compatibility.js.map +1 -1
- package/dist/plugins/hono-islands.d.ts.map +1 -1
- package/dist/plugins/hono-islands.js +78 -31
- package/dist/plugins/hono-islands.js.map +1 -1
- package/dist/plugins/hono-jsx.d.ts +11 -3
- package/dist/plugins/hono-jsx.d.ts.map +1 -1
- package/dist/plugins/hono-jsx.js +183 -18
- package/dist/plugins/hono-jsx.js.map +1 -1
- package/dist/plugins/hono-markdown.d.ts.map +1 -1
- package/dist/plugins/hono-markdown.js +25 -14
- package/dist/plugins/hono-markdown.js.map +1 -1
- package/dist/plugins/jsx-transform.d.ts +4 -0
- package/dist/plugins/jsx-transform.d.ts.map +1 -0
- package/dist/plugins/jsx-transform.js +21 -0
- package/dist/plugins/jsx-transform.js.map +1 -0
- package/dist/plugins/markdown-api.d.ts +2 -1
- package/dist/plugins/markdown-api.d.ts.map +1 -1
- package/dist/plugins/markdown-api.js.map +1 -1
- package/dist/server/form-view.d.ts +4 -3
- package/dist/server/form-view.d.ts.map +1 -1
- package/dist/server/form-view.js +6 -4
- package/dist/server/form-view.js.map +1 -1
- package/dist/server/form.d.ts +2 -2
- package/dist/server/form.d.ts.map +1 -1
- package/dist/server/form.js +13 -5
- package/dist/server/form.js.map +1 -1
- package/package.json +6 -6
- package/src/plugins/compatibility.ts +11 -4
- package/src/plugins/hono-islands.ts +59 -27
- package/src/plugins/hono-jsx.ts +176 -17
- package/src/plugins/hono-markdown.ts +20 -10
- package/src/plugins/jsx-transform.ts +20 -0
- package/src/plugins/markdown-api.ts +2 -1
- package/src/runtime/form-view.tsx +9 -5
- package/src/runtime/form.ts +13 -8
- package/src/runtime/navigation.ts +64 -21
- package/dist/plugins/hono-pages.d.ts +0 -12
- package/dist/plugins/hono-pages.d.ts.map +0 -1
- package/dist/plugins/hono-pages.js +0 -186
- package/dist/plugins/hono-pages.js.map +0 -1
- package/src/plugins/hono-pages.ts +0 -179
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError } from 'void/pages-client';
|
|
1
|
+
import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, VoidActionError } from 'void/pages-client';
|
|
2
2
|
/** DOM updates still complete when a native animation is skipped or replaced. */
|
|
3
3
|
export async function applyWithTransition(enabled, update) {
|
|
4
4
|
if (!enabled || !document.startViewTransition)
|
|
5
5
|
return update();
|
|
6
6
|
const transition = document.startViewTransition(update);
|
|
7
|
-
//
|
|
8
|
-
// propagates rendering failures. Never patch the browser's native method.
|
|
7
|
+
// Rendering failures propagate through updateCallbackDone; animation skips do not.
|
|
9
8
|
void transition.ready.catch(() => { });
|
|
10
9
|
void transition.finished?.catch(() => { });
|
|
11
10
|
await transition.updateCallbackDone;
|
|
@@ -24,40 +23,96 @@ export async function createHonoRouter(config) {
|
|
|
24
23
|
let routeUrl = currentUrl();
|
|
25
24
|
let routeParams = engine.initialPageData.params ?? {};
|
|
26
25
|
let active = null;
|
|
26
|
+
let resource;
|
|
27
|
+
let multipartController;
|
|
28
|
+
let multipartId = 0;
|
|
27
29
|
const setRoute = (url, params = routeParams) => { routeUrl = url; routeParams = params; config.onRouteChange?.(url); };
|
|
28
|
-
const assertCurrent = (
|
|
29
|
-
if (active !==
|
|
30
|
+
const assertCurrent = (id) => {
|
|
31
|
+
if (active !== id)
|
|
30
32
|
throw new DOMException('Hono Pages: stale navigation callback discarded.', 'AbortError');
|
|
31
33
|
};
|
|
32
|
-
async function apply(
|
|
33
|
-
|
|
34
|
+
async function apply(next, navigationMethod = next.method) {
|
|
35
|
+
resource = next;
|
|
36
|
+
active = next.id;
|
|
34
37
|
const previousParams = routeParams;
|
|
35
|
-
config.onNavigationChange?.({ state:
|
|
38
|
+
config.onNavigationChange?.({ state: navigationMethod === 'GET' ? 'loading' : 'submitting', location: toUrl(next.fetchUrl + next.hash), method: navigationMethod.toUpperCase() });
|
|
36
39
|
try {
|
|
37
|
-
const result = await
|
|
40
|
+
const result = await next.shell;
|
|
38
41
|
if (!result)
|
|
39
42
|
return;
|
|
40
|
-
assertCurrent(
|
|
41
|
-
setRoute(result.pageData.url ||
|
|
42
|
-
await applyWithTransition(
|
|
43
|
-
assertCurrent(
|
|
44
|
-
await config.adapter.applyUpdate(result.pageData, result.component, result.layouts, { preserveState:
|
|
43
|
+
assertCurrent(next.id);
|
|
44
|
+
setRoute(result.pageData.url || next.fetchUrl + next.hash, result.pageData.params ?? {});
|
|
45
|
+
await applyWithTransition(next.options.viewTransition ?? config.viewTransitions, async () => {
|
|
46
|
+
assertCurrent(next.id);
|
|
47
|
+
await config.adapter.applyUpdate(result.pageData, result.component, result.layouts, { preserveState: next.options.preserveState ?? next.method !== 'GET' });
|
|
45
48
|
});
|
|
46
|
-
assertCurrent(
|
|
47
|
-
await
|
|
48
|
-
if (active ===
|
|
49
|
+
assertCurrent(next.id);
|
|
50
|
+
await next.commit();
|
|
51
|
+
if (active === next.id)
|
|
49
52
|
setRoute(currentUrl(), result.pageData.params ?? {});
|
|
50
53
|
return result.pageData;
|
|
51
54
|
}
|
|
52
55
|
catch (error) {
|
|
53
|
-
if (active ===
|
|
56
|
+
if (active === next.id)
|
|
54
57
|
routeParams = previousParams;
|
|
55
|
-
if (
|
|
58
|
+
if (navigationMethod === 'GET' && !next.options._resolveOnShell && isAbortError(error))
|
|
56
59
|
return;
|
|
57
60
|
throw error;
|
|
58
61
|
}
|
|
59
62
|
finally {
|
|
60
|
-
if (
|
|
63
|
+
if (resource === next)
|
|
64
|
+
resource = undefined;
|
|
65
|
+
if (active === next.id) {
|
|
66
|
+
active = null;
|
|
67
|
+
setRoute(currentUrl());
|
|
68
|
+
config.onNavigationChange?.(idleNavigationState());
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function visitMultipart(url, options) {
|
|
73
|
+
const method = (options.method ?? 'GET').toUpperCase();
|
|
74
|
+
if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(method))
|
|
75
|
+
throw new Error('Hono Pages: FormData requires POST, PUT, PATCH or DELETE.');
|
|
76
|
+
const target = toUrl(url);
|
|
77
|
+
if (target.origin !== window.location.origin || !['http:', 'https:'].includes(target.protocol))
|
|
78
|
+
throw new Error('Hono Pages: FormData actions must target the current origin.');
|
|
79
|
+
// Negative IDs cannot collide with the shared engine's positive generation IDs.
|
|
80
|
+
const id = --multipartId;
|
|
81
|
+
active = id;
|
|
82
|
+
resource?.abort();
|
|
83
|
+
multipartController?.abort();
|
|
84
|
+
const controller = multipartController = new AbortController();
|
|
85
|
+
engine.flushAll();
|
|
86
|
+
config.onNavigationChange?.({ state: 'submitting', location: target, method: method });
|
|
87
|
+
try {
|
|
88
|
+
const response = await fetch(target, { method, body: options.data, headers: { 'X-VoidPages': 'true', Accept: 'application/json' }, signal: controller.signal });
|
|
89
|
+
let body;
|
|
90
|
+
if (response.headers.get('content-type')?.includes('application/json'))
|
|
91
|
+
body = await response.json();
|
|
92
|
+
else if (!response.ok)
|
|
93
|
+
body = await response.text();
|
|
94
|
+
else
|
|
95
|
+
await response.body?.cancel();
|
|
96
|
+
assertCurrent(id);
|
|
97
|
+
if (!response.ok)
|
|
98
|
+
throw new VoidActionError({ body, status: response.status, statusText: response.statusText, url });
|
|
99
|
+
if (typeof body === 'object' && body !== null && 'errors' in body && body.errors && Object.keys(body.errors).length) {
|
|
100
|
+
throw new VoidActionError({ body: { errors: body.errors }, status: 422, statusText: 'Unprocessable Content', url });
|
|
101
|
+
}
|
|
102
|
+
if (!response.headers.get('X-VoidPages')) {
|
|
103
|
+
window.location.assign(response.url || target.href);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const destination = response.redirected ? response.url : typeof body === 'object' && body !== null && 'url' in body && typeof body.url === 'string' ? body.url : target.href;
|
|
107
|
+
multipartController = undefined;
|
|
108
|
+
// The public engine cannot consume raw FormData or an externally fetched shell.
|
|
109
|
+
// Refresh through its GET protocol, retaining component state and mutation UI.
|
|
110
|
+
return await apply(engine.prepareVisit(normalize(destination), { ...options, method: 'GET', data: undefined, preserveState: options.preserveState ?? true, preserveScroll: options.preserveScroll ?? true }), method);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
if (multipartController === controller)
|
|
114
|
+
multipartController = undefined;
|
|
115
|
+
if (active === id) {
|
|
61
116
|
active = null;
|
|
62
117
|
setRoute(currentUrl());
|
|
63
118
|
config.onNavigationChange?.(idleNavigationState());
|
|
@@ -70,7 +125,13 @@ export async function createHonoRouter(config) {
|
|
|
70
125
|
get path() { return this.url.pathname; },
|
|
71
126
|
get query() { return this.url.searchParams; },
|
|
72
127
|
get params() { return routeParams; },
|
|
73
|
-
visit(url, options = {}) {
|
|
128
|
+
visit(url, options = {}) {
|
|
129
|
+
if (options.data instanceof FormData)
|
|
130
|
+
return visitMultipart(normalize(url), options);
|
|
131
|
+
multipartController?.abort();
|
|
132
|
+
multipartController = undefined;
|
|
133
|
+
return apply(engine.prepareVisit(normalize(url), options));
|
|
134
|
+
},
|
|
74
135
|
refresh(options = {}) { return raw.visit(window.location.pathname + window.location.search, { preserveState: true, preserveScroll: true, ...options }); },
|
|
75
136
|
prefetch(url, options = {}) { return engine.prefetch(normalize(url), options); },
|
|
76
137
|
flush(url, method = 'GET') { engine.flush(normalize(url), method); },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/runtime/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, type PageNavigationResource, type VoidRouter, type VoidRouterConfig, type NavigationMethod } from 'void/pages-client';\n\n/** DOM updates still complete when a native animation is skipped or replaced. */\nexport async function applyWithTransition(enabled: boolean, update: () => Promise<void>) {\n if (!enabled || !document.startViewTransition) return update();\n const transition = document.startViewTransition(update);\n // ready rejects for expected animation skips; updateCallbackDone separately\n // propagates rendering failures. Never patch the browser's native method.\n void transition.ready.catch(() => {});\n void transition.finished?.catch(() => {});\n await transition.updateCallbackDone;\n}\n\n/** Hono render integration over Void's public navigation engine and facade. */\nexport async function createHonoRouter(config: VoidRouterConfig) {\n const engine = await createPageNavigationEngine(config);\n const currentUrl = () => window.location.pathname + window.location.search + window.location.hash;\n const toUrl = (value: string | URL) => new URL(value, window.location.href);\n const normalize = (value: string | URL) => {\n const url = toUrl(value);\n // Preserve foreign origins and schemes for the shared engine's guards.\n return url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol)\n ? url.pathname + url.search + url.hash : url.href;\n };\n let routeUrl = currentUrl();\n let routeParams = engine.initialPageData.params ?? {};\n let active: number | null = null;\n const setRoute = (url: string, params = routeParams) => { routeUrl = url; routeParams = params; config.onRouteChange?.(url); };\n const assertCurrent = (resource: PageNavigationResource) => {\n if (active !== resource.id) throw new DOMException('Hono Pages: stale navigation callback discarded.', 'AbortError');\n };\n async function apply(resource: PageNavigationResource) {\n active = resource.id;\n const previousParams = routeParams;\n config.onNavigationChange?.({ state: resource.method === 'GET' ? 'loading' : 'submitting', location: toUrl(resource.fetchUrl + resource.hash), method: resource.method.toUpperCase() as NavigationMethod });\n try {\n const result = await resource.shell;\n if (!result) return;\n assertCurrent(resource);\n setRoute(result.pageData.url || resource.fetchUrl + resource.hash, result.pageData.params ?? {});\n await applyWithTransition(resource.options.viewTransition ?? config.viewTransitions, async () => {\n assertCurrent(resource);\n await config.adapter.applyUpdate(result.pageData, result.component, result.layouts, { preserveState: resource.options.preserveState ?? resource.method !== 'GET' });\n });\n assertCurrent(resource);\n await resource.commit();\n if (active === resource.id) setRoute(currentUrl(), result.pageData.params ?? {});\n return result.pageData;\n } catch (error) {\n if (active === resource.id) routeParams = previousParams;\n if (resource.method === 'GET' && !resource.options._resolveOnShell && isAbortError(error)) return;\n throw error;\n } finally {\n if (active === resource.id) { active = null; setRoute(currentUrl()); config.onNavigationChange?.(idleNavigationState()); }\n }\n }\n const raw: VoidRouter = {\n _hoverDelay: engine._hoverDelay,\n get url() { return toUrl(routeUrl); },\n get path() { return this.url.pathname; },\n get query() { return this.url.searchParams; },\n get params() { return routeParams; },\n visit(url, options = {}) { return apply(engine.prepareVisit(normalize(url), options)); },\n refresh(options = {}) { return raw.visit(window.location.pathname + window.location.search, { preserveState: true, preserveScroll: true, ...options }); },\n prefetch(url, options = {}) { return engine.prefetch(normalize(url), options); },\n flush(url, method = 'GET') { engine.flush(normalize(url), method); },\n flushAll() { engine.flushAll(); },\n };\n const router = createRouterFacade(raw, () => routeUrl, () => routeParams);\n engine.setPopStateHandler((url, options) => { void router.visit(url, options).catch(error => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }))); });\n return { router, initialPageData: engine.initialPageData, initialComponent: engine.initialComponent, initialLayouts: engine.initialLayouts, start: engine.start, commitInitialRender: engine.commitInitialRender };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/runtime/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, VoidActionError, type VisitOptions, type PageNavigationResource, type VoidRouter, type VoidRouterConfig, type NavigationMethod } from 'void/pages-client';\n\n/** DOM updates still complete when a native animation is skipped or replaced. */\nexport async function applyWithTransition(enabled: boolean, update: () => Promise<void>) {\n if (!enabled || !document.startViewTransition) return update();\n const transition = document.startViewTransition(update);\n // Rendering failures propagate through updateCallbackDone; animation skips do not.\n void transition.ready.catch(() => {});\n void transition.finished?.catch(() => {});\n await transition.updateCallbackDone;\n}\n\n/** Hono render integration over Void's public navigation engine and facade. */\nexport async function createHonoRouter(config: VoidRouterConfig) {\n const engine = await createPageNavigationEngine(config);\n const currentUrl = () => window.location.pathname + window.location.search + window.location.hash;\n const toUrl = (value: string | URL) => new URL(value, window.location.href);\n const normalize = (value: string | URL) => {\n const url = toUrl(value);\n // Preserve foreign origins and schemes for the shared engine's guards.\n return url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol)\n ? url.pathname + url.search + url.hash : url.href;\n };\n let routeUrl = currentUrl();\n let routeParams = engine.initialPageData.params ?? {};\n let active: number | null = null;\n let resource: PageNavigationResource | undefined;\n let multipartController: AbortController | undefined;\n let multipartId = 0;\n const setRoute = (url: string, params = routeParams) => { routeUrl = url; routeParams = params; config.onRouteChange?.(url); };\n const assertCurrent = (id: number) => {\n if (active !== id) throw new DOMException('Hono Pages: stale navigation callback discarded.', 'AbortError');\n };\n async function apply(next: PageNavigationResource, navigationMethod = next.method) {\n resource = next; active = next.id;\n const previousParams = routeParams;\n config.onNavigationChange?.({ state: navigationMethod === 'GET' ? 'loading' : 'submitting', location: toUrl(next.fetchUrl + next.hash), method: navigationMethod.toUpperCase() as NavigationMethod });\n try {\n const result = await next.shell;\n if (!result) return;\n assertCurrent(next.id);\n setRoute(result.pageData.url || next.fetchUrl + next.hash, result.pageData.params ?? {});\n await applyWithTransition(next.options.viewTransition ?? config.viewTransitions, async () => {\n assertCurrent(next.id);\n await config.adapter.applyUpdate(result.pageData, result.component, result.layouts, { preserveState: next.options.preserveState ?? next.method !== 'GET' });\n });\n assertCurrent(next.id);\n await next.commit();\n if (active === next.id) setRoute(currentUrl(), result.pageData.params ?? {});\n return result.pageData;\n } catch (error) {\n if (active === next.id) routeParams = previousParams;\n if (navigationMethod === 'GET' && !next.options._resolveOnShell && isAbortError(error)) return;\n throw error;\n } finally {\n if (resource === next) resource = undefined;\n if (active === next.id) { active = null; setRoute(currentUrl()); config.onNavigationChange?.(idleNavigationState()); }\n }\n }\n\n async function visitMultipart(url: string, options: VisitOptions) {\n const method = (options.method ?? 'GET').toUpperCase();\n if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new Error('Hono Pages: FormData requires POST, PUT, PATCH or DELETE.');\n const target = toUrl(url);\n if (target.origin !== window.location.origin || !['http:', 'https:'].includes(target.protocol)) throw new Error('Hono Pages: FormData actions must target the current origin.');\n // Negative IDs cannot collide with the shared engine's positive generation IDs.\n const id = --multipartId;\n active = id;\n resource?.abort(); multipartController?.abort();\n const controller = multipartController = new AbortController();\n engine.flushAll();\n config.onNavigationChange?.({ state: 'submitting', location: target, method: method as NavigationMethod });\n try {\n const response = await fetch(target, { method, body: options.data as FormData, headers: { 'X-VoidPages': 'true', Accept: 'application/json' }, signal: controller.signal });\n let body: unknown;\n if (response.headers.get('content-type')?.includes('application/json')) body = await response.json();\n else if (!response.ok) body = await response.text();\n else await response.body?.cancel();\n assertCurrent(id);\n if (!response.ok) throw new VoidActionError({ body, status: response.status, statusText: response.statusText, url });\n if (typeof body === 'object' && body !== null && 'errors' in body && body.errors && Object.keys(body.errors).length) {\n throw new VoidActionError({ body: { errors: body.errors }, status: 422, statusText: 'Unprocessable Content', url });\n }\n if (!response.headers.get('X-VoidPages')) { window.location.assign(response.url || target.href); return; }\n const destination = response.redirected ? response.url : typeof body === 'object' && body !== null && 'url' in body && typeof body.url === 'string' ? body.url : target.href;\n multipartController = undefined;\n // The public engine cannot consume raw FormData or an externally fetched shell.\n // Refresh through its GET protocol, retaining component state and mutation UI.\n return await apply(engine.prepareVisit(normalize(destination), { ...options, method: 'GET', data: undefined, preserveState: options.preserveState ?? true, preserveScroll: options.preserveScroll ?? true }), method);\n } finally {\n if (multipartController === controller) multipartController = undefined;\n if (active === id) { active = null; setRoute(currentUrl()); config.onNavigationChange?.(idleNavigationState()); }\n }\n }\n\n const raw: VoidRouter = {\n _hoverDelay: engine._hoverDelay,\n get url() { return toUrl(routeUrl); },\n get path() { return this.url.pathname; },\n get query() { return this.url.searchParams; },\n get params() { return routeParams; },\n visit(url, options = {}) {\n if (options.data instanceof FormData) return visitMultipart(normalize(url), options);\n multipartController?.abort(); multipartController = undefined;\n return apply(engine.prepareVisit(normalize(url), options));\n },\n refresh(options = {}) { return raw.visit(window.location.pathname + window.location.search, { preserveState: true, preserveScroll: true, ...options }); },\n prefetch(url, options = {}) { return engine.prefetch(normalize(url), options); },\n flush(url, method = 'GET') { engine.flush(normalize(url), method); },\n flushAll() { engine.flushAll(); },\n };\n const router = createRouterFacade(raw, () => routeUrl, () => routeParams);\n engine.setPopStateHandler((url, options) => { void router.visit(url, options).catch(error => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }))); });\n return { router, initialPageData: engine.initialPageData, initialComponent: engine.initialComponent, initialLayouts: engine.initialLayouts, start: engine.start, commitInitialRender: engine.commitInitialRender };\n}\n"]}
|
|
@@ -4,6 +4,8 @@ export declare const supportedFrameworkRanges: {
|
|
|
4
4
|
vite: string;
|
|
5
5
|
};
|
|
6
6
|
export declare const supportedViteRange: string;
|
|
7
|
+
export declare const supportedNodeRange = ">=24.21.0 <25.0.0";
|
|
8
|
+
export declare function supportsNode(version: unknown): boolean;
|
|
7
9
|
export declare function supportsFramework(name: keyof typeof supportedFrameworkRanges, version: unknown): boolean;
|
|
8
10
|
export declare const supportsVite: (version: unknown) => boolean;
|
|
9
11
|
export declare function assertSupportedFrameworks({ root, viteVersion }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/plugins/compatibility.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,wBAAwB;IACnC,IAAI;IACJ,IAAI;IACJ,IAAI;CACL,CAAC;AACF,eAAO,MAAM,kBAAkB,QAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/plugins/compatibility.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,wBAAwB;IACnC,IAAI;IACJ,IAAI;IACJ,IAAI;CACL,CAAC;AACF,eAAO,MAAM,kBAAkB,QAAgC,CAAC;AAChE,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AACtD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAItD;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,OAAO,wBAAwB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CASxG;AACD,eAAO,MAAM,YAAY,YAAa,OAAO,KAAG,OAA6C,CAAC;AAwB9F,wBAAgB,yBAAyB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,QAgBtG"}
|
|
@@ -3,13 +3,20 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { version as helperViteVersion } from 'vite';
|
|
5
5
|
export const supportedFrameworkRanges = {
|
|
6
|
-
void: '>=
|
|
6
|
+
void: '>=1.1.11 <1.2.0',
|
|
7
7
|
hono: '>=4.13.13 <5.0.0',
|
|
8
8
|
vite: '>=8.0.16 <9.0.0',
|
|
9
9
|
};
|
|
10
10
|
export const supportedViteRange = supportedFrameworkRanges.vite;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
export const supportedNodeRange = '>=24.21.0 <25.0.0';
|
|
12
|
+
export function supportsNode(version) {
|
|
13
|
+
if (typeof version !== 'string')
|
|
14
|
+
return false;
|
|
15
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(version);
|
|
16
|
+
return !!match && match[1] === '24' && Number.isSafeInteger(Number(match[2])) && Number.isSafeInteger(Number(match[3])) && Number(match[2]) >= 21;
|
|
17
|
+
}
|
|
18
|
+
// Only stable releases are admitted. Void minors are validated explicitly
|
|
19
|
+
// because the adapter also uses its virtual-module integration contracts.
|
|
13
20
|
export function supportsFramework(name, version) {
|
|
14
21
|
if (typeof version !== 'string')
|
|
15
22
|
return false;
|
|
@@ -20,7 +27,7 @@ export function supportsFramework(name, version) {
|
|
|
20
27
|
if (![major, minor, patch].every(Number.isSafeInteger))
|
|
21
28
|
return false;
|
|
22
29
|
if (name === 'void')
|
|
23
|
-
return major ===
|
|
30
|
+
return major === 1 && minor === 1 && patch >= 11;
|
|
24
31
|
if (name === 'hono')
|
|
25
32
|
return major === 4 && (minor > 13 || (minor === 13 && patch >= 13));
|
|
26
33
|
return major === 8 && (minor > 0 || patch >= 16);
|
|
@@ -54,6 +61,8 @@ function describe(name, require) {
|
|
|
54
61
|
}
|
|
55
62
|
}
|
|
56
63
|
export function assertSupportedFrameworks({ root, viteVersion }) {
|
|
64
|
+
if (!supportsNode(process.versions.node))
|
|
65
|
+
throw new Error(`Hono Pages: Node ${process.versions.node} is unsupported; expected ${supportedNodeRange}. Use Node 24 LTS from your project root.`);
|
|
57
66
|
const adapter = createRequire(import.meta.url);
|
|
58
67
|
const project = createRequire(join(root, 'package.json'));
|
|
59
68
|
const diagnostic = () => `Running Vite from hook context: ${typeof viteVersion === 'string' ? viteVersion : 'unavailable'}. Adapter helper Vite: ${helperViteVersion}; package.json: ${describe('vite', adapter)}. Project Vite package.json: ${describe('vite', project)}. Package paths are diagnostics, not the running Vite identity.`;
|
|
@@ -1 +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;AAC1C,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEpD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../../src/plugins/compatibility.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRequire } from 'node:module';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { version as helperViteVersion } from 'vite';\n\nexport const supportedFrameworkRanges = {\n void: '>=1.1.11 <1.2.0',\n hono: '>=4.13.13 <5.0.0',\n vite: '>=8.0.16 <9.0.0',\n};\nexport const supportedViteRange = supportedFrameworkRanges.vite;\nexport const supportedNodeRange = '>=24.21.0 <25.0.0';\nexport function supportsNode(version: unknown): boolean {\n if (typeof version !== 'string') return false;\n const match = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/.exec(version);\n return !!match && match[1] === '24' && Number.isSafeInteger(Number(match[2])) && Number.isSafeInteger(Number(match[3])) && Number(match[2]) >= 21;\n}\n\n// Only stable releases are admitted. Void minors are validated explicitly\n// because the adapter also uses its virtual-module integration contracts.\nexport function supportsFramework(name: keyof typeof supportedFrameworkRanges, version: unknown): boolean {\n if (typeof version !== 'string') return false;\n const match = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/.exec(version);\n if (!match) return false;\n const [major, minor, patch] = match.slice(1).map(Number);\n if (![major, minor, patch].every(Number.isSafeInteger)) return false;\n if (name === 'void') return major === 1 && minor === 1 && patch >= 11;\n if (name === 'hono') return major === 4 && (minor > 13 || (minor === 13 && patch >= 13));\n return major === 8 && (minor > 0 || patch >= 16);\n}\nexport const supportsVite = (version: unknown): boolean => supportsFramework('vite', version);\n\ntype PackageInfo = { version: string; path: string };\nfunction packageInfo(name: string, require: NodeRequire): PackageInfo {\n let directory = dirname(require.resolve(name));\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 || (name === 'vite' && metadata.name === '@voidzero-dev/vite-plus-core'))) {\n if (!('version' in metadata) || typeof metadata.version !== 'string') throw new Error(`Hono Pages: ${name} package version is missing (${path}).`);\n return { version: metadata.version, path };\n }\n }\n const parent = dirname(directory);\n if (parent === directory) throw new Error(`Hono Pages: cannot locate ${name} package metadata from ${require.resolve(name)}.`);\n directory = parent;\n }\n}\nfunction describe(name: string, require: NodeRequire): string {\n try { const info = packageInfo(name, require); return `${info.path} (metadata ${info.version})`; }\n catch { return `not resolved from ${require.resolve.paths(name)?.join(', ') ?? 'this context'}`; }\n}\n\nexport function assertSupportedFrameworks({ root, viteVersion }: { root: string; viteVersion: unknown }) {\n if (!supportsNode(process.versions.node)) throw new Error(`Hono Pages: Node ${process.versions.node} is unsupported; expected ${supportedNodeRange}. Use Node 24 LTS from your project root.`);\n const adapter = createRequire(import.meta.url);\n const project = createRequire(join(root, 'package.json'));\n const diagnostic = () => `Running Vite from hook context: ${typeof viteVersion === 'string' ? viteVersion : 'unavailable'}. Adapter helper Vite: ${helperViteVersion}; package.json: ${describe('vite', adapter)}. Project Vite package.json: ${describe('vite', project)}. Package paths are diagnostics, not the running Vite identity.`;\n if (!supportsVite(viteVersion)) {\n throw new Error(`Hono Pages: running Vite ${typeof viteVersion === 'string' ? viteVersion : 'unavailable'} is unsupported; expected ${supportedViteRange}. ${diagnostic()} Update the CLI/launcher that executes Vite. For bundled launchers such as vp, installing project vite alone does not update the running Vite. For standard Vite, install vite@^8.3.4 and run vite directly.`);\n }\n if (!supportsVite(helperViteVersion)) {\n throw new Error(`Hono Pages: adapter helper Vite ${helperViteVersion} is unsupported; expected ${supportedViteRange}. ${diagnostic()} Inspect the adapter's resolved peer copy; install vite@^8.3.4 and refresh the adapter's peer resolution/lockfile if a stale copy remains.`);\n }\n for (const name of ['void', 'hono'] as const) {\n const expected = supportedFrameworkRanges[name];\n const info = packageInfo(name, adapter);\n if (!supportsFramework(name, info.version)) throw new Error(`Hono Pages: ${name} ${info.version} is unsupported; install ${name}@\"${expected}\". Resolved package.json: ${info.path}. Project package.json: ${describe(name, project)}. ${diagnostic()}`);\n }\n}\n"]}
|
|
@@ -1 +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;AAQ7D,4DAA4D;AAC5D,wBAAgB,WAAW,IAAI,MAAM,CA+
|
|
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;AAQ7D,4DAA4D;AAC5D,wBAAgB,WAAW,IAAI,MAAM,CA+NpC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync, realpathSync } from 'node:fs';
|
|
2
|
-
import { join, relative } from 'node:path';
|
|
2
|
+
import { join, relative, resolve, dirname, basename } from 'node:path';
|
|
3
3
|
import { normalizePath, parseSync } from 'vite';
|
|
4
4
|
import { scanPages, resolveEffectiveLayoutChain, resolvePagesDir } from 'void/pages';
|
|
5
5
|
import { findIslandImports, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';
|
|
@@ -11,21 +11,21 @@ export function honoIslands() {
|
|
|
11
11
|
const pagesDir = resolvePagesDir(root);
|
|
12
12
|
const islands = new Map();
|
|
13
13
|
const pageFiles = new Set();
|
|
14
|
+
let dependencyFiles = new Set();
|
|
14
15
|
const graph = new Map();
|
|
15
16
|
const directlyInteractive = new Set();
|
|
16
17
|
const interactivePages = new Set();
|
|
17
18
|
const scriptOnlyPages = new Set();
|
|
18
19
|
let scan;
|
|
19
20
|
let markdown;
|
|
20
|
-
function islandImports(code, filename) {
|
|
21
|
+
function islandImports(code, filename, body = parseSync(filename, code).program.body) {
|
|
21
22
|
const found = findIslandImports(code, filename);
|
|
22
|
-
const attributed =
|
|
23
|
+
const attributed = body.filter((node) => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));
|
|
23
24
|
if (attributed.length !== found.length)
|
|
24
25
|
throw new Error(`Hono islands: use one default import with exactly one island attribute using load, visible, idle or media:query in ${filename}.`);
|
|
25
26
|
return found;
|
|
26
27
|
}
|
|
27
|
-
function imports(code, filename) {
|
|
28
|
-
const found = islandImports(code, filename);
|
|
28
|
+
function imports(code, filename, found = islandImports(code, filename)) {
|
|
29
29
|
for (const entry of found) {
|
|
30
30
|
if (!['load', 'visible', 'idle'].includes(entry.hydrate)) {
|
|
31
31
|
const query = entry.hydrate.startsWith('media:') ? entry.hydrate.slice(6).trim() : '';
|
|
@@ -52,7 +52,9 @@ export function honoIslands() {
|
|
|
52
52
|
}
|
|
53
53
|
return found;
|
|
54
54
|
}
|
|
55
|
+
// Refresh before graph analysis, regardless of Markdown hot-hook order.
|
|
55
56
|
async function rescan() {
|
|
57
|
+
markdown?.refresh();
|
|
56
58
|
scan = await scanPages(root, { pagesDir });
|
|
57
59
|
// Never pass Markdown text to the JavaScript static-graph parser.
|
|
58
60
|
for (const file of [...scan.pages.map(page => page.componentPath), ...scan.layouts.map(layout => layout.filePath), ...scan.namedLayouts.map(layout => layout.filePath)]) {
|
|
@@ -65,6 +67,61 @@ export function honoIslands() {
|
|
|
65
67
|
directlyInteractive.clear();
|
|
66
68
|
interactivePages.clear();
|
|
67
69
|
scriptOnlyPages.clear();
|
|
70
|
+
const analyses = new Map();
|
|
71
|
+
const watched = new Set();
|
|
72
|
+
const watchedBases = new Set();
|
|
73
|
+
const watch = (file) => { const path = normalizePath(file); watched.add(path); dependencyFiles.add(path); };
|
|
74
|
+
const watchImport = (specifier, filename) => {
|
|
75
|
+
const base = resolve(dirname(filename), specifier);
|
|
76
|
+
if (watchedBases.has(base))
|
|
77
|
+
return;
|
|
78
|
+
watchedBases.add(base);
|
|
79
|
+
const bases = new Set([base]);
|
|
80
|
+
// Keep missing targets observable through symlinked directories too.
|
|
81
|
+
try {
|
|
82
|
+
bases.add(join(realpathSync(dirname(base)), basename(base)));
|
|
83
|
+
}
|
|
84
|
+
catch { }
|
|
85
|
+
try {
|
|
86
|
+
bases.add(realpathSync(base));
|
|
87
|
+
}
|
|
88
|
+
catch { }
|
|
89
|
+
for (const candidate of bases) {
|
|
90
|
+
watch(candidate);
|
|
91
|
+
for (const extension of ['.tsx', '.jsx', '.ts', '.js']) {
|
|
92
|
+
watch(candidate + extension);
|
|
93
|
+
watch(join(candidate, 'index' + extension));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const analyze = (canonical) => {
|
|
98
|
+
const previous = analyses.get(canonical);
|
|
99
|
+
if (previous)
|
|
100
|
+
return previous;
|
|
101
|
+
// Retain failed dependencies until recovery so an edit can trigger a rescan.
|
|
102
|
+
watch(canonical);
|
|
103
|
+
const code = canonical.endsWith('.md') && markdown ? markdown.getGraphSource(canonical) : readFileSync(canonical, 'utf8');
|
|
104
|
+
const parsed = parseSync(canonical, code);
|
|
105
|
+
if (parsed.errors.length)
|
|
106
|
+
throw new Error(`Hono islands: cannot parse ${canonical}: ${parsed.errors.map(error => error.message).join('; ')}`);
|
|
107
|
+
const body = parsed.program.body;
|
|
108
|
+
const found = islandImports(code, canonical, body);
|
|
109
|
+
const edges = [];
|
|
110
|
+
for (const node of body) {
|
|
111
|
+
const source = node.type === 'ImportDeclaration' ? node.source : node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration' ? node.source : undefined;
|
|
112
|
+
const typeOnly = node.type === 'ImportDeclaration' ? node.importKind === 'type' || (node.specifiers.length > 0 && node.specifiers.every((entry) => entry.type === 'ImportSpecifier' && entry.importKind === 'type')) : (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') && node.exportKind === 'type';
|
|
113
|
+
if (!source || typeOnly || !source.value.startsWith('.'))
|
|
114
|
+
continue;
|
|
115
|
+
const target = resolveComponent(source.value, join(canonical, '..'), ['.tsx', '.jsx', '.ts', '.js']);
|
|
116
|
+
if (!target || /\.[jt]sx?$/.test(target))
|
|
117
|
+
watchImport(source.value, canonical);
|
|
118
|
+
if (target && /\.[jt]sx?$/.test(target))
|
|
119
|
+
edges.push({ specifier: source.value, target: realpathSync(target) });
|
|
120
|
+
}
|
|
121
|
+
const analysis = { code, found, edges };
|
|
122
|
+
analyses.set(canonical, analysis);
|
|
123
|
+
return analysis;
|
|
124
|
+
};
|
|
68
125
|
const visit = (filename) => {
|
|
69
126
|
const canonical = realpathSync(filename);
|
|
70
127
|
if (graph.has(canonical))
|
|
@@ -72,44 +129,33 @@ export function honoIslands() {
|
|
|
72
129
|
const dependencies = new Set();
|
|
73
130
|
graph.set(canonical, dependencies);
|
|
74
131
|
pageFiles.add(canonical);
|
|
75
|
-
const code
|
|
76
|
-
|
|
132
|
+
const { code, found, edges } = analyze(canonical);
|
|
133
|
+
imports(code, canonical, found);
|
|
77
134
|
if (found.length) {
|
|
78
135
|
if (!/\.[jt]sx$/.test(canonical) && !(canonical.endsWith('.md') && markdown))
|
|
79
136
|
throw new Error('Hono islands: attributed imports require a static TSX/JSX module.');
|
|
80
137
|
directlyInteractive.add(canonical);
|
|
81
138
|
}
|
|
82
|
-
for (const
|
|
83
|
-
|
|
84
|
-
const typeOnly = node.type === 'ImportDeclaration' ? node.importKind === 'type' || (node.specifiers.length > 0 && node.specifiers.every((entry) => entry.type === 'ImportSpecifier' && entry.importKind === 'type')) : (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') && node.exportKind === 'type';
|
|
85
|
-
if (!source || typeOnly || !source.value.startsWith('.') || found.some((entry) => entry.specifier === source.value))
|
|
139
|
+
for (const edge of edges) {
|
|
140
|
+
if (found.some(entry => entry.specifier === edge.specifier))
|
|
86
141
|
continue;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
continue;
|
|
90
|
-
dependencies.add(realpathSync(target));
|
|
91
|
-
visit(target);
|
|
142
|
+
dependencies.add(edge.target);
|
|
143
|
+
visit(edge.target);
|
|
92
144
|
}
|
|
93
145
|
};
|
|
94
146
|
for (const entry of [...scan.pages.filter((page) => page.island).map((page) => page.componentPath), ...scan.layouts.filter((layout) => layout.island).map((layout) => layout.filePath), ...scan.namedLayouts.filter((layout) => layout.island).map((layout) => layout.filePath)])
|
|
95
147
|
visit(join(pagesDir, entry));
|
|
96
|
-
const
|
|
148
|
+
const validated = new Set();
|
|
149
|
+
const validateInteractive = (filename) => {
|
|
97
150
|
const canonical = realpathSync(filename);
|
|
98
|
-
if (
|
|
151
|
+
if (validated.has(canonical))
|
|
99
152
|
return;
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
153
|
+
validated.add(canonical);
|
|
154
|
+
const { found, edges } = analyze(canonical);
|
|
155
|
+
if (found.length)
|
|
103
156
|
throw new Error('Hono islands: attributed imports inside an interactive component are unsupported; use ordinary component imports there.');
|
|
104
|
-
for (const
|
|
105
|
-
|
|
106
|
-
const typeOnly = node.type === 'ImportDeclaration' ? node.importKind === 'type' || (node.specifiers.length > 0 && node.specifiers.every((entry) => entry.type === 'ImportSpecifier' && entry.importKind === 'type')) : (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') && node.exportKind === 'type';
|
|
107
|
-
if (!source || typeOnly || !source.value.startsWith('.'))
|
|
108
|
-
continue;
|
|
109
|
-
const target = resolveComponent(source.value, join(canonical, '..'), ['.tsx', '.jsx', '.ts', '.js']);
|
|
110
|
-
if (target && /\.[jt]sx?$/.test(target))
|
|
111
|
-
validateInteractive(target, seen);
|
|
112
|
-
}
|
|
157
|
+
for (const edge of edges)
|
|
158
|
+
validateInteractive(edge.target);
|
|
113
159
|
};
|
|
114
160
|
for (const target of islands.values())
|
|
115
161
|
validateInteractive(target);
|
|
@@ -117,6 +163,7 @@ export function honoIslands() {
|
|
|
117
163
|
for (const file of [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)])
|
|
118
164
|
validateInteractive(join(pagesDir, file));
|
|
119
165
|
}
|
|
166
|
+
dependencyFiles = watched;
|
|
120
167
|
const needsJS = new Set(directlyInteractive);
|
|
121
168
|
let changed = true;
|
|
122
169
|
while (changed) {
|
|
@@ -144,7 +191,7 @@ export function honoIslands() {
|
|
|
144
191
|
buildStart: rescan,
|
|
145
192
|
async hotUpdate({ file, modules, timestamp }) {
|
|
146
193
|
const inPages = normalizePath(file).startsWith(normalizePath(pagesDir) + '/');
|
|
147
|
-
if (!inPages && !
|
|
194
|
+
if (!inPages && !dependencyFiles.has(normalizePath(file)))
|
|
148
195
|
return;
|
|
149
196
|
await rescan();
|
|
150
197
|
const invalidated = new Set();
|