@ilha/router 0.8.0 → 0.8.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.
- package/dist/index.js +3 -1
- package/dist/plugin-DdquB3Nf.js +642 -0
- package/dist/rolldown.d.ts +1 -1
- package/dist/rolldown.js +10 -1
- package/dist/rspack.d.ts +1 -1
- package/dist/rspack.js +10 -1
- package/dist/src-C_n-faIh.js +1926 -0
- package/dist/ssr.js +139 -10
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +10 -1
- package/package.json +3 -3
- package/dist/plugin-BW2tnuyF.js +0 -8
- package/dist/src-8LBo_Ieg.js +0 -4
package/dist/ssr.js
CHANGED
|
@@ -1,15 +1,144 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { t as LOADER_ENDPOINT } from "./src-C_n-faIh.js";
|
|
2
|
+
import { pageRouter, registry } from "ilha:pages/server";
|
|
3
|
+
import "ilha:loaders";
|
|
4
|
+
|
|
5
|
+
//#region src/ssr.ts
|
|
6
|
+
/**
|
|
7
|
+
* Merge client and SSR asset manifests (same as `client.merge(server)` from Nitro).
|
|
8
|
+
*/
|
|
9
|
+
function mergeAssets({ client, server }) {
|
|
10
|
+
return client.merge(server);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* App-wide `<head>` defaults for `IlhaHandler`. Same shape as route `head()`;
|
|
14
|
+
* use so entry files read clearly: `head: appHead({ title, script: [...] })`.
|
|
15
|
+
*/
|
|
16
|
+
function appHead(head) {
|
|
17
|
+
return head;
|
|
18
|
+
}
|
|
19
|
+
const ATTR_ESC = {
|
|
20
|
+
"&": "&",
|
|
21
|
+
"<": "<",
|
|
22
|
+
">": ">",
|
|
23
|
+
"\"": """,
|
|
24
|
+
"'": "'"
|
|
25
|
+
};
|
|
26
|
+
function escapeAttr(value) {
|
|
27
|
+
return value.replace(/[&<>"']/g, (c) => ATTR_ESC[c]);
|
|
28
|
+
}
|
|
29
|
+
function stylesheetTag(attrs) {
|
|
30
|
+
const devId = attrs["data-vite-dev-id"] ? ` data-vite-dev-id="${escapeAttr(attrs["data-vite-dev-id"])}"` : "";
|
|
31
|
+
return `<link rel="stylesheet" href="${escapeAttr(attrs.href)}"${devId} />`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* SSR host helper for Ilha apps. Wires the generated `pageRouter` /
|
|
35
|
+
* `registry` and the asset manifest into a single `fetch`-style handler so a
|
|
36
|
+
* host entry collapses to:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { IlhaHandler } from "@ilha/router/ssr";
|
|
40
|
+
* import client from "./entry-client.ts?assets=client";
|
|
41
|
+
* import server from "./entry-server.ts?assets=ssr";
|
|
42
|
+
*
|
|
43
|
+
* const handler = new IlhaHandler({
|
|
44
|
+
* assets: mergeAssets({ client, server }),
|
|
45
|
+
* head: appHead({ title: "My app", script: [{ children: "..." }] }),
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* export default { fetch: (request: Request) => handler.handle(request) };
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
var IlhaHandler = class {
|
|
52
|
+
assets;
|
|
53
|
+
lang;
|
|
54
|
+
appId;
|
|
55
|
+
clientEntry;
|
|
56
|
+
head;
|
|
57
|
+
renderOptions;
|
|
58
|
+
constructor(options) {
|
|
59
|
+
this.assets = options.assets;
|
|
60
|
+
this.lang = options.lang ?? "en";
|
|
61
|
+
this.appId = options.appId ?? "app";
|
|
62
|
+
this.clientEntry = options.clientEntry ?? "/entry-client.js";
|
|
63
|
+
this.head = options.head ?? {};
|
|
64
|
+
this.renderOptions = options.renderOptions ?? {};
|
|
65
|
+
}
|
|
66
|
+
/** Render the document shell around an already-rendered island body. */
|
|
67
|
+
document(body, head) {
|
|
68
|
+
const clientEntry = this.assets.entry ?? this.clientEntry;
|
|
69
|
+
const styles = this.assets.css.map(stylesheetTag).join("\n ");
|
|
70
|
+
const titleTag = head?.headTags.includes("<title") ? "" : `<title>Ilha</title>\n `;
|
|
71
|
+
const routeHead = head?.headTags ? `\n ${head.headTags}` : "";
|
|
72
|
+
const htmlAttrsStr = head?.htmlAttrs ?? "";
|
|
73
|
+
const langFromHead = htmlAttrsStr.match(/\blang="([^"]*)"/)?.[1];
|
|
74
|
+
return `<!doctype html>
|
|
75
|
+
<html lang="${langFromHead != null ? langFromHead : this.lang}"${htmlAttrsStr.replace(/\s*lang="[^"]*"/, "")}>
|
|
5
76
|
<head>
|
|
6
77
|
<meta charset="UTF-8" />
|
|
7
78
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
-
${
|
|
9
|
-
${
|
|
79
|
+
${titleTag}<link rel="icon" href="/favicon.svg" />
|
|
80
|
+
${styles}${routeHead}
|
|
10
81
|
</head>
|
|
11
|
-
<body${
|
|
12
|
-
<div id="${
|
|
13
|
-
<script type="module" src="${
|
|
82
|
+
<body${head?.bodyAttrs ?? ""}>
|
|
83
|
+
<div id="${escapeAttr(this.appId)}">${body}</div>
|
|
84
|
+
<script type="module" src="${escapeAttr(clientEntry)}"><\/script>
|
|
14
85
|
</body>
|
|
15
|
-
</html
|
|
86
|
+
</html>`;
|
|
87
|
+
}
|
|
88
|
+
/** Handle an incoming request and return a full HTML / redirect Response. */
|
|
89
|
+
async handle(request) {
|
|
90
|
+
try {
|
|
91
|
+
return await this.handleInner(request);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.error("[ilha-router] request handling failed:", e);
|
|
94
|
+
return new Response("Internal Server Error", {
|
|
95
|
+
status: 500,
|
|
96
|
+
headers: { "content-type": "text/plain;charset=utf-8" }
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async handleInner(request) {
|
|
101
|
+
const url = new URL(request.url);
|
|
102
|
+
if (url.pathname === "/__ilha/loader") {
|
|
103
|
+
if (request.method !== "GET" && request.method !== "HEAD") return new Response(JSON.stringify({
|
|
104
|
+
kind: "error",
|
|
105
|
+
status: 405,
|
|
106
|
+
message: "Method Not Allowed"
|
|
107
|
+
}), {
|
|
108
|
+
status: 405,
|
|
109
|
+
headers: {
|
|
110
|
+
"content-type": "application/json;charset=utf-8",
|
|
111
|
+
allow: "GET, HEAD"
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
const path = url.searchParams.get("path") ?? "/";
|
|
115
|
+
const result = await pageRouter.runLoader(path, request);
|
|
116
|
+
const status = result.kind === "error" ? result.status : result.kind === "not-found" ? 404 : 200;
|
|
117
|
+
return new Response(JSON.stringify(result), {
|
|
118
|
+
status,
|
|
119
|
+
headers: {
|
|
120
|
+
"content-type": "application/json;charset=utf-8",
|
|
121
|
+
"cache-control": "no-store"
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const href = url.href.slice(url.origin.length);
|
|
126
|
+
const renderOptions = {
|
|
127
|
+
...this.renderOptions,
|
|
128
|
+
baseHead: this.head
|
|
129
|
+
};
|
|
130
|
+
const response = await pageRouter.renderResponse(href, registry, renderOptions, request);
|
|
131
|
+
if (response.kind === "redirect") return new Response(null, {
|
|
132
|
+
status: response.status,
|
|
133
|
+
headers: { location: response.to }
|
|
134
|
+
});
|
|
135
|
+
const status = response.kind === "error" ? response.status : response.status ?? 200;
|
|
136
|
+
return new Response(this.document(response.html, response.head), {
|
|
137
|
+
status,
|
|
138
|
+
headers: { "content-type": "text/html;charset=utf-8" }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
//#endregion
|
|
144
|
+
export { IlhaHandler, appHead, mergeAssets };
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
-
export {
|
|
2
|
+
export type { LayoutHandler, ErrorHandler, RouteSnapshot, AppError } from "./index";
|
|
3
3
|
export { ilhaPages, type IlhaPagesOptions } from "./plugin";
|
|
4
4
|
import { type IlhaPagesOptions } from "./plugin";
|
|
5
5
|
/** Vite plugin — use via `@ilha/router/vite`. */
|
package/dist/vite.js
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { t as ilhaPages } from "./plugin-DdquB3Nf.js";
|
|
2
|
+
|
|
3
|
+
//#region src/vite.ts
|
|
4
|
+
/** Vite plugin — use via `@ilha/router/vite`. */
|
|
5
|
+
function pages(options = {}) {
|
|
6
|
+
return ilhaPages.vite(options);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { ilhaPages, pages };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ilha/router",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "A tiny SPA router for Ilha",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"frontend",
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
"unplugin": "3.3.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"ilha": "0.9.
|
|
71
|
+
"ilha": "0.9.1",
|
|
72
72
|
"vite": "^8.1.3"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
|
-
"ilha": ">=0.9.
|
|
75
|
+
"ilha": ">=0.9.1"
|
|
76
76
|
}
|
|
77
77
|
}
|
package/dist/plugin-BW2tnuyF.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{existsSync as e,readFileSync as t,watch as n}from"node:fs";import{basename as r,dirname as i,extname as a,join as o,relative as s,resolve as c,sep as l}from"node:path";import{createUnplugin as u}from"unplugin";import{mkdir as d,readFile as f,readdir as p,writeFile as m}from"node:fs/promises";function h(e){return e.replace(/\\/g,`/`)}const g=/\.(test|spec|d)\.(ts|tsx)$/,_=/^\s*export\s+(?:const|let|var|async\s+function|function)\s+load\b/m,v=/^\s*export\s+(?:const|let|var|async\s+function|function)\s+clientLoad\b/m;async function y(e){try{let t=(await f(e,`utf8`)).replace(/^\s*\/\/.*$/gm,``);return{load:_.test(t),clientLoad:v.test(t)}}catch(t){return t?.code!==`ENOENT`&&console.warn(`[ilha-router] failed to read ${e} while detecting loader exports:`,t),{load:!1,clientLoad:!1}}}function b(e){return e.startsWith(`[...`)&&e.endsWith(`]`)?`**:${e.slice(4,-1)}`:e.startsWith(`[`)&&e.endsWith(`]`)?`:${e.slice(1,-1)}`:e}function x(e){return e.startsWith(`(`)&&e.endsWith(`)`)?``:b(e)}function S(e,t){let n=h(s(e,t)),r=n.slice(0,-a(n).length).split(`/`),i=[...r.slice(0,-1).map(x),b(r.at(-1))];return i.at(-1)===`index`&&i.pop(),`/`+i.filter(Boolean).join(`/`)||`/`}function C(e){return e===`/`?`index`:e.replace(/^\//,``).replace(/\*\*:[^/]*/g,e=>e.length>3?e.slice(3):`wildcard`).replace(/:/g,``).replace(/\*\*/g,`wildcard`).replace(/\//g,`-`).replace(/[^a-zA-Z0-9-]/g,``)||`page`}function w(e){return e===`/`?3:e.includes(`**`)?0:e.includes(`:`)?1:2}function T(e){return[...e].sort((e,t)=>{let n=w(t.pattern)-w(e.pattern);if(n!==0)return n;let r=t.pattern.split(`/`).length-e.pattern.split(`/`).length;return r===0?e.pattern.localeCompare(t.pattern):r})}function E(e,t,n,r){let a=h(s(e,i(t))),c=a===``?[]:a.split(`/`);return[e,...c.map((t,n)=>o(e,...c.slice(0,n+1)))].flatMap(e=>{let t=`${o(e,r)}.tsx`;if(n.has(t))return[t];let i=`${o(e,r)}.ts`;return n.has(i)?[i]:[]})}async function D(e,t=0){if(t>20)return console.warn(`[ilha:pages] Max scan depth (20) reached at ${e} — skipping`),[];let n=[];try{for(let r of await p(e,{withFileTypes:!0})){let i=o(e,r.name);r.isDirectory()?n.push(...await D(i,t+1)):r.isFile()&&/\.(ts|tsx)$/.test(r.name)&&!g.test(r.name)&&n.push(i)}}catch(e){if(e.code===`ENOENT`)return[];throw e}return n}async function O(e){let t=await D(e),n=new Set(t),i=t.filter(e=>!r(e).startsWith(`+`)),a=new Map,o=e=>{let t=a.get(e);return t||(t=y(e),a.set(e,t)),t};return Promise.all(i.map(async t=>{let r=S(e,t),i=E(e,t,n,`+layout`),a=E(e,t,n,`+error`),[s,...c]=await Promise.all([y(t),...i.map(o)]),l=i.filter((e,t)=>c[t].load),u=i.filter((e,t)=>c[t].clientLoad);return{file:t,pattern:r,name:C(r),layouts:i,errors:a,hasLoader:s.load,loaderLayouts:l,hasClientLoader:s.clientLoad,clientLoaderLayouts:u}}))}function k(e,t,n){if(e.length===0){console.warn(`[ilha:pages] No pages found in ${t}`);return}let r=new Map,i=new Map,a=[];for(let t of e){let e=r.get(t.pattern);e?a.push(`Duplicate route pattern "${t.pattern}"\n first: ${e}\n second: ${t.file}\n The first match wins — the second page will never be reached.`):r.set(t.pattern,t.file);let n=i.get(t.name);n?a.push(`Registry name collision: "${t.name}" is used by both\n ${n}\n ${t.file}\n Hydration may not work correctly for one of these routes.`):i.set(t.name,t.file)}if(a.length!==0){if(n)throw Error(`[ilha:pages] Route validation failed:\n\n${a.join(`
|
|
2
|
-
|
|
3
|
-
`)}`);for(let e of a)console.warn(`[ilha:pages] ${e}`)}}function A(e){return{serverFile:o(e,`pages.server.ts`),clientFile:o(e,`pages.client.ts`),loadersFile:o(e,`loaders.ts`)}}async function j(e,t,n={}){let r=n.mode??`spa`,i=n.interceptLinks,a=r===`static`,o=T(await O(e));k(o,e,n.strict===!0),await d(t,{recursive:!0});let{serverFile:s,clientFile:c,loadersFile:l}=A(t),u=await F(s,M(o,s)),f=await F(c,N(o,c,{isStatic:a,interceptLinks:i}));a||await F(l,P(o,l,s)),(u||f)&&await I(t)}function M(e,t){let n=e=>{let n=h(s(i(t),e));return n.startsWith(`.`)?n:`./${n}`},r=[`import { router, wrapLayout, wrapError } from "@ilha/router";`,`import type { Island } from "ilha";`],a=[],o=[],c=[];for(let[t,i]of e.entries()){r.push(`import { default as _page${t} } from ${JSON.stringify(n(i.file))};`);for(let[e,a]of i.layouts.entries())r.push(`import { default as _layout${t}_${e} } from ${JSON.stringify(n(a))};`);for(let[e,a]of i.errors.entries())r.push(`import { default as _error${t}_${e} } from ${JSON.stringify(n(a))};`);let s=`_page${t}`;for(let e=i.errors.length-1;e>=0;e--)s=`wrapError(_error${t}_${e}, ${s})`;for(let e=i.layouts.length-1;e>=0;e--)s=`wrapLayout(_layout${t}_${e}, ${s})`;let l=`_wrapped${t}`;a.push(`const ${l} = ${s};`),o.push(` ${JSON.stringify(i.name)}: ${l}`+(t<e.length-1?`,`:``)),c.push(` .route(${JSON.stringify(i.pattern)}, ${l})`+(i.hasLoader||i.loaderLayouts.length>0?`.markLoader(${JSON.stringify(i.pattern)})`:``)),i.errors.length>0&&c.push(` .errorBoundary(${JSON.stringify(i.pattern)}, _error${t}_${i.errors.length-1})`)}return[`// @generated by @ilha/router — do not edit`,`// Server module. Use for SSR and SSG/prerender.`,`// Import via: import { pageRouter, registry } from "ilha:pages/server";`,``,...r,``,...a,``,`export const registry: Record<string, Island<any, any>> = {`,...o,`};`,``,`export const pageRouter = router()`,...c,` ;`].join(`
|
|
4
|
-
`)}function N(e,t,n){let{isStatic:r,interceptLinks:a}=n,o=e=>{let n=h(s(i(t),e));return n.startsWith(`.`)?n:`./${n}`},c=e=>`${o(e)}?client`,l=e=>`${o(e)}?client-loader`,u=!1,d=r?[`import { router as _router, wrapLayout, wrapError } from "@ilha/router";`,`import type { Island } from "ilha";`]:[`import { router, wrapLayout, wrapError } from "@ilha/router";`,`import type { Island } from "ilha";`],f=[],p=[],m=[];for(let[t,n]of e.entries()){d.push(`import { default as _page${t} } from ${JSON.stringify(c(n.file))};`);for(let[e,r]of n.layouts.entries())d.push(`import { default as _layout${t}_${e} } from ${JSON.stringify(c(r))};`);for(let[e,r]of n.errors.entries())d.push(`import { default as _error${t}_${e} } from ${JSON.stringify(c(r))};`);let i=`_page${t}`;for(let e=n.errors.length-1;e>=0;e--)i=`wrapError(_error${t}_${e}, ${i})`;for(let e=n.layouts.length-1;e>=0;e--)i=`wrapLayout(_layout${t}_${e}, ${i})`;let a=`_wrapped${t}`;if(f.push(`const ${a} = ${i};`),p.push(` ${JSON.stringify(n.name)}: ${a}`+(t<e.length-1?`,`:``)),!r){m.push(` .route(${JSON.stringify(n.pattern)}, ${a})`+(n.hasLoader||n.loaderLayouts.length>0?`.markLoader(${JSON.stringify(n.pattern)})`:``));let e=[];for(let[r,i]of n.clientLoaderLayouts.entries()){let n=`_cl${t}_l${r}`;d.push(`import { clientLoad as ${n} } from ${JSON.stringify(l(i))};`),e.push(n)}if(n.hasClientLoader){let r=`_cl${t}`;d.push(`import { clientLoad as ${r} } from ${JSON.stringify(l(n.file))};`),e.push(r)}if(e.length>0){let t=e.length===1?e[0]:`composeLoaders([${e.join(`, `)}])`;e.length>1&&(u=!0),m.push(` .clientLoader(${JSON.stringify(n.pattern)}, ${t})`)}n.errors.length>0&&m.push(` .errorBoundary(${JSON.stringify(n.pattern)}, _error${t}_${n.errors.length-1})`)}}u&&(d[0]=d[0].replace(`{ router`,`{ composeLoaders, router`));let g=r?`_router({ mode: "static" })`:`router(${a===!1?`{ interceptLinks: false }`:``})`,_=[`// @generated by @ilha/router — do not edit`,`// Client module. Use for browser hydration.`,`// Import via: import { pageRouter, registry } from "ilha:pages/client";`,``,...d,``,...f,``,`export const registry: Record<string, Island<any, any>> = {`,...p,`};`,``];return r?_.push(`export const pageRouter = ${g};`):_.push(`export const pageRouter = ${g}`,...m,` ;`),_.join(`
|
|
5
|
-
`)}function P(e,t,n){let r=e=>{let n=h(s(i(t),e));return n.startsWith(`.`)?n:`./${n}`},a=e.filter(e=>e.hasLoader||e.loaderLayouts.length>0);if(a.length===0)return[`// @generated by @ilha/router — do not edit`,`// This project has no loader exports; this file is intentionally empty.`,``,`export {};`,``].join(`
|
|
6
|
-
`);let o=r(n).replace(/\.tsx?$/,``),c=[`import { pageRouter } from ${JSON.stringify(o)};`],l=!1,u=[];for(let[e,t]of a.entries()){let n=[];for(let[i,a]of t.loaderLayouts.entries()){let t=`_p${e}_l${i}`;c.push(`import { load as ${t} } from ${JSON.stringify(r(a))};`),n.push(t)}if(t.hasLoader){let i=`_p${e}`;c.push(`import { load as ${i} } from ${JSON.stringify(r(t.file))};`),n.push(i)}let i=n.length===1?n[0]:`composeLoaders([${n.join(`, `)}])`;n.length>1&&(l=!0),u.push(`pageRouter.attachLoader(${JSON.stringify(t.pattern)}, ${i});`)}return l&&c.unshift(`import { composeLoaders } from "@ilha/router";`),[`// @generated by @ilha/router — do not edit`,`// Server-only. Import this module from your SSR entry to wire loaders`,`// onto pageRouter. Importing it from the client is a no-op but wastes`,`// bundle size — rely on the default build pipeline to keep it out.`,``,...c,``,...u,``].join(`
|
|
7
|
-
`)}async function F(e,t){try{if(await f(e,`utf8`)===t)return!1}catch{}return await m(e,t,`utf8`),!0}async function I(e){await F(o(e,`pages.d.ts`),[`// @generated by @ilha/router — do not edit`,``,`declare module "ilha:pages/server" {`,` import type { RouterBuilder } from "@ilha/router";`,` import type { Island } from "ilha";`,` export const pageRouter: RouterBuilder;`,` export const registry: Record<string, Island<any, any>>;`,`}`,``,`declare module "ilha:pages/client" {`,` import type { RouterBuilder } from "@ilha/router";`,` import type { Island } from "ilha";`,` export const pageRouter: RouterBuilder;`,` export const registry: Record<string, Island<any, any>>;`,`}`,``,`declare module "ilha:loaders" {`,` // Side-effect-only module. Importing it attaches loaders to pageRouter.`,`}`,``].join(`
|
|
8
|
-
`))}const L=`\0ilha:pages/server`,R=`\0ilha:pages/client`,z=`\0ilha:loaders`,B=[L,R,z];function V(e){try{return JSON.parse(t(e,`utf8`))}catch{return null}}function H(t,n){let r=t;for(;;){let t=o(r,`node_modules`,n,`package.json`);if(e(t))return V(t);let a=i(r);if(a===r)return null;r=a}}function U(e){let t=V(o(e,`package.json`));if(!t)return[];let n={...t.dependencies??{},...t.devDependencies??{}},r=[];for(let t of Object.keys(n)){if(t===`ilha`)continue;let n=H(e,t);if(!n)continue;let i=n.peerDependencies??{},a=n.dependencies??{};(`ilha`in i||`ilha`in a)&&r.push(t)}return r}function W(e,t){let n=c(e,t.dir??`src/pages`),r=c(e,t.outDir??`.ilha`),{serverFile:i,clientFile:a,loadersFile:o}=A(r);return{pagesDir:n,outDir:r,serverFile:i,clientFile:a,loadersFile:o}}function G(e){let t,n,i,a,o,s=r=>{({pagesDir:t,outDir:n,serverFile:i,clientFile:a,loadersFile:o}=W(r,e))},c=async()=>{try{await j(t,n,{mode:e.mode,interceptLinks:e.interceptLinks,strict:e.strict})}catch(t){if(console.error(`[ilha:pages] codegen failed:`,t),e.strict)throw t}},u=e=>e===t||e.startsWith(t+l);return{get pagesDir(){return t},get outDir(){return n},get serverFile(){return i},get clientFile(){return a},get loadersFile(){return o},setPaths:s,regen:c,shouldRegenOnChange:e=>{if(!u(e))return!1;let t=r(e);return t.startsWith(`+`)||/\.(ts|tsx)$/.test(t)},isUnderPagesDir:u}}async function K(e,t,n){n(t)&&await e.regen()}function q(e,t,n){if(t===`ilha:pages/server`)return L;if(t===`ilha:pages/client`)return R;if(t===`ilha:loaders`)return z;for(let r of[`?client-loader`,`?client`]){if(!t.endsWith(r))continue;let i=t.slice(0,-r.length),a=n?c(n.replace(/\?.*$/,``),`..`,i):c(i);return!e.pagesDir||!e.isUnderPagesDir(a)?void 0:a+r}}function J(e,t){if(t===`\0ilha:pages/server`){let t=e.serverFile.replace(/\.tsx?$/,``);return`export { pageRouter, registry } from ${JSON.stringify(t)};`}if(t===`\0ilha:pages/client`){let t=e.clientFile.replace(/\.tsx?$/,``);return`export { pageRouter, registry } from ${JSON.stringify(t)};`}if(t===`\0ilha:loaders`){let t=e.loadersFile.replace(/\.tsx?$/,``);return`import ${JSON.stringify(t)};`}if(t.endsWith(`?client-loader`)){let e=t.slice(0,-14);return`export { clientLoad } from ${JSON.stringify(e)};`}if(t.endsWith(`?client`)){let e=t.slice(0,-7);return`export { default } from ${JSON.stringify(e)};`}}function Y(e,t){return async n=>{e.isUnderPagesDir(n)&&(await e.regen(),await t())}}function X(t,r){let i=null,a=null,s=!1,c=()=>{i=n(t.pagesDir,{recursive:!0},(e,n)=>{n&&r(o(t.pagesDir,n))})};return e(t.pagesDir)?c():(a=setInterval(()=>{s||!e(t.pagesDir)||(clearInterval(a),a=null,c(),r(o(t.pagesDir,`.`)))},1e3),a.unref?.()),()=>{s=!0,a&&clearInterval(a),i?.close()}}const Z=u((e={})=>{let t=G(e);return{name:`ilha:pages`,async buildStart(){t.pagesDir||t.setPaths(process.cwd()),this.addWatchFile?.(t.pagesDir),await t.regen()},async watchChange(e){await K(t,e,e=>t.shouldRegenOnChange(e))},resolveId(e,n){return q(t,e,n)},load(e){return J(t,e)},vite:{config(e){let t=[`ilha`,`@ilha/store`,`@ilha/router`,`alien-signals`,...U(e.root?c(e.root):process.cwd())],n=e.ssr?.noExternal,r=n===!0?!0:[...new Set([...Array.isArray(n)?n:n==null?[]:[n],...t])];return{resolve:{dedupe:[...new Set([...e.resolve?.dedupe??[],...t])]},ssr:{noExternal:r},optimizeDeps:{...e.optimizeDeps,include:[...new Set([...e.optimizeDeps?.include??[],`ilha`,`ilha/jsx-runtime`,`ilha/jsx-dev-runtime`,`@ilha/store`,`alien-signals`])]}}},configResolved(e){t.setPaths(e.root)},configureServer(e){e.watcher.add(t.pagesDir);let n=Y(t,async()=>{for(let t of B){let n=e.moduleGraph.getModuleById(t);n&&e.moduleGraph.invalidateModule(n)}e.hot.send({type:`full-reload`})});e.watcher.on(`add`,n),e.watcher.on(`addDir`,n),e.watcher.on(`unlink`,n),e.watcher.on(`change`,async e=>{t.shouldRegenOnChange(e)&&await n(e)})}},rspack(e){t.setPaths(e.options.context??process.cwd());let n=Y(t,()=>{e.watching&&e.invalidate()}),r;e.hooks.watchRun.tap(`ilha:pages`,()=>{r?.(),r=X(t,n)}),e.hooks.shutdown.tap(`ilha:pages`,()=>r?.())}}});export{Z as t};
|
package/dist/src-8LBo_Ieg.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import e,{ISLAND_MOUNT_INTERNAL as t,context as n,html as r,mount as i}from"ilha";import{addRoute as a,createRouter as o,findRoute as s}from"rou3";const c=typeof window<`u`&&typeof document<`u`,l={readLocation(){return c?{pathname:location.pathname,search:location.search,hash:location.hash}:{pathname:`/`,search:``,hash:``}},push(e,t){c&&history.pushState(t??null,``,e)},replace(e,t){c&&history.replaceState(t??null,``,e)},onChange(e){return c?(window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)):()=>{}},toLinkHref(e){return e},extractLogicalPath(e){let t=e.getAttribute(`href`);return!t||e.protocol&&!/^(http:|https:)$/.test(e.protocol)||t.startsWith(`#`)||e.hostname&&(e.hostname!==location.hostname||e.protocol!==location.protocol)?null:e.pathname+e.search+e.hash}};function u(e){let t=e.startsWith(`#`)?e.slice(1):e,n=t===``?`/`:t.startsWith(`/`)?t:`/`+t,r=new URL(n,`http://_`);return{pathname:r.pathname,search:r.search,hash:r.hash}}const d={readLocation(){return c?u(location.hash):{pathname:`/`,search:``,hash:``}},push(e,t){c&&history.pushState(t??null,``,e.startsWith(`#`)?e:`#`+e)},replace(e,t){c&&history.replaceState(t??null,``,e.startsWith(`#`)?e:`#`+e)},onChange(e){return c?(window.addEventListener(`popstate`,e),window.addEventListener(`hashchange`,e),()=>{window.removeEventListener(`popstate`,e),window.removeEventListener(`hashchange`,e)}):()=>{}},toLinkHref(e){return e.startsWith(`#`)?e:`#`+e},extractLogicalPath(e){let t=e.getAttribute(`href`);if(!t||e.protocol&&!/^(http:|https:)$/.test(e.protocol))return null;if(t.startsWith(`#`)){let e=t.slice(1);return e===``||!e.startsWith(`/`)?null:e}if(/^https?:\/\//i.test(t))try{let e=new URL(t);if(e.origin!==location.origin||!e.hash||e.hash===`#`)return null;let n=e.hash.slice(1);return n.startsWith(`/`)?n:null}catch{return null}return t}};let f=`history`,p=l;function m(e){f=e,p=e===`hash`?d:l}function h(){return f}function g(){return p}const _=typeof window<`u`&&typeof document<`u`;function v(e){return e}var y=class{__ilhaRedirect=!0;to;status;constructor(e,t=302){this.to=e,this.status=t}},b=class{__ilhaLoaderError=!0;status;message;constructor(e,t){this.status=e,this.message=t}};function x(e,t=302){throw new y(e,t)}function ee(e,t){throw new b(e,t)}function S(e){return e.length===0?async()=>({}):e.length===1?e[0]:async t=>{let n=await Promise.all(e.map(e=>e(t)));return Object.assign({},...n)}}const C=Symbol.for(`ilha.router.wrapLayout.leaf`),te=Symbol.for(`ilha.router.wrapLayout.handler`);function ne(e){let t=e.match(/^<([a-zA-Z][\w-]*)\s[^>]*>([\s\S]*)<\/\1>\s*$/);return t?t[2]:e}function re(e){let t=e.match(/^<([a-zA-Z][\w-]*)\s([^>]*)>/);return t?{tag:t[1],attrs:t[2]}:null}const ie=/<(pre|script|style|textarea)\b/i;function ae(e,t,n){let r=RegExp(`<${n}\\b`,`gi`),i=RegExp(`</${n}>`,`gi`),a=1,o=t;for(;a>0&&o<e.length;){r.lastIndex=o,i.lastIndex=o;let t=r.exec(e),n=i.exec(e);if(!n)return null;if(t&&t.index<n.index)a+=1,o=t.index+t[0].length;else{if(--a,a===0)return n.index+n[0].length;o=n.index+n[0].length}}return o}function oe(e,t){let n=t;for(;n<e.length;){if(e.startsWith(`<!--`,n)){let t=e.indexOf(`-->`,n);if(t===-1)return null;n=t+3;continue}let t=e.slice(n).match(ie);if(t&&t.index!=null&&t.index>=0){let r=n+t.index,i=!1,a=n;for(;a<r;){let t=e.indexOf(`<!--`,a);if(t===-1||t>=r)break;let o=e.indexOf(`-->`,t);if(o===-1)return null;if(r<o+3){n=o+3,i=!0;break}a=o+3}if(i)continue;let o=e.indexOf(`<div`,n),s=e.indexOf(`</div>`,n);if(!(o!==-1&&o<r||s!==-1&&s<r)){let i=t[1].toLowerCase(),a=ae(e,r+t[0].length,i);if(a===null)return null;n=a;continue}}let r=e.indexOf(`<div`,n),i=e.indexOf(`</div>`,n);return i===-1&&r===-1?null:r===-1||i!==-1&&i<r?{kind:`close`,index:i}:{kind:`open`,index:r}}return null}function se(e){let t=[];for(let n of e.matchAll(/<div\s[^>]*data-ilha-slot="k:page"[^>]*>/g)){let r=n.index+n[0].length,i=1,a=r;for(;i>0;){let n=oe(e,a);if(!n)break;if(n.kind===`open`)i+=1,a=n.index+4;else{if(--i,i===0){t.push({openEnd:r,closeStart:n.index});break}a=n.index+6}}}return t}function w(e,t,n){let r=se(e);if(r.length===0)return e;let i=n===`innermost`?r[r.length-1]:r[0];return e.slice(0,i.openEnd)+t+e.slice(i.closeStart)}function ce(e,t){let n=e[te];if(!n)return e.toString(t);let r=e[C]??e;return n(Object.assign(r.key(`page`),{toString:()=>``})).toString(t)}async function le(e,t,n,r){let i=ne(await t.hydratable(n,r));return w(w(ce(e,n),``,`innermost`),i,`innermost`)}function ue(e,n){let r=n[C]??n,i=r===n?null:n,a=e(Object.assign(n.key(`page`),{toString:n.toString.bind(n)}));a[C]=r,a[te]=e;function o(e){let t=[...e.querySelectorAll(`[data-ilha-slot="k:page"]`)].filter(t=>{let n=t.closest(`[data-ilha]`);return n===null||n===e});return t.length===0?e:t[t.length-1]}function s(e,t){let n=e=>{delete e._skipOnMount,t.setAttribute(`data-ilha-state`,JSON.stringify(e))};if(t.hasAttribute(`data-ilha-state`)){let r=e.getAttribute(`data-ilha-state`);if(r)try{n(JSON.parse(r));return}catch{}let i=t.getAttribute(`data-ilha-state`);if(i)try{let e=JSON.parse(i);delete e._skipOnMount,t.setAttribute(`data-ilha-state`,JSON.stringify(e))}catch{}return}let r=e.getAttribute(`data-ilha-state`);if(r)try{n(JSON.parse(r));return}catch{}t.childNodes.length>0&&t.setAttribute(`data-ilha-state`,`{}`)}function c(e){let n=e[t];if(typeof n!=`function`)return;e[t]=(e,t)=>{let r=e.closest(`[data-ilha]`);return r&&r!==e&&s(r,e),n(e,t)};let r=e.mount.bind(e);e.mount=(e,t)=>{let n=e.closest(`[data-ilha]`);return n&&n!==e&&s(n,e),r(e,t)}}c(r);let l=a.mount.bind(a),u=a[t];function d(e){s(e,o(e))}return a.mount=(e,t)=>(d(e),l(e,t)),a[t]=(e,t)=>(d(e),typeof u==`function`?u(e,t):{unmount:l(e,t),updateProps:()=>{}}),a.hydratable=async(e,t)=>{if(!t?.name)throw Error(`wrapLayout: hydratable requires options.name`);let n=e??{},o=await r.hydratable(n,t),s=re(o);if(!s)return o;let c=ne(o);i&&(c=await le(i,r,n,t));let l=w(w(ce(a,n),``,`first`),c,`first`);return`<${s.tag} ${s.attrs}>${l}</${s.tag}>`},a}function de(n,r){let i=e.render(()=>{try{return r.toString()}catch(e){let t={path:A(),params:j(),search:M(),hash:N()};return n({message:e.message,status:e.status,stack:e.stack},t).toString()}});return i.mount=(e,t)=>{try{return r.mount(e,t)}catch(r){let i={path:A(),params:j(),search:M(),hash:N()},a=n({message:r.message,status:r.status,stack:r.stack},i);return e.innerHTML=a.toString(),a.mount(e,t)}},i[t]=(e,i)=>{try{let n=r[t];return typeof n==`function`?n(e,i):{unmount:r.mount(e,i),updateProps:()=>{}}}catch(t){let r={path:A(),params:j(),search:M(),hash:N()},a=n({message:t.message,status:t.status,stack:t.stack},r);return e.innerHTML=a.toString(),{unmount:a.mount(e,i),updateProps:()=>{}}}},i.hydratable=async(e,t)=>{if(!t?.name)throw Error(`wrapError: hydratable requires options.name`);return r.hydratable(e??{},t)},i}function fe(e){return e}function pe(e){let t=new Map;for(let[n,r]of Object.entries(e))t.has(r)||t.set(r,n);return t}const me=`/__ilha/loader`,T=new Map;let he=!1;async function E(e){let t=document.startViewTransition?.bind(document);if(!he||!t)return e();let n,r,i=!1;if(await t(()=>{try{n=e()}catch(e){throw i=!0,r=e,e}}).updateCallbackDone?.catch(()=>{}),i)throw r;return n}async function ge(e,t,n,r){let i=new URL(n,location.origin),a=z(t),o=[],s=await pt(e,i,a,ft(i),r??new AbortController().signal,e=>o.push(e));if(r?.throwIfAborted(),s.kind===`redirect`){let e=ut(s.to,i,Ge);return e.ok?{kind:`redirect`,to:e.to,status:s.status}:(console.warn(`[ilha-router] Blocked unsafe redirect target "${s.to}". Set allowExternalRedirects: true to allow cross-origin redirects.`),{kind:`error`,status:500,message:`Unsafe redirect target`})}return s.kind===`data`?o.length>0?{kind:`data`,data:s.data,headEntries:o}:{kind:`data`,data:s.data}:s}async function _e(e,t){let n=T.get(e);if(n&&(T.delete(e),Date.now()<=n.expires))try{t?.throwIfAborted();let e=await n.promise;return t?.throwIfAborted(),e}catch(e){if(e?.name===`AbortError`)throw e}let r=e.split(`?`)[0]??``,i=s(R,`GET`,r),a=i?.data?.clientLoader??i?.data?.loader;if(a)return ge(a,i?.params,e,t);let o=`${me}?path=${encodeURIComponent(e)}`;try{let e=await fetch(o,{signal:t,headers:{accept:`application/json`}});if(!e.ok){try{let t=await e.json();if(t&&typeof t==`object`&&`kind`in t)return t}catch{}return{kind:`error`,status:e.status,message:e.statusText}}return await e.json()}catch(e){if(e?.name===`AbortError`)throw e;return{kind:`error`,status:0,message:e?.message??`network error`}}}function D(e){if(!_)return;let t=T.get(e);if(t&&Date.now()<=t.expires)return;let n=e.split(`?`)[0]??``;if(!s(R,`GET`,n)?.data?.hasLoader)return;let r=_e(e).catch(e=>({kind:`error`,status:0,message:e?.message??`prefetch failed`}));T.set(e,{promise:r,expires:Date.now()+3e4})}async function ve(e,t,n,r,i,a){if(!e){if(W){let e=W;return E(()=>{t.innerHTML=`<div data-router-view data-router-not-found>${e.toString()}</div>`;let n=t.firstElementChild;return n?e.mount(n):()=>{}})}return await E(()=>{t.innerHTML=`<div data-router-empty></div>`}),()=>{}}let o=s(R,`GET`,n.split(`?`)[0]??``),c=!!o?.data?.hasLoader,l={},u=c?await _e(n,r):{kind:`data`,data:{}};if(u.kind===`redirect`)return Ue(u.to),()=>{};if(u.kind===`error`){let e=o?.data?.errorHandler;if(e)return E(()=>ye(e,t,u.status,u.message));let n=it(u.message);return await E(()=>{t.innerHTML=`<div data-router-view data-router-error="${u.status}">${n}</div>`}),()=>{}}if(u.kind===`not-found`)return await E(()=>{t.innerHTML=`<div data-router-empty></div>`}),()=>{};l=u.data;let d={entries:[...u.headEntries??[]]};if(!i){console.warn(`[ilha-router] No registry provided for client-side navigation. Island will not be interactive.`);let n=await Z(d,()=>e.toString(l));return await E(()=>{X(d.entries),t.innerHTML=`<div data-router-view>${n}</div>`}),()=>{}}let f=a?.get(e)??Object.entries(i).find(([,t])=>t===e)?.[0];if(!f){console.warn(`[ilha-router] Island not found in registry for client-side navigation.`);let n=await Z(d,()=>e.toString(l));return await E(()=>{X(d.entries),t.innerHTML=`<div data-router-view>${n}</div>`}),()=>{}}let p=await Z(d,()=>e.hydratable(l,{name:f,as:`div`,snapshot:!0}));return E(()=>{X(d.entries),t.innerHTML=`<div data-router-view>${p}</div>`;let n=t.querySelector(`[data-ilha="${f}"]`);return n?e.mount(n):()=>{}})}function ye(e,t,n,r){try{let i=e({message:r,status:n},{path:A(),params:j(),search:M(),hash:N()});t.innerHTML=`<div data-router-view data-router-error="${n}">${i.toString()}</div>`;let a=t.firstElementChild;return a?i.mount(a):()=>{}}catch(e){return console.error(`[ilha-router] error boundary threw while rendering a loader error:`,e),t.innerHTML=`<div data-router-view data-router-error="${n}"></div>`,()=>{}}}let O=null,be=null;async function xe(){return O||(be||=import(`node:async_hooks`).then(({AsyncLocalStorage:e})=>(O=new e,O)),be)}_||xe().catch(()=>{});function k(){return _?null:O?.getStore()??null}function Se(){return{path:``,params:{},search:``,hash:``,island:null}}const Ce=n(`router.path`,``),we=n(`router.params`,{}),Te=n(`router.search`,``),Ee=n(`router.hash`,``);function A(e){let t=k();return arguments.length>0?t?t.path=e:(Ce(e),e):t?t.path:Ce()}function j(e){let t=k();return arguments.length>0?t?t.params=e:(we(e),e):t?t.params:we()}function M(e){let t=k();return arguments.length>0?t?t.search=e:(Te(e),e):t?t.search:Te()}function N(e){let t=k();return arguments.length>0?t?t.hash=e:(Ee(e),e):t?t.hash:Ee()}const P=n(`router.navigating`,0);function De(){return P()>0}let F=null;function Oe(){return!_||!F?Promise.resolve():F()}function I(){if(!_)return()=>{};P(P()+1);let e=!1;return()=>{e||(e=!0,P(Math.max(0,P()-1)))}}function ke(){return{path:A,params:j,search:M,hash:N,navigating:De}}const Ae=n(`router.active`,null);function L(e){let t=k();return arguments.length>0?t?t.island=e??null:(Ae(e??null),e??null):t?t.island:Ae()}let R=o();function z(e){let t={};if(e)for(let[n,r]of Object.entries(e))t[n]=decodeURIComponent(r);return t}function je(e,t=R){let n=typeof e==`string`?new URL(e,`http://localhost`):e,r=s(t,`GET`,n.pathname);A(n.pathname),j(z(r?.params)),M(n.search),N(n.hash),L(r?.data?.island??null)}function Me(){let e=g().readLocation(),t=s(R,`GET`,e.pathname);A(e.pathname),j(z(t?.params)),M(e.search),N(e.hash),L(t?.data?.island??null)}function B(){_&&Me()}const Ne=new Set,Pe=new Set;function Fe(e){return Ne.add(e),()=>Ne.delete(e)}function Ie(e){return Pe.add(e),()=>Pe.delete(e)}function Le(e){for(let t of Pe)try{t(e)}catch(e){console.error(`[ilha-router] afterNavigate hook threw:`,e)}}const Re=new Map;let ze=0,V=0;function H(){if(!_)return 0;let e=history.state;return typeof e?.__ilhaNavKey==`number`?e.__ilhaNavKey:0}function Be(){Re.set(H(),{x:window.scrollX,y:window.scrollY})}function Ve(e){requestAnimationFrame(()=>{if(e&&e!==`#`){let t=document.getElementById(e.slice(1))??document.querySelector(`a[name="${Y(e.slice(1))}"]`);if(t){t.scrollIntoView();return}}window.scrollTo(0,0)})}function He(){let e=Re.get(H());e&&requestAnimationFrame(()=>window.scrollTo(e.x,e.y))}function U(e,t={}){if(!_)return;let n=g(),r=n.readLocation(),i=r.pathname+r.search+r.hash;if(e===i)return;let a=t.replace?`replace`:`push`,o=!1;for(let t of Ne)try{t({from:i,to:e,type:a,cancel:()=>o=!0})}catch(e){console.error(`[ilha-router] beforeNavigate hook threw:`,e)}o||(t.replace?n.replace(e,{__ilhaNavKey:H()}):(Be(),ze=Math.max(ze+1,H()+1),n.push(e,{__ilhaNavKey:ze})),V=H(),Me(),t.scroll!==!1&&Ve(n.readLocation().hash),Le({from:i,to:e,type:a}))}function Ue(e){if(/^https?:\/\//i.test(e)){try{let t=new URL(e);if(t.origin===location.origin){U(t.pathname+t.search+t.hash,{replace:!0});return}}catch{return}location.assign(e);return}U(e,{replace:!0})}function We(e=document,t={}){if(!_)return()=>{};let n=t.prefetch!==!1;function r(e,t){let n=e.getAttribute(`target`)===`_blank`,r=!!t&&(t.ctrlKey||t.metaKey||t.shiftKey||t.altKey),i=e.hasAttribute(`data-no-intercept`),a=e.hasAttribute(`download`),o=/\bexternal\b/i.test(e.getAttribute(`rel`)??``);return n||r||i||a||o?null:g().extractLogicalPath(e)}let i=e=>{if(e.defaultPrevented||typeof e.button==`number`&&e.button!==0)return;let t=e.target.closest(`a`);if(!t)return;let n=r(t,e);n!==null&&(e.preventDefault(),U(n))},a=e=>{let t=e.target.closest(`a`);if(!t)return;let n=t.getAttribute(`data-prefetch`);if(n===null||n===`false`)return;let i=r(t);i!==null&&D(i.split(`#`)[0]??i)};return e.addEventListener(`click`,i),n&&e.addEventListener(`mouseover`,a,{passive:!0}),()=>{e.removeEventListener(`click`,i),n&&e.removeEventListener(`mouseover`,a)}}let W=null,Ge=!1;const G=e.render(()=>{let e=L();return e?`<div data-router-view>${e.toString()}</div>`:W?`<div data-router-view data-router-not-found>${W.toString()}</div>`:`<div data-router-empty></div>`}),Ke=e.state(`href`,``).state(`label`,``).on(`[data-link]@click`,({state:e,event:t})=>{t.preventDefault(),U(e.href())}).on(`[data-link]@mouseenter`,({state:e})=>{let t=e.href();if(t){if(/^https?:\/\//i.test(t))try{let e=new URL(t);if(e.origin!==location.origin)return;D(e.pathname+e.search);return}catch{return}D(t)}}).render(({state:e})=>r`<a data-link data-prefetch href="${()=>g().toLinkHref(e.href())}"
|
|
2
|
-
>${e.label}</a
|
|
3
|
-
>`);function qe(e,t={}){if(t.exact===!1){let t=A(),n=e.endsWith(`/`)?e.slice(0,-1):e;return t===n||t===n+`/`||t.startsWith(n+`/`)}let n=s(R,`GET`,A());return n?n.data.pattern===e:!1}const K=`data-ilha-head`,Je=`data-ilha-router-html`,Ye=`data-ilha-router-body`;let q=null,J=null,Xe=null;async function Ze(){return J||(Xe||=import(`node:async_hooks`).then(({AsyncLocalStorage:e})=>(J=new e,J)),Xe)}function Qe(){return _?q:J?.getStore()??null}function $e(e){let t=Qe();if(!t){_||console.warn(`[ilha-router] head() called outside an SSR render window — ignored.`);return}t.entries.push(e)}function Y(e){return typeof CSS<`u`&&typeof CSS.escape==`function`?CSS.escape(e):e.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`)}function et(e){return`charset`in e?`meta[charset][${K}]`:`name`in e?`meta[name="${Y(e.name)}"][${K}]`:`property`in e?`meta[property="${Y(e.property)}"][${K}]`:`http-equiv`in e?`meta[http-equiv="${Y(e[`http-equiv`])}"][${K}]`:null}function tt(e){return e.rel&&e.href?`link[rel="${Y(e.rel)}"][href="${Y(e.href)}"][${K}]`:null}function X(e){if(!_)return;let t,n,r=[],i=[],a={},o={};for(let s of e)s.title!==void 0&&(t=s.title),s.titleTemplate!==void 0&&(n=s.titleTemplate),s.meta&&r.push(...s.meta),s.link&&i.push(...s.link),s.htmlAttrs&&(a={...a,...s.htmlAttrs}),s.bodyAttrs&&(o={...o,...s.bodyAttrs});let s=st(t,n);s!==void 0&&(document.title=s);let c=ot(r,at),l=ot(i,e=>`${e.rel??``}:${e.href??``}`),u=new Set;for(let e of c){let t=et(e);if(!t)continue;let n=document.querySelector(t);n||(n=document.createElement(`meta`),n.setAttribute(K,``),document.head.appendChild(n));for(let[t,r]of Object.entries(e))n.setAttribute(t,r);u.add(n)}for(let e of l){let t=tt(e),n=t?document.querySelector(t):null;n||(n=document.createElement(`link`),n.setAttribute(K,``),document.head.appendChild(n));for(let[t,r]of Object.entries(e))n.setAttribute(t,r);u.add(n)}for(let e of[...document.head.querySelectorAll(`[${K}]`)])u.has(e)||e.remove();let d=document.documentElement,f=(d.getAttribute(Je)??``).split(/\s+/).filter(Boolean);for(let e of f)d.removeAttribute(e);let p=Object.keys(a);for(let[e,t]of Object.entries(a))d.setAttribute(e,t);p.length?d.setAttribute(Je,p.join(` `)):d.removeAttribute(Je);let m=document.body,h=(m.getAttribute(Ye)??``).split(/\s+/).filter(Boolean);for(let e of h)m.removeAttribute(e);let g=Object.keys(o);for(let[e,t]of Object.entries(o))m.setAttribute(e,t);g.length?m.setAttribute(Ye,g.join(` `)):m.removeAttribute(Ye)}async function Z(e,t){if(_){let n=q;q=e;try{return await t()}finally{q=n}}return await(await Ze()).run(e,()=>Promise.resolve(t()))}const nt={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`};function rt(e){return String(e).replace(/[&<>"']/g,e=>nt[e])}function it(e){return String(e).replace(/[&<>]/g,e=>nt[e])}function Q(e){return Object.entries(e).map(([e,t])=>` ${e}="${rt(t)}"`).join(``)}function at(e){return`charset`in e?`charset`:`name`in e?`name:${e.name}`:`property`in e?`property:${e.property}`:`http-equiv`in e?`http-equiv:${e[`http-equiv`]}`:JSON.stringify(e)}function ot(e,t){let n=new Map;for(let r of e)n.set(t(r),r);return[...n.values()]}function st(e,t){return t===void 0?e:typeof t==`function`?t(e):t.replace(/%s/g,e??``)}function $(e){let t,n,r=[],i=[],a=[],o={},s={};for(let c of e)c.title!==void 0&&(t=c.title),c.titleTemplate!==void 0&&(n=c.titleTemplate),c.meta&&r.push(...c.meta),c.link&&i.push(...c.link),c.script&&a.push(...c.script),c.htmlAttrs&&(o={...o,...c.htmlAttrs}),c.bodyAttrs&&(s={...s,...c.bodyAttrs});let c=st(t,n),l=[];c!==void 0&&l.push(`<title>${rt(c)}</title>`);for(let e of ot(r,at))l.push(`<meta${Q({...e,[K]:``})} />`);for(let e of ot(i,e=>`${e.rel??``}:${e.href??``}`))l.push(`<link${Q({...e,[K]:``})} />`);for(let e of a){let{children:t,...n}=e,r=(t??``).replace(/<\/script/gi,`<\\/script`);l.push(`<script${Q(n)}>${r}<\/script>`)}return{headTags:l.join(`
|
|
4
|
-
`),htmlAttrs:Q(o),bodyAttrs:Q(s)}}function ct(e){return typeof e==`string`?new URL(e,`http://localhost`):e}function lt(){try{return typeof process<`u`&&!!process.env&&process.env.NODE_ENV!==`production`}catch{return!1}}function ut(e,t,n){if(e.startsWith(`/`)&&!e.startsWith(`//`))return{ok:!0,to:e};try{let r=new URL(e,t);return/^https?:$/.test(r.protocol)?r.origin===t.origin?{ok:!0,to:r.pathname+r.search+r.hash}:n?{ok:!0,to:r.href}:{ok:!1}:{ok:!1}}catch{return{ok:!1}}}function dt(e,t){let n=new AbortController,r=()=>n.abort(),i=e?.signal;i&&(i.aborted?r():i.addEventListener(`abort`,r,{once:!0}));let a;return t&&t>0&&(a=setTimeout(r,t)),{signal:n.signal,done:()=>{a!==void 0&&clearTimeout(a),i?.removeEventListener(`abort`,r)}}}function ft(e){try{return new Request(e.toString())}catch{return{url:e.toString(),headers:new Headers}}}async function pt(e,t,n,r,i,a){let o=[],s=a??(e=>o.push(e));try{let a=Promise.resolve(e({params:n,request:r,url:t,signal:i,head:s}));a.catch(()=>{});let c={kind:`data`,data:await Promise.race([a,new Promise((e,t)=>{let n=()=>t(new b(504,`Loader aborted or timed out`));i.aborted?n():i.addEventListener(`abort`,n,{once:!0})})])??{}};return o.length>0&&(c.head=$(o)),c}catch(e){return e instanceof y?{kind:`redirect`,to:e.to,status:e.status}:e instanceof b?{kind:`error`,status:e.status,message:e.message}:(console.error(`[ilha-router] loader failed:`,e),{kind:`error`,status:typeof e?.status==`number`?e.status:500,message:lt()?e?.message??`Loader failed`:`Internal error`})}}function mt(t={}){let n=t.mode??`spa`,r=t.interceptLinks!==!1,c=t.allowExternalRedirects===!0,l=t.loaderTimeout,u=[],d=o(),f=new Map,p=t.notFound??null;R=d,W=p,Ge=c,he=t.viewTransitions===!0;let m=null,v=null,y={route(e,t,n){let r=!!n,i={island:t,pattern:e,loader:n,hasLoader:r};return u.push({pattern:e,island:t,loader:n,hasLoader:r}),a(d,`GET`,e,i),f.set(e,i),y},attachLoader(e,t){let n=f.get(e);if(!n)return console.warn(`[ilha-router] attachLoader("${e}", …): pattern was never registered via .route(). The loader will be ignored.`),y;n.loader=t,n.hasLoader=!0;let r=u.find(t=>t.pattern===e);return r&&(r.loader=t,r.hasLoader=!0),y},clientLoader(e,t){let n=f.get(e);if(!n)return console.warn(`[ilha-router] clientLoader("${e}", …): pattern was never registered via .route(). The loader will be ignored.`),y;n.clientLoader=t,n.hasLoader=!0;let r=u.find(t=>t.pattern===e);return r&&(r.hasLoader=!0),y},errorBoundary(e,t){let n=f.get(e);return n?(n.errorHandler=t,y):(console.warn(`[ilha-router] errorBoundary("${e}", …): pattern was never registered via .route(). The boundary will be ignored.`),y)},markLoader(e){let t=f.get(e);if(!t)return console.warn(`[ilha-router] markLoader("${e}"): pattern was never registered via .route(). The loader marker will be ignored.`),y;t.hasLoader=!0;let n=u.find(t=>t.pattern===e);return n&&(n.hasLoader=!0),y},routes(){return u.map(e=>({...e}))},prime:B,hydrateStatic(e,t={}){if(!_)return()=>{};let n=t.root??document.body;B();let{unmount:r}=i(e,{root:n});return r},mount(t,{hydrate:i=!1,registry:a,interceptLinks:o}={}){if(!_)return console.warn(`[ilha-router] mount() called in a non-browser environment`),()=>{};let c=typeof t==`string`?document.querySelector(t):t;if(!c)return console.warn(`[ilha-router] No element found for selector "${t}"`),()=>{};if(Me(),V=H(),n===`static`)return console.warn(`[ilha-router] router.mount() called in static mode. Use router.hydrateStatic(registry) instead.`),()=>{};let l=!0,u=`scrollRestoration`in history?history.scrollRestoration:null;u!==null&&(history.scrollRestoration=`manual`),m=g().onChange(()=>{if(!l)return;let e=A()+M()+N();Re.set(V,{x:window.scrollX,y:window.scrollY}),V=H(),Me(),He(),Le({from:e,to:A()+M()+N(),type:`pop`})}),v=o??r?We(document):null;let d=null,f=null;if(i){h()===`hash`&&console.warn("[ilha-router] mount({ hydrate: true }) was called in hash mode. SSR + hydration assumes the server can render the active route, but in hash mode the server only ever sees the document URL. Use plain SPA mode (`mount(target)` without `hydrate: true`) for hash-mode apps.");let t=c.querySelector(`[data-router-view]`)??c,n=L(),r=a?pe(a):void 0,i=0,o=e.render(()=>{let e=L();if(e!==n){let o=++i;f?.abort(),f=new AbortController;let s=f.signal;queueMicrotask(async()=>{if(o!==i)return;let c=I();d?.(),d=null;try{let n=g().readLocation();d=await ve(e,t,n.pathname+n.search,s,a,r)}catch(e){if(e?.name===`AbortError`)return;console.error(`[ilha-router] navigation failed:`,e),t.innerHTML=`<div data-router-view data-router-error="500"></div>`;return}finally{c()}n=e})}return``}),p=document.createElement(`div`);p.style.display=`none`,c.appendChild(p);let _=o.mount(p);return(async()=>{let e=L();if(!e)return;let n=g().readLocation(),o=n.pathname+n.search,c=s(R,`GET`,n.pathname);if(c?.data?.clientLoader){let n=++i,s=new AbortController;f=s;try{let c=await ve(e,t,o,s.signal,a,r);n===i?d=c:c()}catch(e){e?.name!==`AbortError`&&console.error(`[ilha-router] initial client loader render failed:`,e)}return}let u=c?.data?.hasLoader?await _e(o):{kind:`data`,data:{}};if(u.kind===`redirect`||u.kind===`error`)return;let p=u.kind===`data`?u.data:{},m={entries:[...u.kind===`data`?u.headEntries??[]:[]]};await Z(m,()=>e.toString(p)),l&&X(m.entries)})(),F=async()=>{let e=L(),o=++i;f?.abort();let s=new AbortController;f=s;let c=I();try{let c=g().readLocation(),l=await ve(e,t,c.pathname+c.search,s.signal,a,r);o===i?(d?.(),d=l,n=e):l()}catch(e){e?.name!==`AbortError`&&console.error(`[ilha-router] invalidate failed:`,e)}finally{c()}},()=>{l=!1,++i,F=null,f?.abort(),_(),p.remove(),d?.(),v?.(),m?.(),v=null,m=null,u!==null&&(history.scrollRestoration=u)}}let p=null,y=null,b=0;d=G.mount(c);async function x(e,t){if(p?.(),p=null,y=e,!e){let e=c?.querySelector(`[data-router-not-found]`);W&&e&&(p=W.mount(e));return}let n=c?.querySelector(`[data-router-view]`);if(!n)return;let r=g().readLocation(),i=s(R,`GET`,r.pathname),a=i?.data?.hasLoader?await _e(r.pathname+r.search,t):{kind:`data`,data:{}};if(t.aborted)return;if(a.kind===`redirect`){Ue(a.to);return}if(a.kind===`error`){let e=i?.data?.errorHandler;if(e){p=await E(()=>ye(e,n,a.status,a.message));return}let t=it(a.message);await E(()=>{n.innerHTML=`<div data-router-error="${a.status}">${t}</div>`});return}let o=a.kind===`data`?a.data:{},l={entries:[...a.kind===`data`?a.headEntries??[]:[]]},u=await Z(l,()=>e.toString(o));p=await E(()=>(X(l.entries),n.innerHTML=u,e.mount(n,o)))}f=new AbortController,x(L(),f.signal).catch(e=>{e?.name!==`AbortError`&&console.error(`[ilha-router] initial mount failed:`,e)});let ee=e.render(()=>{let e=L();if(e!==y){let t=++b;f?.abort(),f=new AbortController;let n=f.signal;queueMicrotask(()=>{if(t!==b)return;let r=I();x(e,n).catch(e=>{e?.name!==`AbortError`&&console.error(`[ilha-router] navigation failed:`,e)}).finally(r)})}return``}),S=document.createElement(`div`);S.style.display=`none`,c.appendChild(S);let C=ee.mount(S);return F=async()=>{++b,f?.abort(),f=new AbortController;let e=I();try{await x(L(),f.signal)}catch(e){e?.name!==`AbortError`&&console.error(`[ilha-router] invalidate failed:`,e)}finally{e()}},()=>{l=!1,++b,F=null,f?.abort(),p?.(),C(),S.remove(),d?.(),v?.(),m?.(),v=null,m=null,u!==null&&(history.scrollRestoration=u)}},render(e){let t=()=>(je(e,d),G.toString());return!_&&O?O.run(Se(),t):t()},async renderHydratable(e,t,n={},r){let i=await this.renderResponse(e,t,n,r);return i.kind===`html`||i.kind===`error`?i.html:`<meta http-equiv="refresh" content="0; url=${rt(i.to)}">`},async renderResponse(e,t,n={},r){if(!_){let i=await xe();if(!i.getStore())return i.run(Se(),()=>b(e,t,n,r))}return b(e,t,n,r)},async runLoader(e,t){let n=ct(e),r=s(d,`GET`,n.pathname);if(!r?.data?.island)return{kind:`not-found`};if(!r.data.loader)return{kind:`data`,data:{}};let i=z(r.params),a=t??ft(n),o=dt(t,l),u={entries:[]};try{let e=await pt(r.data.loader,n,i,a,o.signal,e=>u.entries.push(e));if(e.kind===`redirect`){let t=ut(e.to,n,c);return t.ok?{...e,to:t.to}:(console.warn(`[ilha-router] Blocked unsafe redirect target "${e.to}". Set allowExternalRedirects: true to allow cross-origin redirects.`),{kind:`error`,status:500,message:`Unsafe redirect target`})}return e.kind!==`data`||u.entries.length===0?e:{...e,head:$(u.entries),headEntries:u.entries}}finally{o.done()}},hydrate(e,t={}){if(!_)return console.warn(`[ilha-router] hydrate() called in a non-browser environment`),()=>{};let n=t.root??document.body,r=t.target??n;B();let{unmount:a}=i(e,{root:n}),o=this.mount(r,{hydrate:!0,registry:e,interceptLinks:t.interceptLinks});return()=>{a(),o()}}};async function b(e,t,n={},r){let{baseHead:i,...a}=n,o=ct(e);je(o,d);let u=s(d,`GET`,o.pathname),f=u?.data?.island??null;if(!f){let e={entries:i?[i]:[]};return p?{kind:`html`,html:`<div data-router-view data-router-not-found>${await Z(e,()=>p.toString())}</div>`,status:404,head:$(e.entries)}:{kind:`html`,html:`<div data-router-empty></div>`,status:404,head:i?$([i]):void 0}}let m={entries:i?[i]:[]},h={};if(u?.data?.loader){let e=r??ft(o),t=dt(r,l),n;try{n=await pt(u.data.loader,o,j(),e,t.signal,e=>m.entries.push(e))}finally{t.done()}if(n.kind===`redirect`){let e=ut(n.to,o,c);if(!e.ok)console.warn(`[ilha-router] Blocked unsafe redirect target "${n.to}". Set allowExternalRedirects: true to allow cross-origin redirects.`),n={kind:`error`,status:500,message:`Unsafe redirect target`};else return{kind:`redirect`,to:e.to,status:n.status}}if(n.kind===`error`){let e=u.data.errorHandler;if(e)try{let t=e({message:n.message,status:n.status},{path:A(),params:j(),search:M(),hash:N()}),r=await Z(m,()=>t.toString());return{kind:`error`,status:n.status,message:n.message,html:`<div data-router-view data-router-error="${n.status}">${r}</div>`,head:$(m.entries)}}catch(e){console.error(`[ilha-router] error boundary threw while rendering a loader error:`,e)}let t=it(n.message),r=`<div data-router-view data-router-error="${n.status}">${t}</div>`;return{kind:`error`,status:n.status,message:n.message,html:r,head:$(m.entries)}}h=n.data}let g=pe(t).get(f);return g?{kind:`html`,html:`<div data-router-view>${await Z(m,()=>f.hydratable(h,{name:g,as:`div`,snapshot:!0,...a}))}</div>`,head:$(m.entries)}:(console.warn(`[ilha-router] renderHydratable: active island for "${A()}" is not in the registry. Falling back to plain SSR — the island will not be interactive on the client.`),{kind:`html`,html:`<div data-router-view>${await Z(m,()=>f.toString(h))}</div>`,head:$(m.entries)})}return y}var ht={router:mt,navigate:U,useRoute:ke,isActive:qe,enableLinkInterception:We,prime:B,prefetch:D,beforeNavigate:Fe,afterNavigate:Ie,RouterView:G,RouterLink:Ke,loader:v,redirect:x,error:ee,composeLoaders:S,head:$e};export{ue as A,A as C,ht as D,$ as E,m as M,ke as O,j as S,mt as T,De as _,G as a,x as b,S as c,ee as d,$e as f,U as g,v as h,Ke as i,h as j,de as k,fe as l,qe as m,b as n,Ie as o,Oe as p,y as r,Fe as s,me as t,We as u,D as v,M as w,N as x,B as y};
|