@aihu/app 0.1.1 → 0.1.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/README.md +7 -7
- package/dist/client.d.ts +9 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ npm install @aihu/app
|
|
|
21
21
|
bun add @aihu/app
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
<sub><i>Auto-generated against `@aihu/app@0.1.1
|
|
24
|
+
<sub><i>Auto-generated against `@aihu/app@0.1.1`.</i></sub>
|
|
25
25
|
|
|
26
26
|
<!-- END_AUTOGEN: install -->
|
|
27
27
|
|
|
@@ -34,11 +34,11 @@ bun add @aihu/app
|
|
|
34
34
|
|---|---|
|
|
35
35
|
| **Version** | `0.1.1` |
|
|
36
36
|
| **Tier** | B — Meta-framework — top-level integration of runtime, router, adapter |
|
|
37
|
-
| **Bundle size** |
|
|
37
|
+
| **Bundle size** | 764 B (gz) — limit 800 B |
|
|
38
38
|
| **Published files** | 3 entries |
|
|
39
39
|
| **License** | MIT |
|
|
40
40
|
|
|
41
|
-
<sub><i>Auto-generated against `@aihu/app@0.1.1
|
|
41
|
+
<sub><i>Auto-generated against `@aihu/app@0.1.1`.</i></sub>
|
|
42
42
|
|
|
43
43
|
<!-- END_AUTOGEN: stats -->
|
|
44
44
|
|
|
@@ -52,7 +52,7 @@ bun add @aihu/app
|
|
|
52
52
|
| `.` | `./dist/index.js` | `—` |
|
|
53
53
|
| `./client` | `./dist/client.js` | `—` |
|
|
54
54
|
|
|
55
|
-
<sub><i>Auto-generated against `@aihu/app@0.1.1
|
|
55
|
+
<sub><i>Auto-generated against `@aihu/app@0.1.1`.</i></sub>
|
|
56
56
|
|
|
57
57
|
<!-- END_AUTOGEN: exports -->
|
|
58
58
|
|
|
@@ -69,7 +69,7 @@ bun add @aihu/app
|
|
|
69
69
|
- `@aihu/signals` — `workspace:*`
|
|
70
70
|
- `vite` — `>=5.0.0`
|
|
71
71
|
|
|
72
|
-
<sub><i>Auto-generated against `@aihu/app@0.1.1
|
|
72
|
+
<sub><i>Auto-generated against `@aihu/app@0.1.1`.</i></sub>
|
|
73
73
|
|
|
74
74
|
<!-- END_AUTOGEN: deps -->
|
|
75
75
|
|
|
@@ -83,7 +83,7 @@ bun add @aihu/app
|
|
|
83
83
|
- [@aihu/adapter-cloudflare](../adapter-cloudflare)
|
|
84
84
|
- [Aihu framework root](../../README.md)
|
|
85
85
|
|
|
86
|
-
<sub><i>Auto-generated against `@aihu/app@0.1.1
|
|
86
|
+
<sub><i>Auto-generated against `@aihu/app@0.1.1`.</i></sub>
|
|
87
87
|
|
|
88
88
|
<!-- END_AUTOGEN: see-also -->
|
|
89
89
|
|
|
@@ -94,6 +94,6 @@ bun add @aihu/app
|
|
|
94
94
|
|
|
95
95
|
MIT — see [LICENSE](../../LICENSE).
|
|
96
96
|
|
|
97
|
-
<sub><i>Auto-generated against `@aihu/app@0.1.1
|
|
97
|
+
<sub><i>Auto-generated against `@aihu/app@0.1.1`.</i></sub>
|
|
98
98
|
|
|
99
99
|
<!-- END_AUTOGEN: license -->
|
package/dist/client.d.ts
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
interface AppConfig {
|
|
4
4
|
/** Id of the outlet element in index.html. Default: 'outlet' */
|
|
5
5
|
outletId?: string;
|
|
6
|
+
/**
|
|
7
|
+
* App-level values hoisted into globalThis before any component runs.
|
|
8
|
+
* Use this for singletons (db clients, auth helpers, i18n) that are
|
|
9
|
+
* referenced as bare identifiers inside @state blocks.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* createApp({ provide: { supabase, checkAuth } })
|
|
13
|
+
*/
|
|
14
|
+
provide?: Record<string, unknown>;
|
|
6
15
|
}
|
|
7
16
|
/**
|
|
8
17
|
* Bootstrap the aihu SPA.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","names":[],"sources":["../src/client.ts"],"mappings":";;UAQiB,SAAA;EAAS;EAExB,QAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","names":[],"sources":["../src/client.ts"],"mappings":";;UAQiB,SAAA;EAAS;EAExB,QAAA;EASgB;;;;;;AAgBlB;;EAhBE,OAAA,GAAU,MAAA;AAAA;;;;;;;;;;;;;;iBAgBI,SAAA,CAAU,MAAA,GAAS,SAAA"}
|
package/dist/client.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"virtual:aihu-routes";import{mount as t}from"@aihu/arbor";import{createRouter as n}from"@aihu/router";import{_setMount as r,_setSignal as i}from"@aihu/runtime";import{signal as a}from"@aihu/signals";function o(o){r(t),i(a);let s=o?.outletId??`outlet`,c=document.getElementById(s);if(!c)throw Error(`@aihu/app: no element with id="${s}" found. Add <div id="${s}"></div> to your index.html`);let l=c,u=n(e);async function d(t){if(!t){let t=e.find(e=>e.pattern===`*`||e.name===`not-found`);if(t){await t.module();let e=t.name;if(e
|
|
1
|
+
import e from"virtual:aihu-routes";import{mount as t}from"@aihu/arbor";import{createRouter as n}from"@aihu/router";import{_setMount as r,_setSignal as i}from"@aihu/runtime";import{signal as a}from"@aihu/signals";function o(o){o?.provide&&Object.assign(globalThis,o.provide),r(t),i(a);let s=o?.outletId??`outlet`,c=document.getElementById(s);if(!c)throw Error(`@aihu/app: no element with id="${s}" found. Add <div id="${s}"></div> to your index.html`);let l=c,u=n(e);async function d(t){if(!t){let t=e.find(e=>e.pattern===`*`||e.name===`not-found`);if(t){await t.module();let e=t.name;if(e?.includes(`-`)){l.replaceChildren(document.createElement(e));return}}let n=document.createElement(`p`);n.style.cssText=`font-family:system-ui;padding:2rem;color:#888`,n.textContent=`404 — page not found`,l.replaceChildren(n);return}await t.route.module();let n=t.route.name;if(!n?.includes(`-`))return;let r=document.createElement(n);if(t.params)for(let[e,n]of Object.entries(t.params))r.setAttribute(e,String(n));l.replaceChildren(r)}d(u.match(location.pathname)),document.addEventListener(`click`,e=>{let t=e.target.closest(`a`);if(!t)return;let n=t.getAttribute(`href`);!n||n.startsWith(`http`)||n.startsWith(`//`)||n.startsWith(`mailto:`)||(e.preventDefault(),history.pushState({},``,n),d(u.match(location.pathname)))}),window.addEventListener(`popstate`,()=>{d(u.match(location.pathname))})}export{o as createApp};
|
|
2
2
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import routes from 'virtual:aihu-routes'\nimport { mount } from '@aihu/arbor'\nimport type { MatchResult, RouteDefinition } from '@aihu/router'\nimport { createRouter } from '@aihu/router'\nimport { _setMount, _setSignal } from '@aihu/runtime'\nimport { signal } from '@aihu/signals'\n\n/** Inline runtime configuration accepted by createApp(). All fields optional. */\nexport interface AppConfig {\n /** Id of the outlet element in index.html. Default: 'outlet' */\n outletId?: string\n}\n\n/**\n * Bootstrap the aihu SPA.\n *\n * - Wires the aihu runtime (mount + signal) — idempotent if called multiple times\n * - Creates the router from virtual:aihu-routes\n * - Renders the current route\n * - Installs SPA click interception and popstate listeners\n *\n * @example\n * // src/main.ts\n * import { createApp } from '@aihu/app/client'\n * createApp()\n */\nexport function createApp(config?: AppConfig): void {\n // Wire runtime — null-guarded in @aihu/runtime, safe to call multiple times\n _setMount(mount)\n _setSignal(signal as Parameters<typeof _setSignal>[0])\n\n const outletId = config?.outletId ?? 'outlet'\n const outletEl = document.getElementById(outletId)\n if (!outletEl) {\n throw new Error(\n `@aihu/app: no element with id=\"${outletId}\" found. Add <div id=\"${outletId}\"></div> to your index.html`,\n )\n }\n const outlet: HTMLElement = outletEl\n\n const router = createRouter(routes)\n\n async function render(match: MatchResult | null): Promise<void> {\n if (!match) {\n // Check for a 404/not-found route by convention before falling back inline\n const notFoundRoute = (routes as RouteDefinition[]).find(\n (r) => r.pattern === '*' || r.name === 'not-found',\n )\n if (notFoundRoute) {\n await notFoundRoute.module()\n const tag = notFoundRoute.name\n if (tag
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import routes from 'virtual:aihu-routes'\nimport { mount } from '@aihu/arbor'\nimport type { MatchResult, RouteDefinition } from '@aihu/router'\nimport { createRouter } from '@aihu/router'\nimport { _setMount, _setSignal } from '@aihu/runtime'\nimport { signal } from '@aihu/signals'\n\n/** Inline runtime configuration accepted by createApp(). All fields optional. */\nexport interface AppConfig {\n /** Id of the outlet element in index.html. Default: 'outlet' */\n outletId?: string\n /**\n * App-level values hoisted into globalThis before any component runs.\n * Use this for singletons (db clients, auth helpers, i18n) that are\n * referenced as bare identifiers inside @state blocks.\n *\n * @example\n * createApp({ provide: { supabase, checkAuth } })\n */\n provide?: Record<string, unknown>\n}\n\n/**\n * Bootstrap the aihu SPA.\n *\n * - Wires the aihu runtime (mount + signal) — idempotent if called multiple times\n * - Creates the router from virtual:aihu-routes\n * - Renders the current route\n * - Installs SPA click interception and popstate listeners\n *\n * @example\n * // src/main.ts\n * import { createApp } from '@aihu/app/client'\n * createApp()\n */\nexport function createApp(config?: AppConfig): void {\n // Hoist provided values into globalThis before any component runs so that\n // @state blocks can reference them as bare identifiers.\n if (config?.provide) {\n Object.assign(globalThis, config.provide)\n }\n\n // Wire runtime — null-guarded in @aihu/runtime, safe to call multiple times\n _setMount(mount)\n _setSignal(signal as Parameters<typeof _setSignal>[0])\n\n const outletId = config?.outletId ?? 'outlet'\n const outletEl = document.getElementById(outletId)\n if (!outletEl) {\n throw new Error(\n `@aihu/app: no element with id=\"${outletId}\" found. Add <div id=\"${outletId}\"></div> to your index.html`,\n )\n }\n const outlet: HTMLElement = outletEl\n\n const router = createRouter(routes)\n\n async function render(match: MatchResult | null): Promise<void> {\n if (!match) {\n // Check for a 404/not-found route by convention before falling back inline\n const notFoundRoute = (routes as RouteDefinition[]).find(\n (r) => r.pattern === '*' || r.name === 'not-found',\n )\n if (notFoundRoute) {\n await notFoundRoute.module()\n const tag = notFoundRoute.name\n if (tag?.includes('-')) {\n outlet.replaceChildren(document.createElement(tag))\n return\n }\n }\n // Inline fallback 404\n const p = document.createElement('p')\n p.style.cssText = 'font-family:system-ui;padding:2rem;color:#888'\n p.textContent = '404 — page not found'\n outlet.replaceChildren(p)\n return\n }\n\n // Import the page module — registers its custom element + auto-wires runtime\n await match.route.module()\n const tag = match.route.name\n if (!tag?.includes('-')) return\n\n const el = document.createElement(tag)\n\n // Flat per-attribute route params (A4 protocol — replaces JSON route attribute)\n if (match.params) {\n for (const [key, val] of Object.entries(match.params)) {\n el.setAttribute(key, String(val))\n }\n }\n\n outlet.replaceChildren(el)\n }\n\n // Initial render\n render(router.match(location.pathname))\n\n // SPA click interception — handles <a> links within the app\n document.addEventListener('click', (e) => {\n const a = (e.target as Element).closest('a') as HTMLAnchorElement | null\n if (!a) return\n const href = a.getAttribute('href')\n if (!href || href.startsWith('http') || href.startsWith('//') || href.startsWith('mailto:'))\n return\n e.preventDefault()\n history.pushState({}, '', href)\n render(router.match(location.pathname))\n })\n\n // Browser back/forward\n window.addEventListener('popstate', () => {\n render(router.match(location.pathname))\n })\n}\n"],"mappings":"oNAmCA,SAAgB,EAAU,EAA0B,CAG9C,GAAQ,SACV,OAAO,OAAO,WAAY,EAAO,QAAQ,CAI3C,EAAU,EAAM,CAChB,EAAW,EAA2C,CAEtD,IAAM,EAAW,GAAQ,UAAY,SAC/B,EAAW,SAAS,eAAe,EAAS,CAClD,GAAI,CAAC,EACH,MAAU,MACR,kCAAkC,EAAS,wBAAwB,EAAS,6BAC7E,CAEH,IAAM,EAAsB,EAEtB,EAAS,EAAa,EAAO,CAEnC,eAAe,EAAO,EAA0C,CAC9D,GAAI,CAAC,EAAO,CAEV,IAAM,EAAiB,EAA6B,KACjD,GAAM,EAAE,UAAY,KAAO,EAAE,OAAS,YACxC,CACD,GAAI,EAAe,CACjB,MAAM,EAAc,QAAQ,CAC5B,IAAM,EAAM,EAAc,KAC1B,GAAI,GAAK,SAAS,IAAI,CAAE,CACtB,EAAO,gBAAgB,SAAS,cAAc,EAAI,CAAC,CACnD,QAIJ,IAAM,EAAI,SAAS,cAAc,IAAI,CACrC,EAAE,MAAM,QAAU,gDAClB,EAAE,YAAc,uBAChB,EAAO,gBAAgB,EAAE,CACzB,OAIF,MAAM,EAAM,MAAM,QAAQ,CAC1B,IAAM,EAAM,EAAM,MAAM,KACxB,GAAI,CAAC,GAAK,SAAS,IAAI,CAAE,OAEzB,IAAM,EAAK,SAAS,cAAc,EAAI,CAGtC,GAAI,EAAM,OACR,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,EAAM,OAAO,CACnD,EAAG,aAAa,EAAK,OAAO,EAAI,CAAC,CAIrC,EAAO,gBAAgB,EAAG,CAI5B,EAAO,EAAO,MAAM,SAAS,SAAS,CAAC,CAGvC,SAAS,iBAAiB,QAAU,GAAM,CACxC,IAAM,EAAK,EAAE,OAAmB,QAAQ,IAAI,CAC5C,GAAI,CAAC,EAAG,OACR,IAAM,EAAO,EAAE,aAAa,OAAO,CAC/B,CAAC,GAAQ,EAAK,WAAW,OAAO,EAAI,EAAK,WAAW,KAAK,EAAI,EAAK,WAAW,UAAU,GAE3F,EAAE,gBAAgB,CAClB,QAAQ,UAAU,EAAE,CAAE,GAAI,EAAK,CAC/B,EAAO,EAAO,MAAM,SAAS,SAAS,CAAC,GACvC,CAGF,OAAO,iBAAiB,eAAkB,CACxC,EAAO,EAAO,MAAM,SAAS,SAAS,CAAC,EACvC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -63,6 +63,15 @@ interface AihuConfig {
|
|
|
63
63
|
readonly plugins?: ReadonlyArray<AihuPlugin>;
|
|
64
64
|
/** Runtime configuration split — public values are inlined in the client bundle. */
|
|
65
65
|
readonly runtimeConfig?: RuntimeConfig;
|
|
66
|
+
/**
|
|
67
|
+
* App-level values made available to all components as bare identifiers.
|
|
68
|
+
* Declared here for documentation and future build-time validation; the
|
|
69
|
+
* values are hoisted into globalThis by createApp() at runtime.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* export default defineConfig({ provide: { supabase, checkAuth } })
|
|
73
|
+
*/
|
|
74
|
+
readonly provide?: Record<string, unknown>;
|
|
66
75
|
/** HTML <head> metadata. */
|
|
67
76
|
readonly app?: AppHeadConfig;
|
|
68
77
|
/** Passthrough to Vite's UserConfig. Merged via Vite's config() hook. */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/adapter.ts","../src/vite-plugin.ts"],"mappings":";;;;;;KAIY,UAAA;AAAA,UAEK,SAAA;EAFL;EAAA,SAID,KAAA;;WAEA,OAAA;EANW;EAAA,SAQX,MAAA;AAAA;;UAIM,aAAA;EAAA,SACN,MAAA,GAAS,MAAA;EAPT;EAAA,SASA,OAAA,GAAU,MAAA;AAAA;AAAA,UAGJ,UAAA;EAAA,SACN,KAAA;EAPmB;EAAA,SASnB,OAAA;EANgB;EAAA,SAQhB,QAAA;EAAA,SACA,IAAA,GAAO,aAAA,CAAc,MAAA;AAAA;AAAA,UAGf,aAAA;EAAA,SACN,IAAA,GAAO,UAAA;AAAA;AAVlB;AAAA,KAcY,eAAA,GAAkB,IAAA,CAAK,UAAA;;KAGvB,UAAA,GAAa,MAAA;;KAGb,oBAAA,GAAoB,wBAAA,CAAmC,oBAAA;;UAGlD,YAAA;EAjBC;;;;AAGlB;;;;EAHkB,SA0BP,eAAA;AAAA;AAAA,UAGM,UAAA;;WAEN,GAAA,GAAM,SAAA;EAvB4B;AAG7C;;;EAH6C,SA4BlC,MAAA,GAAS,UAAA;EAzBW;AAG/B;;;EAH+B,SA8BpB,OAAA,GAAU,aAAA,CAAc,UAAA;EA3BoD;EAAA,SA6B5E,aAAA,GAAgB,aAAA;EA1BE;EAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/adapter.ts","../src/vite-plugin.ts"],"mappings":";;;;;;KAIY,UAAA;AAAA,UAEK,SAAA;EAFL;EAAA,SAID,KAAA;;WAEA,OAAA;EANW;EAAA,SAQX,MAAA;AAAA;;UAIM,aAAA;EAAA,SACN,MAAA,GAAS,MAAA;EAPT;EAAA,SASA,OAAA,GAAU,MAAA;AAAA;AAAA,UAGJ,UAAA;EAAA,SACN,KAAA;EAPmB;EAAA,SASnB,OAAA;EANgB;EAAA,SAQhB,QAAA;EAAA,SACA,IAAA,GAAO,aAAA,CAAc,MAAA;AAAA;AAAA,UAGf,aAAA;EAAA,SACN,IAAA,GAAO,UAAA;AAAA;AAVlB;AAAA,KAcY,eAAA,GAAkB,IAAA,CAAK,UAAA;;KAGvB,UAAA,GAAa,MAAA;;KAGb,oBAAA,GAAoB,wBAAA,CAAmC,oBAAA;;UAGlD,YAAA;EAjBC;;;;AAGlB;;;;EAHkB,SA0BP,eAAA;AAAA;AAAA,UAGM,UAAA;;WAEN,GAAA,GAAM,SAAA;EAvB4B;AAG7C;;;EAH6C,SA4BlC,MAAA,GAAS,UAAA;EAzBW;AAG/B;;;EAH+B,SA8BpB,OAAA,GAAU,aAAA,CAAc,UAAA;EA3BoD;EAAA,SA6B5E,aAAA,GAAgB,aAAA;EA1BE;;;;AAY7B;;;;EAZ6B,SAmClB,OAAA,GAAU,MAAA;EAXc;EAAA,SAaxB,GAAA,GAAM,aAAA;EAXU;EAAA,SAahB,IAAA,GAAO,eAAA;EAFD;;;;;EAAA,SAQN,cAAA,GAAiB,oBAAA;EAWI;;;;;EAAA,SALrB,OAAA,GAAU,WAAA;EA3BA;;;;EAAA,SAgCV,MAAA,GAAS,YAAA;AAAA;;cAIP,eAAA,SAAwB,KAAA;EAAA,SAGxB,IAAA;EAAA,SACA,KAAA;cAFT,OAAA,UACS,IAAA,2DACA,KAAA;AAAA;;;;;;;AAJb;;;;;;;iBAwBgB,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;;;;UC9HjC,0BAAA;;;ADCjB;;ECIE,eAAA;EDJoB;;AAEtB;;;ECQE,eAAA;AAAA;;;;;UAOe,cAAA;EDLa;EAAA,SCOnB,MAAA;EDJgB;EAAA,SCMhB,IAAA;EDRS;;;;EAAA,SCaT,MAAA,EAAQ,aAAA,CAAc,eAAA;EDRhB;EAAA,SCUN,MAAA,EAFqB,UAAA;;;;;EAQ9B,QAAA,CAAS,IAAA,UAAc,OAAA,WAAkB,OAAA;EDVhC;;;ECeT,IAAA,CAAK,GAAA,UAAa,IAAA,WAAe,OAAA;EDfG;AAGtC;;ECiBE,SAAA,CAAU,YAAA,UAAsB,OAAA,WAAkB,OAAA;EDhBzC;;AAIX;;;;;ECqBE,mBAAA,CAAoB,OAAA,GAAU,0BAAA;AAAA;;;;ADfhC;;;;;AAGA;;;;;UC4BiB,WAAA;EDhBU;;;;EAAA,SCqBhB,IAAA;EDTU;;;;;;ECiBnB,KAAA,CAAM,OAAA,EAAS,cAAA,GAAiB,OAAA;AAAA;;;;;;ADlFlC;;;;;AAEA;;;;;;;;;AAUA;;;;;;;;;;iBEyGgB,cAAA,CAAe,MAAA,GAAS,UAAA,GAAa,MAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
`)}}}function p(e){let t={pagesDir:e?.dir?.pages??`pages`,layoutsDir:e?.dir?.layouts??`src/layouts`},n,r=e?.agentReadiness;if(r){let{viteAgentReadinessIntegration:e}=c(`@aihu/agent-readiness`);n=e(r)}else n={name:`aihu-agent-readiness-disabled`};let i={name:`aihu-vite-passthrough`,config(){return e?.vite??{}}},l=null,u={name:`aihu-adapter`,apply:`build`,configResolved(e){l=e},async closeBundle(){let t=e?.adapter;if(!t||!l)return;let n=e?.dir?.pages??`pages`,{routes:r}=o(l.root,n),i=f(l,r,e);try{await t.adapt(i)}catch(e){let n=e instanceof Error?e.message:String(e);this.error(`[@aihu/app] Adapter '${t.name}' failed: ${n}`)}}};return[a(),s(t),n,...e?.plugins??[],i,u]}export{l as AihuConfigError,u as defineConfig,p as viteAihuPlugin};
|
|
1
|
+
import{cp as e,mkdir as t,writeFile as n}from"node:fs/promises";import{dirname as r,resolve as i}from"node:path";import{aihuCompilerPlugin as a}from"@aihu/compiler";import{scanPages as o,viteRouterIntegration as s}from"@aihu/router/plugin";var c=(e=>typeof require<`u`?require:typeof Proxy<`u`?new Proxy(e,{get:(e,t)=>(typeof require<`u`?require:e)[t]}):e)(function(e){if(typeof require<`u`)return require.apply(this,arguments);throw Error('Calling `require` for "'+e+"\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.")}),l=class extends Error{constructor(e,t,n){super(e),this.code=t,this.field=n,this.name=`AihuConfigError`}};function u(e){if(e.output&&e.output!==`spa`)throw new l(`output mode '${e.output}' is not supported in V0 (only 'spa')`,`INVALID_OUTPUT_MODE`,`output`);if(e.dir?.pages!==void 0&&typeof e.dir.pages!=`string`)throw new l(`dir.pages must be a string`,`INVALID_DIR`,`dir.pages`);if(e.dir?.layouts!==void 0&&typeof e.dir.layouts!=`string`)throw new l(`dir.layouts must be a string`,`INVALID_DIR`,`dir.layouts`);return e}function d(e,t,n){let r=e.replace(/\\/g,`/`).replace(RegExp(`^.*?${n}/`),``).replace(/\.[^.]+$/,``).split(`/`).filter(Boolean);r.length>0&&r[r.length-1]===`index`&&r.pop();let i=r.map(e=>e.startsWith(`[...`)&&e.endsWith(`]`)?{kind:`catchall`}:e.startsWith(`[`)&&e.endsWith(`]`)?{kind:`param`,name:e.slice(1,-1)}:{kind:`static`,path:e});return{pattern:i.length===0?`/`:`/`+i.map(e=>e.kind===`static`?e.path:e.kind===`param`?`:${e.name}`:`*`).join(`/`),segments:i,module:()=>Promise.resolve({default:null})}}function f(a,o,s){let c=i(a.root,a.build.outDir),l=a.root,u=s?.dir?.pages??`pages`;return{outDir:c,root:l,routes:o.map(e=>d(e,l,u)),config:s??{},async emitFile(e,a){let o=i(c,e);await t(r(o),{recursive:!0}),await n(o,a,`utf8`)},async copy(n,i){await t(r(i),{recursive:!0}),await e(n,i,{recursive:!0,force:!0})},async writeFile(e,i){await t(r(e),{recursive:!0}),await n(e,i,`utf8`)},createHandlerSource(e){let t=e?.routesSpecifier??`./routes-manifest.js`;return[`// AUTO-GENERATED — do not edit`,`import { createRequestRouter } from '${e?.serverSpecifier??`@aihu/server`}'`,`import routes from '${t}'`,`const _manifest = { routes }`,`const _handler = createRequestRouter(_manifest)`,`export { _handler as handler }`].join(`
|
|
2
|
+
`)}}}function p(e){let t={pagesDir:e?.dir?.pages??`pages`,layoutsDir:e?.dir?.layouts??`src/layouts`},n,r=e?.agentReadiness;if(r){let{viteAgentReadinessIntegration:e}=c(`@aihu/agent-readiness`);n=e(r)}else n={name:`aihu-agent-readiness-disabled`};let i={name:`aihu-vite-passthrough`,config(){return e?.vite??{}}},l=null,u={name:`aihu-adapter`,apply:`build`,configResolved(e){l=e},async closeBundle(){let t=e?.adapter;if(!t||!l)return;let n=e?.dir?.pages??`pages`,{routes:r}=o(l.root,n),i=f(l,r,e);try{await t.adapt(i)}catch(e){let n=e instanceof Error?e.message:String(e);this.error(`[@aihu/app] Adapter '${t.name}' failed: ${n}`)}}};return[a({islands:!1}),s(t),n,...e?.plugins??[],i,u]}export{l as AihuConfigError,u as defineConfig,p as viteAihuPlugin};
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["resolvePath","fsWriteFile"],"sources":["../src/config.ts","../src/vite-plugin.ts"],"sourcesContent":["import type { Plugin, UserConfig } from 'vite'\nimport type { AihuAdapter } from './adapter.ts'\n\n/** V0: SPA output only. More modes (ssr, static, hybrid) in V1+. */\nexport type OutputMode = 'spa'\n\nexport interface DirConfig {\n /** Directory to scan for page routes. Default: 'pages' */\n readonly pages?: string\n /** Directory to scan for layout files. Default: 'src/layouts' */\n readonly layouts?: string\n /** Public static assets directory. Default: 'public' */\n readonly public?: string\n}\n\n/** Runtime configuration split. Public values are safe to expose to the client. */\nexport interface RuntimeConfig {\n readonly public?: Record<string, unknown>\n /** V0: accepted but ignored at runtime (server-side enforcement deferred to V1). */\n readonly private?: Record<string, unknown>\n}\n\nexport interface HeadConfig {\n readonly title?: string\n /** Default: 'UTF-8' */\n readonly charset?: string\n /** Default: 'width=device-width, initial-scale=1' */\n readonly viewport?: string\n readonly meta?: ReadonlyArray<Record<string, string>>\n}\n\nexport interface AppHeadConfig {\n readonly head?: HeadConfig\n}\n\n/** Vite config fields that can be safely merged (excludes plugins — use AihuConfig.plugins). */\nexport type VitePassthrough = Omit<UserConfig, 'plugins'>\n\n/** A Aihu plugin is structurally identical to a Vite plugin (V0). */\nexport type AihuPlugin = Plugin\n\n/** Type-only import — not bundled when agentReadiness is absent. */\nexport type AgentReadinessConfig = import('@aihu/agent-readiness').AgentReadinessConfig\n\n/** Router-related app config (arch-5 M1, RFC-A5-012). */\nexport interface RouterConfig {\n /**\n * When `true`, `<$link>` navigation wraps in `document.startViewTransition()`\n * if the browser supports the View Transitions API. No-op in unsupported\n * browsers (graceful degradation). Default: `false`.\n *\n * SSR safety: the wrapping is browser-only — server-rendered HTML is\n * unchanged, and hydration is unaffected.\n */\n readonly viewTransitions?: boolean\n}\n\nexport interface AihuConfig {\n /** Directory layout overrides. */\n readonly dir?: DirConfig\n /**\n * Output mode. V0 supports 'spa' only.\n * defineConfig throws AihuConfigError for any other value.\n */\n readonly output?: OutputMode\n /**\n * Aihu plugins. Order is preserved.\n * Appended after the three framework plugins (compiler, router, agent-readiness).\n */\n readonly plugins?: ReadonlyArray<AihuPlugin>\n /** Runtime configuration split — public values are inlined in the client bundle. */\n readonly runtimeConfig?: RuntimeConfig\n /** HTML <head> metadata. */\n readonly app?: AppHeadConfig\n /** Passthrough to Vite's UserConfig. Merged via Vite's config() hook. */\n readonly vite?: VitePassthrough\n /**\n * Opt-in agent-readiness integration.\n * Requires { name: string } at minimum.\n * When absent or false, a no-op plugin is substituted.\n */\n readonly agentReadiness?: AgentReadinessConfig | false\n /**\n * Deployment adapter. Transforms the Vite build output into the target\n * platform's required format. Called after vite build completes.\n * When absent, no post-build transformation is applied (manual deployment).\n */\n readonly adapter?: AihuAdapter\n /**\n * Router-related app config (arch-5 M1).\n * Currently exposes the `viewTransitions` opt-in for `<$link>`.\n */\n readonly router?: RouterConfig\n}\n\n/** Thrown by defineConfig when configuration validation fails. */\nexport class AihuConfigError extends Error {\n constructor(\n message: string,\n readonly code: 'INVALID_OUTPUT_MODE' | 'INVALID_DIR' | 'UNKNOWN_FIELD',\n readonly field?: string,\n ) {\n super(message)\n this.name = 'AihuConfigError'\n }\n}\n\n/**\n * Define the aihu application configuration.\n *\n * Validates the config at call time and throws AihuConfigError for invalid values.\n * Returns the config unchanged (typed identity function).\n *\n * @example\n * // aihu.config.ts\n * import { defineConfig } from '@aihu/app'\n * export default defineConfig({\n * app: { head: { title: 'My App' } },\n * })\n */\nexport function defineConfig(config: AihuConfig): AihuConfig {\n if (config.output && config.output !== 'spa') {\n throw new AihuConfigError(\n `output mode '${config.output}' is not supported in V0 (only 'spa')`,\n 'INVALID_OUTPUT_MODE',\n 'output',\n )\n }\n if (config.dir?.pages !== undefined && typeof config.dir.pages !== 'string') {\n throw new AihuConfigError('dir.pages must be a string', 'INVALID_DIR', 'dir.pages')\n }\n if (config.dir?.layouts !== undefined && typeof config.dir.layouts !== 'string') {\n throw new AihuConfigError('dir.layouts must be a string', 'INVALID_DIR', 'dir.layouts')\n }\n return config\n}\n","import { existsSync } from 'node:fs'\nimport { cp, writeFile as fsWriteFile, mkdir } from 'node:fs/promises'\nimport { dirname, resolve as resolvePath } from 'node:path'\n// Build-time sub-plugin imports. These are devDependencies of @aihu/app and\n// are marked external in rolldown.config.ts — they are never bundled.\nimport { aihuCompilerPlugin } from '@aihu/compiler'\nimport type { RouteDefinition } from '@aihu/router'\nimport { scanPages, viteRouterIntegration } from '@aihu/router/plugin'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { AdapterContext, CreateHandlerSourceOptions } from './adapter.ts'\nimport type { AihuConfig } from './config.ts'\n\n/** Map a pages-dir file path to a minimal RouteDefinition for adapter context. */\nfunction fileToRouteDefinition(filePath: string, root: string, pagesDir: string): RouteDefinition {\n // Derive a URL pattern from the file path relative to the pages directory.\n const rel = filePath\n .replace(/\\\\/g, '/')\n .replace(new RegExp(`^.*?${pagesDir}/`), '')\n .replace(/\\.[^.]+$/, '') // strip extension\n const parts = rel.split('/').filter(Boolean)\n // Strip trailing 'index' segment (file-router convention)\n if (parts.length > 0 && parts[parts.length - 1] === 'index') parts.pop()\n\n const segments = parts.map((p) =>\n p.startsWith('[...') && p.endsWith(']')\n ? { kind: 'catchall' as const }\n : p.startsWith('[') && p.endsWith(']')\n ? { kind: 'param' as const, name: p.slice(1, -1) }\n : { kind: 'static' as const, path: p },\n )\n\n const pattern =\n segments.length === 0\n ? '/'\n : '/' +\n segments\n .map((s) => (s.kind === 'static' ? s.path : s.kind === 'param' ? `:${s.name}` : '*'))\n .join('/')\n\n return {\n pattern,\n segments,\n module: () => Promise.resolve({ default: null }),\n }\n}\n\n/** Build the AdapterContext object passed to adapter.adapt(). */\nfunction buildAdapterContext(\n resolvedViteConfig: ResolvedConfig,\n routeFiles: string[],\n config: AihuConfig | undefined,\n): AdapterContext {\n const outDir = resolvePath(resolvedViteConfig.root, resolvedViteConfig.build.outDir)\n const root = resolvedViteConfig.root\n const pagesDir = config?.dir?.pages ?? 'pages'\n\n const routes: RouteDefinition[] = routeFiles.map((f) => fileToRouteDefinition(f, root, pagesDir))\n\n return {\n outDir,\n root,\n routes,\n config: config ?? {},\n\n async emitFile(path: string, content: string): Promise<void> {\n const abs = resolvePath(outDir, path)\n await mkdir(dirname(abs), { recursive: true })\n await fsWriteFile(abs, content, 'utf8')\n },\n\n async copy(src: string, dest: string): Promise<void> {\n await mkdir(dirname(dest), { recursive: true })\n await cp(src, dest, { recursive: true, force: true })\n },\n\n async writeFile(absolutePath: string, content: string): Promise<void> {\n await mkdir(dirname(absolutePath), { recursive: true })\n await fsWriteFile(absolutePath, content, 'utf8')\n },\n\n createHandlerSource(opts?: CreateHandlerSourceOptions): string {\n const routesSpec = opts?.routesSpecifier ?? './routes-manifest.js'\n const serverSpec = opts?.serverSpecifier ?? '@aihu/server'\n return [\n `// AUTO-GENERATED — do not edit`,\n `import { createRequestRouter } from '${serverSpec}'`,\n `import routes from '${routesSpec}'`,\n `const _manifest = { routes }`,\n `const _handler = createRequestRouter(_manifest)`,\n `export { _handler as handler }`,\n ].join('\\n')\n },\n }\n}\n\n/**\n * viteAihuPlugin() — composed Vite plugin for aihu SPA projects.\n *\n * Returns Plugin[] composing:\n * [0] aihuCompilerPlugin (enforce:'pre') — transforms .aihu SFCs\n * [1] viteRouterIntegration — serves virtual:aihu-routes + virtual:aihu-layouts\n * [2] aihu-agent-readiness (opt-in) or no-op\n * [3..n] user plugins from config.plugins\n * [n+1] aihu-vite-passthrough (merges config.vite into Vite's resolved config)\n * [n+2] aihu-adapter (adapter.adapt() on closeBundle, build mode only)\n *\n * @example\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import { viteAihuPlugin } from '@aihu/app'\n * export default defineConfig({ plugins: [viteAihuPlugin()] })\n *\n * @example\n * // With adapter\n * import { cloudflare } from '@aihu/adapter-cloudflare'\n * export default defineConfig({\n * plugins: [viteAihuPlugin({\n * dir: { pages: 'src/pages' },\n * adapter: cloudflare({ name: 'my-worker' }),\n * })]\n * })\n */\nexport function viteAihuPlugin(config?: AihuConfig): Plugin[] {\n const routerOpts = {\n pagesDir: config?.dir?.pages ?? 'pages',\n layoutsDir: config?.dir?.layouts ?? 'src/layouts',\n }\n\n // Agent readiness: opt-in only. No safe default for `name`.\n let agentPlugin: Plugin\n const ar = config?.agentReadiness\n if (ar) {\n // Dynamic import to avoid pulling @aihu/agent-readiness into the bundle\n // when it is not configured. The `require` below is evaluated at runtime\n // in Node.js (vite.config.ts execution context), not in the browser.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { viteAgentReadinessIntegration } =\n require('@aihu/agent-readiness') as typeof import('@aihu/agent-readiness')\n agentPlugin = viteAgentReadinessIntegration(ar) as unknown as Plugin\n } else {\n // Stable no-op so plugin-inspector shows a meaningful entry\n agentPlugin = { name: 'aihu-agent-readiness-disabled' }\n }\n\n // Vite config passthrough — deep-merged by Vite via the config() hook return value.\n const passthroughPlugin: Plugin = {\n name: 'aihu-vite-passthrough',\n config() {\n return (config?.vite ?? {}) as import('vite').UserConfig\n },\n }\n\n // Adapter sentinel — calls adapter.adapt() after build completes.\n // Registered unconditionally; short-circuits immediately if no adapter is set.\n let resolvedViteConfig: ResolvedConfig | null = null\n\n const adapterPlugin: Plugin = {\n name: 'aihu-adapter',\n apply: 'build',\n configResolved(rc) {\n resolvedViteConfig = rc\n },\n async closeBundle() {\n const adapter = config?.adapter\n if (!adapter || !resolvedViteConfig) return\n\n const pagesDir = config?.dir?.pages ?? 'pages'\n const { routes: routeFiles } = scanPages(resolvedViteConfig.root, pagesDir)\n const context = buildAdapterContext(resolvedViteConfig, routeFiles, config)\n\n try {\n await adapter.adapt(context)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.error(`[@aihu/app] Adapter '${adapter.name}' failed: ${msg}`)\n }\n },\n }\n\n return [\n aihuCompilerPlugin() as unknown as Plugin,\n viteRouterIntegration(routerOpts) as unknown as Plugin,\n agentPlugin,\n ...((config?.plugins ?? []) as Plugin[]),\n passthroughPlugin,\n adapterPlugin,\n ]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["resolvePath","fsWriteFile"],"sources":["../src/config.ts","../src/vite-plugin.ts"],"sourcesContent":["import type { Plugin, UserConfig } from 'vite'\nimport type { AihuAdapter } from './adapter.ts'\n\n/** V0: SPA output only. More modes (ssr, static, hybrid) in V1+. */\nexport type OutputMode = 'spa'\n\nexport interface DirConfig {\n /** Directory to scan for page routes. Default: 'pages' */\n readonly pages?: string\n /** Directory to scan for layout files. Default: 'src/layouts' */\n readonly layouts?: string\n /** Public static assets directory. Default: 'public' */\n readonly public?: string\n}\n\n/** Runtime configuration split. Public values are safe to expose to the client. */\nexport interface RuntimeConfig {\n readonly public?: Record<string, unknown>\n /** V0: accepted but ignored at runtime (server-side enforcement deferred to V1). */\n readonly private?: Record<string, unknown>\n}\n\nexport interface HeadConfig {\n readonly title?: string\n /** Default: 'UTF-8' */\n readonly charset?: string\n /** Default: 'width=device-width, initial-scale=1' */\n readonly viewport?: string\n readonly meta?: ReadonlyArray<Record<string, string>>\n}\n\nexport interface AppHeadConfig {\n readonly head?: HeadConfig\n}\n\n/** Vite config fields that can be safely merged (excludes plugins — use AihuConfig.plugins). */\nexport type VitePassthrough = Omit<UserConfig, 'plugins'>\n\n/** A Aihu plugin is structurally identical to a Vite plugin (V0). */\nexport type AihuPlugin = Plugin\n\n/** Type-only import — not bundled when agentReadiness is absent. */\nexport type AgentReadinessConfig = import('@aihu/agent-readiness').AgentReadinessConfig\n\n/** Router-related app config (arch-5 M1, RFC-A5-012). */\nexport interface RouterConfig {\n /**\n * When `true`, `<$link>` navigation wraps in `document.startViewTransition()`\n * if the browser supports the View Transitions API. No-op in unsupported\n * browsers (graceful degradation). Default: `false`.\n *\n * SSR safety: the wrapping is browser-only — server-rendered HTML is\n * unchanged, and hydration is unaffected.\n */\n readonly viewTransitions?: boolean\n}\n\nexport interface AihuConfig {\n /** Directory layout overrides. */\n readonly dir?: DirConfig\n /**\n * Output mode. V0 supports 'spa' only.\n * defineConfig throws AihuConfigError for any other value.\n */\n readonly output?: OutputMode\n /**\n * Aihu plugins. Order is preserved.\n * Appended after the three framework plugins (compiler, router, agent-readiness).\n */\n readonly plugins?: ReadonlyArray<AihuPlugin>\n /** Runtime configuration split — public values are inlined in the client bundle. */\n readonly runtimeConfig?: RuntimeConfig\n /**\n * App-level values made available to all components as bare identifiers.\n * Declared here for documentation and future build-time validation; the\n * values are hoisted into globalThis by createApp() at runtime.\n *\n * @example\n * export default defineConfig({ provide: { supabase, checkAuth } })\n */\n readonly provide?: Record<string, unknown>\n /** HTML <head> metadata. */\n readonly app?: AppHeadConfig\n /** Passthrough to Vite's UserConfig. Merged via Vite's config() hook. */\n readonly vite?: VitePassthrough\n /**\n * Opt-in agent-readiness integration.\n * Requires { name: string } at minimum.\n * When absent or false, a no-op plugin is substituted.\n */\n readonly agentReadiness?: AgentReadinessConfig | false\n /**\n * Deployment adapter. Transforms the Vite build output into the target\n * platform's required format. Called after vite build completes.\n * When absent, no post-build transformation is applied (manual deployment).\n */\n readonly adapter?: AihuAdapter\n /**\n * Router-related app config (arch-5 M1).\n * Currently exposes the `viewTransitions` opt-in for `<$link>`.\n */\n readonly router?: RouterConfig\n}\n\n/** Thrown by defineConfig when configuration validation fails. */\nexport class AihuConfigError extends Error {\n constructor(\n message: string,\n readonly code: 'INVALID_OUTPUT_MODE' | 'INVALID_DIR' | 'UNKNOWN_FIELD',\n readonly field?: string,\n ) {\n super(message)\n this.name = 'AihuConfigError'\n }\n}\n\n/**\n * Define the aihu application configuration.\n *\n * Validates the config at call time and throws AihuConfigError for invalid values.\n * Returns the config unchanged (typed identity function).\n *\n * @example\n * // aihu.config.ts\n * import { defineConfig } from '@aihu/app'\n * export default defineConfig({\n * app: { head: { title: 'My App' } },\n * })\n */\nexport function defineConfig(config: AihuConfig): AihuConfig {\n if (config.output && config.output !== 'spa') {\n throw new AihuConfigError(\n `output mode '${config.output}' is not supported in V0 (only 'spa')`,\n 'INVALID_OUTPUT_MODE',\n 'output',\n )\n }\n if (config.dir?.pages !== undefined && typeof config.dir.pages !== 'string') {\n throw new AihuConfigError('dir.pages must be a string', 'INVALID_DIR', 'dir.pages')\n }\n if (config.dir?.layouts !== undefined && typeof config.dir.layouts !== 'string') {\n throw new AihuConfigError('dir.layouts must be a string', 'INVALID_DIR', 'dir.layouts')\n }\n return config\n}\n","import { cp, writeFile as fsWriteFile, mkdir } from 'node:fs/promises'\nimport { dirname, resolve as resolvePath } from 'node:path'\n// Build-time sub-plugin imports. These are devDependencies of @aihu/app and\n// are marked external in rolldown.config.ts — they are never bundled.\nimport { aihuCompilerPlugin } from '@aihu/compiler'\nimport type { RouteDefinition } from '@aihu/router'\nimport { scanPages, viteRouterIntegration } from '@aihu/router/plugin'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { AdapterContext, CreateHandlerSourceOptions } from './adapter.ts'\nimport type { AihuConfig } from './config.ts'\n\n/** Map a pages-dir file path to a minimal RouteDefinition for adapter context. */\nfunction fileToRouteDefinition(filePath: string, _root: string, pagesDir: string): RouteDefinition {\n // Derive a URL pattern from the file path relative to the pages directory.\n const rel = filePath\n .replace(/\\\\/g, '/')\n .replace(new RegExp(`^.*?${pagesDir}/`), '')\n .replace(/\\.[^.]+$/, '') // strip extension\n const parts = rel.split('/').filter(Boolean)\n // Strip trailing 'index' segment (file-router convention)\n if (parts.length > 0 && parts[parts.length - 1] === 'index') parts.pop()\n\n const segments = parts.map((p) =>\n p.startsWith('[...') && p.endsWith(']')\n ? { kind: 'catchall' as const }\n : p.startsWith('[') && p.endsWith(']')\n ? { kind: 'param' as const, name: p.slice(1, -1) }\n : { kind: 'static' as const, path: p },\n )\n\n const pattern =\n segments.length === 0\n ? '/'\n : '/' +\n segments\n .map((s) => (s.kind === 'static' ? s.path : s.kind === 'param' ? `:${s.name}` : '*'))\n .join('/')\n\n return {\n pattern,\n segments,\n module: () => Promise.resolve({ default: null }),\n }\n}\n\n/** Build the AdapterContext object passed to adapter.adapt(). */\nfunction buildAdapterContext(\n resolvedViteConfig: ResolvedConfig,\n routeFiles: string[],\n config: AihuConfig | undefined,\n): AdapterContext {\n const outDir = resolvePath(resolvedViteConfig.root, resolvedViteConfig.build.outDir)\n const root = resolvedViteConfig.root\n const pagesDir = config?.dir?.pages ?? 'pages'\n\n const routes: RouteDefinition[] = routeFiles.map((f) => fileToRouteDefinition(f, root, pagesDir))\n\n return {\n outDir,\n root,\n routes,\n config: config ?? {},\n\n async emitFile(path: string, content: string): Promise<void> {\n const abs = resolvePath(outDir, path)\n await mkdir(dirname(abs), { recursive: true })\n await fsWriteFile(abs, content, 'utf8')\n },\n\n async copy(src: string, dest: string): Promise<void> {\n await mkdir(dirname(dest), { recursive: true })\n await cp(src, dest, { recursive: true, force: true })\n },\n\n async writeFile(absolutePath: string, content: string): Promise<void> {\n await mkdir(dirname(absolutePath), { recursive: true })\n await fsWriteFile(absolutePath, content, 'utf8')\n },\n\n createHandlerSource(opts?: CreateHandlerSourceOptions): string {\n const routesSpec = opts?.routesSpecifier ?? './routes-manifest.js'\n const serverSpec = opts?.serverSpecifier ?? '@aihu/server'\n return [\n `// AUTO-GENERATED — do not edit`,\n `import { createRequestRouter } from '${serverSpec}'`,\n `import routes from '${routesSpec}'`,\n `const _manifest = { routes }`,\n `const _handler = createRequestRouter(_manifest)`,\n `export { _handler as handler }`,\n ].join('\\n')\n },\n }\n}\n\n/**\n * viteAihuPlugin() — composed Vite plugin for aihu SPA projects.\n *\n * Returns Plugin[] composing:\n * [0] aihuCompilerPlugin (enforce:'pre') — transforms .aihu SFCs\n * [1] viteRouterIntegration — serves virtual:aihu-routes + virtual:aihu-layouts\n * [2] aihu-agent-readiness (opt-in) or no-op\n * [3..n] user plugins from config.plugins\n * [n+1] aihu-vite-passthrough (merges config.vite into Vite's resolved config)\n * [n+2] aihu-adapter (adapter.adapt() on closeBundle, build mode only)\n *\n * @example\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import { viteAihuPlugin } from '@aihu/app'\n * export default defineConfig({ plugins: [viteAihuPlugin()] })\n *\n * @example\n * // With adapter\n * import { cloudflare } from '@aihu/adapter-cloudflare'\n * export default defineConfig({\n * plugins: [viteAihuPlugin({\n * dir: { pages: 'src/pages' },\n * adapter: cloudflare({ name: 'my-worker' }),\n * })]\n * })\n */\nexport function viteAihuPlugin(config?: AihuConfig): Plugin[] {\n const routerOpts = {\n pagesDir: config?.dir?.pages ?? 'pages',\n layoutsDir: config?.dir?.layouts ?? 'src/layouts',\n }\n\n // Agent readiness: opt-in only. No safe default for `name`.\n let agentPlugin: Plugin\n const ar = config?.agentReadiness\n if (ar) {\n // Dynamic import to avoid pulling @aihu/agent-readiness into the bundle\n // when it is not configured. The `require` below is evaluated at runtime\n // in Node.js (vite.config.ts execution context), not in the browser.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { viteAgentReadinessIntegration } =\n require('@aihu/agent-readiness') as typeof import('@aihu/agent-readiness')\n agentPlugin = viteAgentReadinessIntegration(ar) as unknown as Plugin\n } else {\n // Stable no-op so plugin-inspector shows a meaningful entry\n agentPlugin = { name: 'aihu-agent-readiness-disabled' }\n }\n\n // Vite config passthrough — deep-merged by Vite via the config() hook return value.\n const passthroughPlugin: Plugin = {\n name: 'aihu-vite-passthrough',\n config() {\n return (config?.vite ?? {}) as import('vite').UserConfig\n },\n }\n\n // Adapter sentinel — calls adapter.adapt() after build completes.\n // Registered unconditionally; short-circuits immediately if no adapter is set.\n let resolvedViteConfig: ResolvedConfig | null = null\n\n const adapterPlugin: Plugin = {\n name: 'aihu-adapter',\n apply: 'build',\n configResolved(rc) {\n resolvedViteConfig = rc\n },\n async closeBundle() {\n const adapter = config?.adapter\n if (!adapter || !resolvedViteConfig) return\n\n const pagesDir = config?.dir?.pages ?? 'pages'\n const { routes: routeFiles } = scanPages(resolvedViteConfig.root, pagesDir)\n const context = buildAdapterContext(resolvedViteConfig, routeFiles, config)\n\n try {\n await adapter.adapt(context)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.error(`[@aihu/app] Adapter '${adapter.name}' failed: ${msg}`)\n }\n },\n }\n\n return [\n // SPA mode: route components are top-level mounts that frequently use\n // lifecycle hooks (onMount/onCleanup) and rely on the runtime/signals\n // owner context regardless of whether they call signal() directly. The\n // static-island optimization is unsafe to apply silently here — it strips\n // defineComponent and breaks `no owner` for any module touching lifecycle.\n // It also saves ~0 B in practice because the runtime already ships in the\n // main bundle. Default islands off; opt back in via the compiler plugin\n // directly if you genuinely have an MPA-style mixed-island layout.\n aihuCompilerPlugin({ islands: false }) as unknown as Plugin,\n viteRouterIntegration(routerOpts) as unknown as Plugin,\n agentPlugin,\n ...((config?.plugins ?? []) as Plugin[]),\n passthroughPlugin,\n adapterPlugin,\n ]\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aihu/app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"prepublishOnly": "bun run build"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@aihu/arbor": "
|
|
32
|
-
"@aihu/router": "
|
|
33
|
-
"@aihu/runtime": "
|
|
34
|
-
"@aihu/signals": "
|
|
31
|
+
"@aihu/arbor": "workspace:*",
|
|
32
|
+
"@aihu/router": "workspace:*",
|
|
33
|
+
"@aihu/runtime": "workspace:*",
|
|
34
|
+
"@aihu/signals": "workspace:*",
|
|
35
35
|
"vite": ">=5.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@aihu/agent-readiness": "
|
|
39
|
-
"@aihu/compiler": "
|
|
38
|
+
"@aihu/agent-readiness": "workspace:*",
|
|
39
|
+
"@aihu/compiler": "workspace:*"
|
|
40
40
|
},
|
|
41
41
|
"description": "Top-level app integration — wires runtime, router, and adapters into a Vite app.",
|
|
42
42
|
"repository": {
|