@useavalon/avalon 0.1.47 → 0.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/mod.d.ts +48 -49
  2. package/dist/mod.js +1 -1
  3. package/dist/src/client/components.d.ts +10 -18
  4. package/dist/src/client/components.js +1 -1
  5. package/dist/src/client/custom-directives.d.ts +25 -0
  6. package/dist/src/client/custom-directives.js +1 -0
  7. package/dist/src/client/main.js +3 -3
  8. package/dist/src/components/IslandErrorBoundary.d.ts +48 -9
  9. package/dist/src/components/IslandErrorBoundary.js +1 -1
  10. package/dist/src/components/LayoutErrorBoundary.d.ts +75 -10
  11. package/dist/src/components/LayoutErrorBoundary.js +1 -1
  12. package/dist/src/islands/builtin-directives.d.ts +15 -0
  13. package/dist/src/islands/builtin-directives.js +1 -0
  14. package/dist/src/islands/hydration-directives.d.ts +89 -0
  15. package/dist/src/islands/hydration-directives.js +1 -0
  16. package/dist/src/islands/integration-loader.d.ts +2 -2
  17. package/dist/src/islands/island.d.ts +11 -9
  18. package/dist/src/islands/island.js +1 -1
  19. package/dist/src/islands/types.d.ts +4 -2
  20. package/dist/src/layout-system.d.ts +14 -30
  21. package/dist/src/layout-system.js +1 -1
  22. package/dist/src/nitro/config.d.ts +3 -3
  23. package/dist/src/nitro/renderer.d.ts +18 -5
  24. package/dist/src/nitro/renderer.js +11 -11
  25. package/dist/src/persistence/island-state-serializer.d.ts +9 -0
  26. package/dist/src/persistence/island-state-serializer.js +1 -0
  27. package/dist/src/persistence/use-persistent-state.d.ts +31 -0
  28. package/dist/src/persistence/use-persistent-state.js +1 -0
  29. package/dist/src/prerender/index.d.ts +1 -1
  30. package/dist/src/prerender/prerender.d.ts +1 -1
  31. package/dist/src/prerender/prerender.js +1 -1
  32. package/dist/src/schemas/core.d.ts +2 -2
  33. package/dist/src/schemas/layout.d.ts +5 -5
  34. package/dist/src/schemas/layout.js +1 -1
  35. package/dist/src/schemas/routing/index.d.ts +2 -2
  36. package/dist/src/schemas/routing.d.ts +4 -4
  37. package/dist/src/types/island-prop.d.ts +14 -6
  38. package/dist/src/types/layout.d.ts +11 -19
  39. package/dist/src/types/layout.js +1 -1
  40. package/dist/src/vite-plugin/nitro-integration.d.ts +3 -3
  41. package/dist/src/vite-plugin/nitro-integration.js +14 -14
  42. package/package.json +2 -2
  43. package/dist/src/components/LayoutDataErrorBoundary.d.ts +0 -34
  44. package/dist/src/components/LayoutDataErrorBoundary.js +0 -1
  45. package/dist/src/components/PersistentIsland.d.ts +0 -36
  46. package/dist/src/components/PersistentIsland.js +0 -1
  47. package/dist/src/components/StreamingErrorBoundary.d.ts +0 -42
  48. package/dist/src/components/StreamingErrorBoundary.js +0 -1
  49. package/dist/src/components/StreamingLayout.d.ts +0 -83
  50. package/dist/src/components/StreamingLayout.js +0 -29
  51. package/dist/src/core/islands/island-persistence.d.ts +0 -74
  52. package/dist/src/core/islands/island-persistence.js +0 -1
  53. package/dist/src/core/islands/island-state-serializer.d.ts +0 -53
  54. package/dist/src/core/islands/island-state-serializer.js +0 -1
  55. package/dist/src/core/islands/persistent-island-context.d.ts +0 -36
  56. package/dist/src/core/islands/persistent-island-context.js +0 -1
  57. package/dist/src/core/islands/use-persistent-state.d.ts +0 -17
  58. package/dist/src/core/islands/use-persistent-state.js +0 -1
@@ -4,9 +4,9 @@ import type { ComponentType } from 'preact/compat';
4
4
  * Route Type Schema - Defines the different types of routes supported
5
5
  */
6
6
  export declare const RouteTypeSchema: z.ZodEnum<{
7
+ group: "group";
7
8
  static: "static";
8
9
  index: "index";
9
- group: "group";
10
10
  dynamic: "dynamic";
11
11
  "catch-all": "catch-all";
12
12
  }>;
@@ -17,9 +17,9 @@ export declare const FileSystemRouteSchema: z.ZodObject<{
17
17
  pattern: z.ZodAny;
18
18
  filePath: z.ZodString;
19
19
  routeType: z.ZodEnum<{
20
+ group: "group";
20
21
  static: "static";
21
22
  index: "index";
22
- group: "group";
23
23
  dynamic: "dynamic";
24
24
  "catch-all": "catch-all";
25
25
  }>;
@@ -266,9 +266,9 @@ export declare const RouteHandlerSchema: z.ZodObject<{
266
266
  metadata: z.ZodObject<{
267
267
  filePath: z.ZodString;
268
268
  routeType: z.ZodEnum<{
269
+ group: "group";
269
270
  static: "static";
270
271
  index: "index";
271
- group: "group";
272
272
  dynamic: "dynamic";
273
273
  "catch-all": "catch-all";
274
274
  }>;
@@ -284,9 +284,9 @@ export declare const RouteCacheEntrySchema: z.ZodObject<{
284
284
  pattern: z.ZodAny;
285
285
  filePath: z.ZodString;
286
286
  routeType: z.ZodEnum<{
287
+ group: "group";
287
288
  static: "static";
288
289
  index: "index";
289
- group: "group";
290
290
  dynamic: "dynamic";
291
291
  "catch-all": "catch-all";
292
292
  }>;
@@ -11,10 +11,18 @@
11
11
  */
12
12
 
13
13
  export interface IslandDirective {
14
- /** Hydration condition */
15
- condition?: 'on:visible' | 'on:interaction' | 'on:idle' | 'on:client' | `media:${string}`;
16
- /** Force SSR-only rendering without client hydration */
17
- ssrOnly?: boolean;
18
- /** Whether to render server-side (default: true) */
19
- ssr?: boolean;
14
+ /** Hydration condition (built-in or custom directive name) */
15
+ condition?:
16
+ | "on:visible"
17
+ | "on:interaction"
18
+ | "on:idle"
19
+ | "on:client"
20
+ | `media:${string}`
21
+ | `on:${string}`;
22
+ /** Optional argument passed to custom hydration directives */
23
+ conditionArg?: string;
24
+ /** Force SSR-only rendering without client hydration */
25
+ ssrOnly?: boolean;
26
+ /** Whether to render server-side (default: true) */
27
+ ssr?: boolean;
20
28
  }
@@ -1,21 +1,13 @@
1
- import type { LayoutContext, LayoutRoute, LayoutHandler, LayoutProps, LayoutDiscoveryOptions, RouteInfo, LayoutRule, LayoutConfig, IslandState, PersistentIslandProps, LayoutErrorInfo, LayoutErrorBoundaryProps, ErrorRecoveryStrategy, StreamingLayoutProps, StreamingComponent, ResolvedLayout, LayoutLoader } from '../schemas/layout.ts';
2
- import type { ComponentType, ComponentChildren } from 'preact';
3
- export type { LayoutContext, LayoutData, LayoutRoute, LayoutHandler, LayoutProps, LayoutDiscoveryOptions, RouteInfo, LayoutRule, LayoutConfig, IslandState, PersistentIslandProps, PersistentIslandContext, LayoutErrorInfo, LayoutErrorBoundaryProps, ErrorRecoveryStrategy, StreamingLayoutProps, StreamingComponent, ResolvedLayout, LayoutCache, EnhancedLayoutContext, LayoutLoader, LayoutMatcherFunction, LayoutErrorHandler, LayoutRetryFunction, LayoutFallbackRenderer, IslandStateSaver, IslandStateLoader, IslandStateClearer, StreamingReadyCheck, } from '../schemas/layout.ts';
4
- export type { ComponentType, ComponentChildren } from 'preact';
5
- export { LayoutDiscovery } from '../core/layout/layout-discovery.ts';
6
- export { LayoutDataLoader } from '../core/layout/layout-data-loader.ts';
7
- export { LayoutMatcher as LayoutMatcherClass } from '../core/layout/layout-matcher.ts';
8
- export { LayoutComposer } from '../core/layout/layout-composer.ts';
9
- export { IslandPersistence, defaultIslandPersistence } from '../core/islands/island-persistence.ts';
10
- export { IslandStateSerializer } from '../core/islands/island-state-serializer.ts';
11
- export { createPersistentIslandContext, usePersistentIslandContext, PersistentIslandProvider, } from '../core/islands/persistent-island-context.tsx';
12
- export { PersistentIsland } from '../components/PersistentIsland.tsx';
13
- export { LayoutErrorBoundary } from '../components/LayoutErrorBoundary.tsx';
14
- export { LayoutDataErrorBoundary } from '../components/LayoutDataErrorBoundary.tsx';
15
- export { IslandErrorBoundary, withIslandErrorBoundary } from '../components/IslandErrorBoundary.tsx';
16
- export { StreamingLayout, StreamingSuspense, withStreaming, useStreamingState, } from '../components/StreamingLayout.tsx';
17
- export { EnhancedLayoutResolver, createEnhancedLayoutResolver, EnhancedLayoutResolverUtils, type EnhancedLayoutResolverOptions, } from '../core/layout/enhanced-layout-resolver.ts';
18
- export { LayoutCacheManager, type CacheEntry, type CacheStats, type CacheConfig, } from '../core/layout/layout-cache-manager.ts';
1
+ import type { ComponentChildren, ComponentType } from "preact";
2
+ import type { ErrorRecoveryStrategy, IslandState, LayoutConfig, LayoutContext, LayoutDiscoveryOptions, LayoutErrorBoundaryProps, LayoutErrorInfo, LayoutHandler, LayoutLoader, LayoutProps, LayoutRoute, LayoutRule, PersistentIslandProps, ResolvedLayout, RouteInfo, StreamingComponent, StreamingLayoutProps } from "../schemas/layout.ts";
3
+ export type { ComponentChildren, ComponentType } from "preact";
4
+ export { createEnhancedLayoutResolver, EnhancedLayoutResolver, type EnhancedLayoutResolverOptions, EnhancedLayoutResolverUtils, } from "../core/layout/enhanced-layout-resolver.ts";
5
+ export { type CacheConfig, type CacheEntry, type CacheStats, LayoutCacheManager, } from "../core/layout/layout-cache-manager.ts";
6
+ export { LayoutComposer } from "../core/layout/layout-composer.ts";
7
+ export { LayoutDataLoader } from "../core/layout/layout-data-loader.ts";
8
+ export { LayoutDiscovery } from "../core/layout/layout-discovery.ts";
9
+ export { LayoutMatcher as LayoutMatcherClass } from "../core/layout/layout-matcher.ts";
10
+ export type { EnhancedLayoutContext, ErrorRecoveryStrategy, IslandState, IslandStateClearer, IslandStateLoader, IslandStateSaver, LayoutCache, LayoutConfig, LayoutContext, LayoutData, LayoutDiscoveryOptions, LayoutErrorBoundaryProps, LayoutErrorHandler, LayoutErrorInfo, LayoutFallbackRenderer, LayoutHandler, LayoutLoader, LayoutMatcherFunction, LayoutProps, LayoutRetryFunction, LayoutRoute, LayoutRule, PersistentIslandContext, PersistentIslandProps, ResolvedLayout, RouteInfo, StreamingComponent, StreamingLayoutProps, StreamingReadyCheck, } from "../schemas/layout.ts";
19
11
  /**
20
12
  * Layout Discovery Interface
21
13
  */
@@ -159,7 +151,7 @@ export interface LayoutDebugInfo {
159
151
  size: number;
160
152
  };
161
153
  }
162
- export type LayoutEventType = 'layout-discovered' | 'layout-loaded' | 'layout-rendered' | 'layout-error' | 'layout-cached' | 'island-state-saved' | 'island-state-loaded' | 'streaming-started' | 'streaming-completed';
154
+ export type LayoutEventType = "layout-discovered" | "layout-loaded" | "layout-rendered" | "layout-error" | "layout-cached" | "island-state-saved" | "island-state-loaded" | "streaming-started" | "streaming-completed";
163
155
  export interface LayoutEventData {
164
156
  type: LayoutEventType;
165
157
  timestamp: number;
@@ -1 +1 @@
1
- export{LayoutDiscovery}from"../core/layout/layout-discovery.js";export{LayoutDataLoader}from"../core/layout/layout-data-loader.js";export{LayoutMatcher as LayoutMatcherClass}from"../core/layout/layout-matcher.js";export{LayoutComposer}from"../core/layout/layout-composer.js";export{IslandPersistence,defaultIslandPersistence}from"../core/islands/island-persistence.js";export{IslandStateSerializer}from"../core/islands/island-state-serializer.js";export{createPersistentIslandContext,usePersistentIslandContext,PersistentIslandProvider}from"../core/islands/persistent-island-context.js";export{PersistentIsland}from"../components/PersistentIsland.js";export{LayoutErrorBoundary}from"../components/LayoutErrorBoundary.js";export{LayoutDataErrorBoundary}from"../components/LayoutDataErrorBoundary.js";export{IslandErrorBoundary,withIslandErrorBoundary}from"../components/IslandErrorBoundary.js";export{StreamingLayout,StreamingSuspense,withStreaming,useStreamingState}from"../components/StreamingLayout.js";export{EnhancedLayoutResolver,createEnhancedLayoutResolver,EnhancedLayoutResolverUtils}from"../core/layout/enhanced-layout-resolver.js";export{LayoutCacheManager}from"../core/layout/layout-cache-manager.js";
1
+ export{createEnhancedLayoutResolver,EnhancedLayoutResolver,EnhancedLayoutResolverUtils}from"../core/layout/enhanced-layout-resolver.js";export{LayoutCacheManager}from"../core/layout/layout-cache-manager.js";export{LayoutComposer}from"../core/layout/layout-composer.js";export{LayoutDataLoader}from"../core/layout/layout-data-loader.js";export{LayoutDiscovery}from"../core/layout/layout-discovery.js";export{LayoutMatcher as LayoutMatcherClass}from"../core/layout/layout-matcher.js";
@@ -6,9 +6,9 @@
6
6
  * - Page routes: Virtual module for SSR page component discovery
7
7
  * - Middleware: Auto-discovered by Nitro from `middleware/` directory
8
8
  */
9
- import type { Plugin, ViteDevServer } from 'vite';
10
- import type { ResolvedAvalonConfig } from './types.ts';
11
- import { type AvalonNitroConfig, type NitroConfigOutput } from '../nitro/config.ts';
9
+ import type { Plugin, ViteDevServer } from "vite";
10
+ import { type AvalonNitroConfig, type NitroConfigOutput } from "../nitro/config.ts";
11
+ import type { ResolvedAvalonConfig } from "./types.ts";
12
12
  export declare const VIRTUAL_MODULE_IDS: {
13
13
  readonly PAGE_ROUTES: "virtual:avalon/page-routes";
14
14
  readonly PAGE_LOADER: "virtual:avalon/page-loader";
@@ -1,46 +1,46 @@
1
- import{nitro as e}from"nitro/vite";import{stat as t}from"node:fs/promises";import{existsSync as n}from"node:fs";import{createRequire as r}from"node:module";import{dirname as i,join as a}from"node:path";import{createNitroConfig as o}from"../nitro/config.js";import{createNitroBuildPlugin as s,createIslandManifestPlugin as c,createSourceMapPlugin as l,createSourceMapConfig as u}from"../nitro/index.js";import{discoverScopedMiddleware as d,executeScopedMiddleware as f,clearMiddlewareCache as p}from"../middleware/index.js";import{generateErrorPage as m,generateFallback404 as h}from"../render/error-pages.js";import{collectCssFromModuleGraph as g,injectSsrCss as _}from"../render/collect-css.js";import{getUniversalCSSForHead as v}from"../islands/universal-css-collector.js";import{getUniversalHeadForInjection as y}from"../islands/universal-head-collector.js";function b(e){let t=a(i(r(import.meta.url).resolve(`@useavalon/avalon`)),e);if(e.endsWith(`.ts`)&&!n(t)){let e=t.replace(/\.ts$/,`.js`);if(n(e))return e}return t}function x(e,t){let o=a(i(r(a(process.cwd(),`package.json`)).resolve(`@useavalon/${e}`)),t);if(t.endsWith(`.ts`)&&!n(o)){let e=o.replace(/\.ts$/,`.js`);if(n(e))return e}return o}export const VIRTUAL_MODULE_IDS={PAGE_ROUTES:`virtual:avalon/page-routes`,PAGE_LOADER:`virtual:avalon/page-loader`,ISLAND_MANIFEST:`virtual:avalon/island-manifest`,RUNTIME_CONFIG:`virtual:avalon/runtime-config`,CONFIG:`virtual:avalon/config`};export const RESOLVED_VIRTUAL_IDS={PAGE_ROUTES:`\0`+VIRTUAL_MODULE_IDS.PAGE_ROUTES,PAGE_LOADER:`\0`+VIRTUAL_MODULE_IDS.PAGE_LOADER,ISLAND_MANIFEST:`\0`+VIRTUAL_MODULE_IDS.ISLAND_MANIFEST,RUNTIME_CONFIG:`\0`+VIRTUAL_MODULE_IDS.RUNTIME_CONFIG,CONFIG:`\0`+VIRTUAL_MODULE_IDS.CONFIG};export function createNitroIntegration(t,n={}){let r=o(n,t),i={preset:r.preset,serverDir:n.serverDir??r.serverDir??`./server`,routeRules:r.routeRules,runtimeConfig:r.runtimeConfig,compatibilityDate:r.compatibilityDate,scanDirs:[`.`],noExternals:[`estree-walker`,/^@useavalon\//,/^estree-util/]};n.renderer===!1?i.renderer=!1:r.renderer&&(i.renderer=r.renderer),r.publicRuntimeConfig&&(i.publicRuntimeConfig=r.publicRuntimeConfig),r.publicAssets&&(i.publicAssets=r.publicAssets),r.compressPublicAssets&&(i.compressPublicAssets=r.compressPublicAssets),r.serverEntry&&(i.serverEntry=r.serverEntry);let a=r.traceDeps??[];i.traceDeps=[...new Set([`undici`,...a])],r.prerender&&(i.prerender={routes:[],crawlLinks:!1});let d=e(i),f=createNitroCoordinationPlugin({avalonConfig:t,nitroConfig:n,verbose:t.verbose}),p=createVirtualModulesPlugin({avalonConfig:t,nitroConfig:n,verbose:t.verbose}),m=s(t,n),h=c(t,{verbose:t.verbose,generatePreloadHints:!0}),g=l(u(n.preset??`node_server`,t.isDev));return{nitroOptions:r,plugins:[...Array.isArray(d)?d:[d],f,p,m,h,g]}}export function createNitroCoordinationPlugin(e){let{avalonConfig:t,verbose:n}=e;return{name:`avalon:nitro-coordination`,enforce:`pre`,configResolved(e){globalThis.__avalonConfig=t},configureServer(e){globalThis.__viteDevServer=e;let r=null;async function i(){return r||=await d({baseDir:`${e.config.root||process.cwd()}/src`,devMode:!1}),r}function a(){r=null}A(e,t,n,a),i().catch(e=>{console.warn(`[middleware] Failed to discover middleware:`,e)}),O(e,t.integrations,n).catch(e=>{console.error(`[prewarm] Core modules pre-warm failed:`,e)}),e.middlewares.use(async(r,a,o)=>{let s=r.url||`/`;if(s.endsWith(`.html`)&&(s=s.slice(0,-5)||`/`),s===`/index`&&(s=`/`),s.startsWith(`/@`)||s.startsWith(`/__`)||s.startsWith(`/node_modules/`)||s.startsWith(`/src/client/`)||s.startsWith(`/packages/`)||s.includes(`.`)&&!s.endsWith(`/`)||s.startsWith(`/api/`))return o();try{if(await E(e,s,r,a,i,n)||await R(e,s,t,a))return;let o=await z(e,s,t);if(o){a.statusCode=200,a.setHeader(`Content-Type`,`text/html`),a.end(o);return}await D(e,s,a,t)}catch(e){console.error(`[SSR Error]`,e),a.statusCode=500,a.setHeader(`Content-Type`,`text/html`),a.end(m(e))}})},buildStart(){}}}async function E(e,t,n,r,i,a){let o=performance.now(),s=await i();if(s.length===0)return!1;let c={};for(let[e,t]of Object.entries(n.headers))typeof t==`string`?c[e]=t:Array.isArray(t)&&(c[e]=t.join(`, `));let l=`http://${n.headers.host||`localhost`}${t}`,u=await f({url:l,method:n.method||`GET`,path:t,node:{req:n,res:r},req:new Request(l,{method:n.method||`GET`,headers:c}),context:{}},s,{devMode:!1}),d=performance.now()-o;return d>100&&console.warn(`⚠️ Slow middleware: ${d.toFixed(0)}ms for ${t}`),u?(r.statusCode=u.status,u.headers.forEach((e,t)=>{r.setHeader(t,e)}),r.end(await u.text()),!0):!1}async function D(e,t,n,r){try{let{discoverErrorPages:i,getErrorPageModule:a,generateDefaultErrorPage:o}=await import(`../nitro/error-handler.js`),s=a(404,await i({isDev:r.isDev,pagesDir:r.pagesDir,loadPageModule:async t=>await e.ssrLoadModule(t)}));if(s?.default&&typeof s.default==`function`){let{renderToHtml:e}=await import(`../render/ssr.js`),r=s.default,i=await e({component:()=>r({statusCode:404,message:`Page not found: ${t}`,url:t})},{});n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(i);return}let c=o(404,`Page not found: ${t}`,r.isDev);n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(c)}catch{n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(h(t))}}async function O(e,t,n){let r=performance.now(),i=[{path:b(`src/render/ssr.ts`),assignTo:`ssr`},{path:b(`src/core/layout/enhanced-layout-resolver.ts`),assignTo:`layout`},{path:b(`src/middleware/index.ts`),assignTo:null},...t.map(e=>({path:x(e,`server/renderer.ts`),assignTo:null}))],a=(await Promise.allSettled(i.map(async({path:t,assignTo:n})=>{let r=await e.ssrLoadModule(t);n===`ssr`&&(I=r),n===`layout`&&(L=r)}))).filter(e=>e.status===`fulfilled`).length,o=performance.now()-r;n&&a>0&&console.log(`🔥 SSR ready in ${o.toFixed(0)}ms (${a}/${i.length} core modules)`)}export function createVirtualModulesPlugin(e){let{avalonConfig:t,nitroConfig:n,verbose:r}=e;return{name:`avalon:nitro-virtual-modules`,enforce:`pre`,resolveId(e){return e===VIRTUAL_MODULE_IDS.PAGE_ROUTES?RESOLVED_VIRTUAL_IDS.PAGE_ROUTES:e===VIRTUAL_MODULE_IDS.PAGE_LOADER?RESOLVED_VIRTUAL_IDS.PAGE_LOADER:e===VIRTUAL_MODULE_IDS.ISLAND_MANIFEST?RESOLVED_VIRTUAL_IDS.ISLAND_MANIFEST:e===VIRTUAL_MODULE_IDS.RUNTIME_CONFIG?RESOLVED_VIRTUAL_IDS.RUNTIME_CONFIG:e===VIRTUAL_MODULE_IDS.CONFIG?RESOLVED_VIRTUAL_IDS.CONFIG:null},async load(e){return e===RESOLVED_VIRTUAL_IDS.PAGE_ROUTES?await j(t,r):e===RESOLVED_VIRTUAL_IDS.PAGE_LOADER?await M(t,r):e===RESOLVED_VIRTUAL_IDS.ISLAND_MANIFEST?N():e===RESOLVED_VIRTUAL_IDS.RUNTIME_CONFIG?P(t,n):e===RESOLVED_VIRTUAL_IDS.CONFIG?generateConfigModule(t,n):null},handleHotUpdate({file:e,server:n}){if(e.includes(t.pagesDir)){let e=n.moduleGraph.getModuleById(RESOLVED_VIRTUAL_IDS.PAGE_ROUTES);e&&n.moduleGraph.invalidateModule(e)}if(e.includes(`vite.config`)||e.includes(`avalon.config`)||e.includes(`nitro.config`)){let e=n.moduleGraph.getModuleById(RESOLVED_VIRTUAL_IDS.CONFIG);e&&n.moduleGraph.invalidateModule(e)}}}}function A(e,t,n,r){e.watcher.on(`change`,e=>{e.includes(`_middleware`)&&(p(),r?.()),(e.includes(`/render/`)||e.includes(`/layout/`)||e.includes(`/islands/`))&&(I=null,L=null),(e.includes(`/layouts/`)||e.includes(`_layout`))&&globalThis.__avalonLayoutResolver?.clearCache?.()}),e.watcher.on(`add`,e=>{e.includes(`_middleware`)&&(p(),r?.())}),e.watcher.on(`unlink`,e=>{e.includes(`_middleware`)&&(p(),r?.())})}async function j(e,t){try{let{getAllPageDirs:t}=await import(`./module-discovery.js`),{discoverPageRoutesFromMultipleDirs:n}=await import(`../nitro/route-discovery.js`),r=await n(await t(e.pagesDir,e.modules,process.cwd()),{developmentMode:e.isDev});return`export const pageRoutes = ${JSON.stringify(r,null,2)};\nexport default pageRoutes;\n`}catch{return`export const pageRoutes = [];
1
+ import{existsSync as e}from"node:fs";import{stat as t}from"node:fs/promises";import{createRequire as n}from"node:module";import{dirname as r,join as i}from"node:path";import{nitro as a}from"nitro/vite";import{isRunnableDevEnvironment as o}from"vite";import{getUniversalCSSForHead as s}from"../islands/universal-css-collector.js";import{getUniversalHeadForInjection as c}from"../islands/universal-head-collector.js";import{clearMiddlewareCache as l,discoverScopedMiddleware as u,executeScopedMiddleware as d}from"../middleware/index.js";import{createNitroConfig as f}from"../nitro/config.js";import{createIslandManifestPlugin as p,createNitroBuildPlugin as m,createSourceMapConfig as h,createSourceMapPlugin as g}from"../nitro/index.js";import{collectCssFromModuleGraph as _,injectSsrCss as v}from"../render/collect-css.js";import{generateErrorPage as y,generateFallback404 as b}from"../render/error-pages.js";function x(t){let a=i(r(n(import.meta.url).resolve(`@useavalon/avalon`)),t);if(t.endsWith(`.ts`)&&!e(a)){let t=a.replace(/\.ts$/,`.js`);if(e(t))return t}return a}function S(t,a){let o=i(r(n(i(process.cwd(),`package.json`)).resolve(`@useavalon/${t}`)),a);if(a.endsWith(`.ts`)&&!e(o)){let t=o.replace(/\.ts$/,`.js`);if(e(t))return t}return o}export const VIRTUAL_MODULE_IDS={PAGE_ROUTES:`virtual:avalon/page-routes`,PAGE_LOADER:`virtual:avalon/page-loader`,ISLAND_MANIFEST:`virtual:avalon/island-manifest`,RUNTIME_CONFIG:`virtual:avalon/runtime-config`,CONFIG:`virtual:avalon/config`};export const RESOLVED_VIRTUAL_IDS={PAGE_ROUTES:`\0`+VIRTUAL_MODULE_IDS.PAGE_ROUTES,PAGE_LOADER:`\0`+VIRTUAL_MODULE_IDS.PAGE_LOADER,ISLAND_MANIFEST:`\0`+VIRTUAL_MODULE_IDS.ISLAND_MANIFEST,RUNTIME_CONFIG:`\0`+VIRTUAL_MODULE_IDS.RUNTIME_CONFIG,CONFIG:`\0`+VIRTUAL_MODULE_IDS.CONFIG};export function createNitroIntegration(e,t={}){let n=f(t,e),r={preset:n.preset,serverDir:t.serverDir??n.serverDir??`./server`,routeRules:n.routeRules,runtimeConfig:n.runtimeConfig,compatibilityDate:n.compatibilityDate,scanDirs:[`.`],noExternals:[`estree-walker`,/^@useavalon\//,/^estree-util/]};t.renderer===!1?r.renderer=!1:n.renderer&&(r.renderer=n.renderer),n.publicRuntimeConfig&&(r.publicRuntimeConfig=n.publicRuntimeConfig),n.publicAssets&&(r.publicAssets=n.publicAssets),n.compressPublicAssets&&(r.compressPublicAssets=n.compressPublicAssets),n.serverEntry&&(r.serverEntry=n.serverEntry);let i=n.traceDeps??[];r.traceDeps=[...new Set([`undici`,...i])],n.prerender&&(r.prerender={routes:[],crawlLinks:!1});let o=a(r),s=createNitroCoordinationPlugin({avalonConfig:e,nitroConfig:t,verbose:e.verbose}),c=createVirtualModulesPlugin({avalonConfig:e,nitroConfig:t,verbose:e.verbose}),l=m(e,t),u=p(e,{verbose:e.verbose,generatePreloadHints:!0}),d=g(h(t.preset??`node_server`,e.isDev));return{nitroOptions:n,plugins:[...Array.isArray(o)?o:[o],s,c,l,u,d]}}export function createNitroCoordinationPlugin(e){let{avalonConfig:t,verbose:n}=e;return{name:`avalon:nitro-coordination`,enforce:`pre`,configResolved(e){globalThis.__avalonConfig=t},configureServer(e){globalThis.__viteDevServer=e;let r=null;async function i(){return r||=await u({baseDir:`${e.config.root||process.cwd()}/src`,devMode:!1}),r}function a(){r=null}j(e,t,n,a),i().catch(e=>{console.warn(`[middleware] Failed to discover middleware:`,e)});let s=e.environments?.ssr,c=!!s&&o(s);c&&k(e,t.integrations,n).catch(e=>{console.error(`[prewarm] Core modules pre-warm failed:`,e)}),e.middlewares.use(async(r,a,o)=>{if(!c)return o();let s=r.url||`/`;if(s.endsWith(`.html`)&&(s=s.slice(0,-5)||`/`),s===`/index`&&(s=`/`),s.startsWith(`/@`)||s.startsWith(`/__`)||s.startsWith(`/node_modules/`)||s.startsWith(`/src/client/`)||s.startsWith(`/packages/`)||s.includes(`.`)&&!s.endsWith(`/`)||s.startsWith(`/api/`))return o();try{if(await D(e,s,r,a,i,n)||await z(e,s,t,a))return;let o=await B(e,s,t);if(o){a.statusCode=200,a.setHeader(`Content-Type`,`text/html`),a.end(o);return}await O(e,s,a,t)}catch(e){console.error(`[SSR Error]`,e),a.statusCode=500,a.setHeader(`Content-Type`,`text/html`),a.end(y(e))}})},buildStart(){}}}async function D(e,t,n,r,i,a){let o=performance.now(),s=await i();if(s.length===0)return!1;let c={};for(let[e,t]of Object.entries(n.headers))typeof t==`string`?c[e]=t:Array.isArray(t)&&(c[e]=t.join(`, `));let l=`http://${n.headers.host||`localhost`}${t}`,u=await d({url:l,method:n.method||`GET`,path:t,node:{req:n,res:r},req:new Request(l,{method:n.method||`GET`,headers:c}),context:{}},s,{devMode:!1}),f=performance.now()-o;return f>100&&console.warn(`⚠️ Slow middleware: ${f.toFixed(0)}ms for ${t}`),u?(r.statusCode=u.status,u.headers.forEach((e,t)=>{r.setHeader(t,e)}),r.end(await u.text()),!0):!1}async function O(e,t,n,r){try{let{discoverErrorPages:i,getErrorPageModule:a,generateDefaultErrorPage:o}=await import(`../nitro/error-handler.js`),s=a(404,await i({isDev:r.isDev,pagesDir:r.pagesDir,loadPageModule:async t=>await e.ssrLoadModule(t)}));if(s?.default&&typeof s.default==`function`){let{renderToHtml:e}=await import(`../render/ssr.js`),r=s.default,i=await e({component:()=>r({statusCode:404,message:`Page not found: ${t}`,url:t})},{});n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(i);return}let c=o(404,`Page not found: ${t}`,r.isDev);n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(c)}catch{n.statusCode=404,n.setHeader(`Content-Type`,`text/html`),n.end(b(t))}}async function k(e,t,n){let r=performance.now(),i=[{path:x(`src/render/ssr.ts`),assignTo:`ssr`},{path:x(`src/core/layout/enhanced-layout-resolver.ts`),assignTo:`layout`},{path:x(`src/middleware/index.ts`),assignTo:null},...t.map(e=>({path:S(e,`server/renderer.ts`),assignTo:null}))],a=(await Promise.allSettled(i.map(async({path:t,assignTo:n})=>{let r=await e.ssrLoadModule(t);n===`ssr`&&(L=r),n===`layout`&&(R=r)}))).filter(e=>e.status===`fulfilled`).length,o=performance.now()-r;n&&a>0&&console.log(`🔥 SSR ready in ${o.toFixed(0)}ms (${a}/${i.length} core modules)`)}export function createVirtualModulesPlugin(e){let{avalonConfig:t,nitroConfig:n,verbose:r}=e;return{name:`avalon:nitro-virtual-modules`,enforce:`pre`,resolveId(e){return e===VIRTUAL_MODULE_IDS.PAGE_ROUTES?RESOLVED_VIRTUAL_IDS.PAGE_ROUTES:e===VIRTUAL_MODULE_IDS.PAGE_LOADER?RESOLVED_VIRTUAL_IDS.PAGE_LOADER:e===VIRTUAL_MODULE_IDS.ISLAND_MANIFEST?RESOLVED_VIRTUAL_IDS.ISLAND_MANIFEST:e===VIRTUAL_MODULE_IDS.RUNTIME_CONFIG?RESOLVED_VIRTUAL_IDS.RUNTIME_CONFIG:e===VIRTUAL_MODULE_IDS.CONFIG?RESOLVED_VIRTUAL_IDS.CONFIG:null},async load(e){return e===RESOLVED_VIRTUAL_IDS.PAGE_ROUTES?await M(t,r):e===RESOLVED_VIRTUAL_IDS.PAGE_LOADER?await N(t,r):e===RESOLVED_VIRTUAL_IDS.ISLAND_MANIFEST?P():e===RESOLVED_VIRTUAL_IDS.RUNTIME_CONFIG?F(t,n):e===RESOLVED_VIRTUAL_IDS.CONFIG?generateConfigModule(t,n):null},handleHotUpdate({file:e,server:n}){if(e.includes(t.pagesDir)){let e=n.moduleGraph.getModuleById(RESOLVED_VIRTUAL_IDS.PAGE_ROUTES);e&&n.moduleGraph.invalidateModule(e)}if(e.includes(`vite.config`)||e.includes(`avalon.config`)||e.includes(`nitro.config`)){let e=n.moduleGraph.getModuleById(RESOLVED_VIRTUAL_IDS.CONFIG);e&&n.moduleGraph.invalidateModule(e)}}}}function j(e,t,n,r){e.watcher.on(`change`,e=>{e.includes(`_middleware`)&&(l(),r?.()),(e.includes(`/render/`)||e.includes(`/layout/`)||e.includes(`/islands/`))&&(L=null,R=null),(e.includes(`/layouts/`)||e.includes(`_layout`))&&globalThis.__avalonLayoutResolver?.clearCache?.()}),e.watcher.on(`add`,e=>{e.includes(`_middleware`)&&(l(),r?.())}),e.watcher.on(`unlink`,e=>{e.includes(`_middleware`)&&(l(),r?.())})}async function M(e,t){try{let{getAllPageDirs:t}=await import(`./module-discovery.js`),{discoverPageRoutesFromMultipleDirs:n}=await import(`../nitro/route-discovery.js`),r=await n(await t(e.pagesDir,e.modules,process.cwd()),{developmentMode:e.isDev});return`export const pageRoutes = ${JSON.stringify(r,null,2)};\nexport default pageRoutes;\n`}catch{return`export const pageRoutes = [];
2
2
  export default pageRoutes;
3
- `}}async function M(e,t){try{let{getAllPageDirs:t}=await import(`./module-discovery.js`),{discoverPageRoutesFromMultipleDirs:n}=await import(`../nitro/route-discovery.js`),{relative:r}=await import(`node:path`),i=process.cwd(),a=await n(await t(e.pagesDir,e.modules,i),{developmentMode:e.isDev}),o=[],s=[];for(let e=0;e<a.length;e++){let t=a[e],n=`page_${e}`,c=r(i,t.filePath).replaceAll(`\\`,`/`),l=c.startsWith(`/`)?c:`/`+c;o.push(`import * as ${n} from '${l}';`),s.push(` { pattern: ${JSON.stringify(t.pattern)}, params: ${JSON.stringify(t.params)}, module: ${n} }`)}return[...o,``,`const routes = [`,s.join(`,
3
+ `}}async function N(e,t){try{let{getAllPageDirs:t}=await import(`./module-discovery.js`),{discoverPageRoutesFromMultipleDirs:n}=await import(`../nitro/route-discovery.js`),{relative:r}=await import(`node:path`),i=process.cwd(),a=await n(await t(e.pagesDir,e.modules,i),{developmentMode:e.isDev}),o=[],s=[];for(let e=0;e<a.length;e++){let t=a[e],n=`page_${e}`,c=r(i,t.filePath).replaceAll(`\\`,`/`),l=c.startsWith(`/`)?c:`/`+c;o.push(`import * as ${n} from '${l}';`),s.push(` { pattern: ${JSON.stringify(t.pattern)}, params: ${JSON.stringify(t.params)}, module: ${n} }`)}return[...o,``,`const routes = [`,s.join(`,
4
4
  `),`];`,``,`/**`,` * Match a pathname against discovered routes and return the page module.`,` * Uses the same pattern matching as Avalon's route discovery.`,` */`,`export function loadPage(pathname) {`,` const cleanPath = pathname.split('?')[0];`,` for (const route of routes) {`,` if (matchRoute(cleanPath, route.pattern, route.params)) {`,` return route.module;`,` }`,` }`,` return null;`,`}`,``,`function matchRoute(pathname, pattern, paramNames) {`,` // Exact match`,` if (pattern === pathname) return true;`,` // Normalize trailing slashes`,` const normPath = pathname === '/' ? '/' : pathname.replace(/\\/$/, '');`,` const normPattern = pattern === '/' ? '/' : pattern.replace(/\\/$/, '');`,` if (normPath === normPattern) return true;`,` // Dynamic segments: /users/:id matches /users/123`,` if (paramNames.length > 0) {`,` const patternParts = normPattern.split('/');`,` const pathParts = normPath.split('/');`,` if (patternParts.length !== pathParts.length) return false;`,` return patternParts.every((part, i) => part.startsWith(':') || part === pathParts[i]);`,` }`,` return false;`,`}`,``,`export default { loadPage, routes };`,``].join(`
5
5
  `)}catch(e){return console.error(`[page-loader] Failed to generate page loader:`,e),`export function loadPage() { return null; }
6
6
  export default { loadPage, routes: [] };
7
- `}}function N(){return`export const islandManifest = { islands: {}, clientEntry: "", css: [] };
7
+ `}}function P(){return`export const islandManifest = { islands: {}, clientEntry: "", css: [] };
8
8
  export default islandManifest;
9
- `}function P(e,t){let n={avalon:{streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev},...t.runtimeConfig};return`export const runtimeConfig = ${JSON.stringify(n,null,2)};\nexport function useRuntimeConfig() { return runtimeConfig; }\nexport default runtimeConfig;\n`}export function generateConfigModule(e,t){let n={streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev,...t.runtimeConfig};return`const config = ${JSON.stringify(n,null,2)};\nexport function useAvalonConfig() { return config; }\nexport default config;\n`}export function getViteDevServer(){return globalThis.__viteDevServer}export function getAvalonConfig(){return globalThis.__avalonConfig}export function isDevelopmentMode(){return globalThis.__avalonConfig?.isDev??!0}const F=`<!--AVALON_STREAM_BOUNDARY-->`;let I=null,L=null;async function R(e,t,n,r){if(!n.modules)return!1;let i=t.split(`?`)[0],a=await U(i,n,e);if(!a)return!1;try{let t=await e.ssrLoadModule(a),n=t.default;if(!n)return!1;let o=t.layoutConfig,s=await g(e,a),c=await H(i,e),l=[];for(let t of c){let n=await e.ssrLoadModule(t);l.push({file:t,module:n})}for(let t of c){let n=await g(e,t);s.push(...n)}if(l.length===0)return!1;let{render:u}=await e.ssrLoadModule(`preact-render-to-string`),{h:d}=await e.ssrLoadModule(`preact`),f=o?.skipLayouts||[],p=l.filter(({file:e})=>{let t=e.split(`/`).pop()?.replace(/\.[^.]+$/,``)||``;return!f.includes(t)}),m=t.frontmatter,h=t.metadata,_={children:null,frontmatter:{...m,...h,currentPath:i},params:{},url:i},b=[],x=[];for(let e of p){let t=e.module.default;if(!(!t||typeof t!=`function`))try{let n=t({..._,children:d(`div`,null,`test`)}),r=u(n instanceof Promise?await n:n);r.trim().startsWith(`<html`)||r.includes(`<!DOCTYPE`)?b.push(e):x.push(e)}catch{x.push(e)}}if(b.length===0)return!1;let{module:S}=b[b.length-1],C=S.default;if(!C||typeof C!=`function`)return!1;let w;try{let e=C({..._,children:d(`div`,{dangerouslySetInnerHTML:{__html:F}})});w=u(e instanceof Promise?await e:e)}catch{return!1}let T=w.indexOf(F);if(T===-1)return!1;let E=w.slice(0,T),D=w.slice(T+29),O=E;if(s.length>0){let e=`<style data-avalon-ssr-css>${s.join(`
9
+ `}function F(e,t){let n={avalon:{streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev},...t.runtimeConfig};return`export const runtimeConfig = ${JSON.stringify(n,null,2)};\nexport function useRuntimeConfig() { return runtimeConfig; }\nexport default runtimeConfig;\n`}export function generateConfigModule(e,t){let n={streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev,...t.runtimeConfig};return`const config = ${JSON.stringify(n,null,2)};\nexport function useAvalonConfig() { return config; }\nexport default config;\n`}export function getViteDevServer(){return globalThis.__viteDevServer}export function getAvalonConfig(){return globalThis.__avalonConfig}export function isDevelopmentMode(){return globalThis.__avalonConfig?.isDev??!0}const I=`<!--AVALON_STREAM_BOUNDARY-->`;let L=null,R=null;async function z(e,t,n,r){if(!n.modules)return!1;let i=t.split(`?`)[0],a=await W(i,n,e);if(!a)return!1;try{let t=await e.ssrLoadModule(a),n=t.default;if(!n)return!1;let o=t.layoutConfig,l=await _(e,a),u=await U(i,e),d=[];for(let t of u){let n=await e.ssrLoadModule(t);d.push({file:t,module:n})}for(let t of u){let n=await _(e,t);l.push(...n)}if(d.length===0)return!1;let{render:f}=await e.ssrLoadModule(`preact-render-to-string`),{h:p}=await e.ssrLoadModule(`preact`),m=o?.skipLayouts||[],h=d.filter(({file:e})=>{let t=e.split(`/`).pop()?.replace(/\.[^.]+$/,``)||``;return!m.includes(t)}),g=t.frontmatter,v=t.metadata,y={children:null,frontmatter:{...g,...v,currentPath:i},params:{},url:i},b=[],x=[];for(let e of h){let t=e.module.default;if(!(!t||typeof t!=`function`))try{let n=t({...y,children:p(`div`,null,`test`)}),r=f(n instanceof Promise?await n:n);r.trim().startsWith(`<html`)||r.includes(`<!DOCTYPE`)?b.push(e):x.push(e)}catch{x.push(e)}}if(b.length===0)return!1;let{module:S}=b[b.length-1],C=S.default;if(!C||typeof C!=`function`)return!1;let w;try{let e=C({...y,children:p(`div`,{dangerouslySetInnerHTML:{__html:I}})});w=f(e instanceof Promise?await e:e)}catch{return!1}let T=w.indexOf(I);if(T===-1)return!1;let E=w.slice(0,T),D=w.slice(T+29),O=E;if(l.length>0){let e=`<style data-avalon-ssr-css>${l.join(`
10
10
  `)}</style>`;O=E.includes(`</head>`)?E.replace(`</head>`,`${e}\n</head>`):E+e}O.trim().toLowerCase().startsWith(`<!doctype`)||(O=`<!DOCTYPE html>
11
- `+O);let k=v(!0);k&&O.includes(`</head>`)&&(O=O.replace(`</head>`,`${k}\n</head>`));let A=y(!0);A&&O.includes(`</head>`)&&(O=O.replace(`</head>`,`${A}\n</head>`)),r.statusCode=200,r.setHeader(`Content-Type`,`text/html; charset=utf-8`),r.setHeader(`Transfer-Encoding`,`chunked`),r.setHeader(`X-Avalon-Streaming`,`1`),r.flushHeaders(),r.write(O);let j;try{let e=typeof n==`function`?n():n;j=u(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR Streaming] Error rendering page component:`,e),j=`<div>Error rendering page</div>`}if(j.trim().startsWith(`<!DOCTYPE html>`)||j.trim().startsWith(`<html`))return r.end(j),!0;let M=j;for(let{module:e}of x){let t=e.default;if(!(!t||typeof t!=`function`))try{let e=t({..._,children:d(`div`,{dangerouslySetInnerHTML:{__html:M}})});M=u(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR Streaming] Error rendering wrapper layout:`,e)}}let N=M+D;if(!N.includes(`/src/client/main.js`)&&!N.includes(`/@vite/client`)){let e=N.lastIndexOf(`</body>`);e!==-1&&(N=N.slice(0,e)+`
11
+ `+O);let k=s(!0);k&&O.includes(`</head>`)&&(O=O.replace(`</head>`,`${k}\n</head>`));let A=c(!0);A&&O.includes(`</head>`)&&(O=O.replace(`</head>`,`${A}\n</head>`)),r.statusCode=200,r.setHeader(`Content-Type`,`text/html; charset=utf-8`),r.setHeader(`Transfer-Encoding`,`chunked`),r.setHeader(`X-Avalon-Streaming`,`1`),r.flushHeaders(),r.write(O);let j;try{let e=typeof n==`function`?n():n;j=f(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR Streaming] Error rendering page component:`,e),j=`<div>Error rendering page</div>`}if(j.trim().startsWith(`<!DOCTYPE html>`)||j.trim().startsWith(`<html`))return r.end(j),!0;let M=j;for(let{module:e}of x){let t=e.default;if(!(!t||typeof t!=`function`))try{let e=t({...y,children:p(`div`,{dangerouslySetInnerHTML:{__html:M}})});M=f(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR Streaming] Error rendering wrapper layout:`,e)}}let N=M+D;if(!N.includes(`/src/client/main.js`)&&!N.includes(`/@vite/client`)){let e=N.lastIndexOf(`</body>`);e!==-1&&(N=N.slice(0,e)+`
12
12
  <script type="module" src="/@vite/client"><\/script>
13
13
  <script type="module" src="/src/client/main.js"><\/script>
14
- `+N.slice(e))}return r.end(N),!0}catch(e){return r.headersSent?(r.end(`<div>Streaming SSR error: ${e.message}</div></body></html>`),!0):!1}}async function z(e,t,n){let r=t.split(`?`)[0],i=await U(r,n,e);if(!i)return null;try{let t=await e.ssrLoadModule(i),a=t.default;if(!a)return console.warn(`[SSR] Page ${i} has no default export`),null;let o=await g(e,i),s=await H(r,e),c=[];for(let t of s){let n=await e.ssrLoadModule(t);c.push({file:t,module:n})}for(let t of s){let n=await g(e,t);o.push(...n)}let l;return l=n.modules&&c.length>0?await B(a,t,c,r,n,e):await W(a,t,r,n,e),o.length>0&&(l=_(l,o)),l}catch(e){throw console.error(`[SSR] Error rendering ${i}:`,e),e}}async function B(e,t,n,r,i,a){let{render:o}=await a.ssrLoadModule(`preact-render-to-string`),{h:s}=await a.ssrLoadModule(`preact`),c=t.layoutConfig?.skipLayouts||[],l=n.filter(({file:e})=>{let t=e.split(`/`).pop()?.replace(/\.[^.]+$/,``)||``;return!c.includes(t)}),u;try{let t=typeof e==`function`?e():e;u=o(t instanceof Promise?await t:t)}catch(e){console.error(`[SSR] Error rendering page component:`,e),u=`<div>Error rendering page</div>`}if(u.trim().startsWith(`<!DOCTYPE html>`)||u.trim().startsWith(`<html`))return V(u);let d=t.frontmatter,f=t.metadata,p={children:null,frontmatter:{...d,...f,currentPath:r},params:{},url:r},m=[],h=[];for(let e of l){let t=e.module.default;if(!(!t||typeof t!=`function`))try{let n=t({...p,children:s(`div`,null,`test`)}),r=o(n instanceof Promise?await n:n);r.trim().startsWith(`<html`)||r.includes(`<!DOCTYPE`)?m.push(e):h.push(e)}catch{h.push(e)}}let g=u;for(let{module:e}of h){let t=e.default;if(!(!t||typeof t!=`function`))try{let e=t({...p,children:s(`div`,{dangerouslySetInnerHTML:{__html:g}})});g=o(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR] Error rendering wrapper layout:`,e)}}if(m.length>0){let{module:e}=m[m.length-1],t=e.default;if(t&&typeof t==`function`)try{let e=t({...p,children:s(`div`,{dangerouslySetInnerHTML:{__html:g}})});g=o(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR] Error rendering shell layout:`,e)}}if(g.trim().startsWith(`<!DOCTYPE html>`)||g.trim().startsWith(`<html`))return V(g);let _=t.metadata||{},v=_.title||`Avalon App`,y=_.description||``;return`<!DOCTYPE html>
14
+ `+N.slice(e))}return r.end(N),!0}catch(e){return r.headersSent?(r.end(`<div>Streaming SSR error: ${e.message}</div></body></html>`),!0):!1}}async function B(e,t,n){let r=t.split(`?`)[0],i=await W(r,n,e);if(!i)return null;try{let t=await e.ssrLoadModule(i),a=t.default;if(!a)return console.warn(`[SSR] Page ${i} has no default export`),null;let o=await _(e,i),s=await U(r,e),c=[];for(let t of s){let n=await e.ssrLoadModule(t);c.push({file:t,module:n})}for(let t of s){let n=await _(e,t);o.push(...n)}let l;return l=n.modules&&c.length>0?await V(a,t,c,r,n,e):await G(a,t,r,n,e),o.length>0&&(l=v(l,o)),l}catch(e){throw console.error(`[SSR] Error rendering ${i}:`,e),e}}async function V(e,t,n,r,i,a){let{render:o}=await a.ssrLoadModule(`preact-render-to-string`),{h:s}=await a.ssrLoadModule(`preact`),c=t.layoutConfig?.skipLayouts||[],l=n.filter(({file:e})=>{let t=e.split(`/`).pop()?.replace(/\.[^.]+$/,``)||``;return!c.includes(t)}),u;try{let t=typeof e==`function`?e():e;u=o(t instanceof Promise?await t:t)}catch(e){console.error(`[SSR] Error rendering page component:`,e),u=`<div>Error rendering page</div>`}if(u.trim().startsWith(`<!DOCTYPE html>`)||u.trim().startsWith(`<html`))return H(u);let d=t.frontmatter,f=t.metadata,p={children:null,frontmatter:{...d,...f,currentPath:r},params:{},url:r},m=[],h=[];for(let e of l){let t=e.module.default;if(!(!t||typeof t!=`function`))try{let n=t({...p,children:s(`div`,null,`test`)}),r=o(n instanceof Promise?await n:n);r.trim().startsWith(`<html`)||r.includes(`<!DOCTYPE`)?m.push(e):h.push(e)}catch{h.push(e)}}let g=u;for(let{module:e}of h){let t=e.default;if(!(!t||typeof t!=`function`))try{let e=t({...p,children:s(`div`,{dangerouslySetInnerHTML:{__html:g}})});g=o(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR] Error rendering wrapper layout:`,e)}}if(m.length>0){let{module:e}=m[m.length-1],t=e.default;if(t&&typeof t==`function`)try{let e=t({...p,children:s(`div`,{dangerouslySetInnerHTML:{__html:g}})});g=o(e instanceof Promise?await e:e)}catch(e){console.error(`[SSR] Error rendering shell layout:`,e)}}if(g.trim().startsWith(`<!DOCTYPE html>`)||g.trim().startsWith(`<html`))return H(g);let _=t.metadata||{},v=_.title||`Avalon App`,y=_.description||``;return`<!DOCTYPE html>
15
15
  <html lang="en">
16
16
  <head>
17
17
  <meta charset="utf-8">
18
18
  <meta name="viewport" content="width=device-width, initial-scale=1">
19
- <title>${G(v)}</title>
20
- ${y?`<meta name="description" content="${G(y)}">`:``}
19
+ <title>${K(v)}</title>
20
+ ${y?`<meta name="description" content="${K(y)}">`:``}
21
21
  <script type="module" src="/@vite/client"><\/script>
22
22
  </head>
23
23
  <body>
24
24
  ${g}
25
25
  <script type="module" src="/src/client/main.js"><\/script>
26
26
  </body>
27
- </html>`}function V(e){let t=e;if(t.trim().toLowerCase().startsWith(`<!doctype`)||(t=`<!DOCTYPE html>
28
- `+t),!t.includes(`data-universal-ssr="true"`)){let e=v(!0);e&&t.includes(`</head>`)&&(t=t.replace(`</head>`,`${e}\n</head>`))}let n=y(!0);if(n&&t.includes(`</head>`)&&(t=t.replace(`</head>`,`${n}\n</head>`)),t.includes(`/src/client/main.js`)||t.includes(`/@vite/client`))return t;let r=t.lastIndexOf(`</body>`);return r===-1?t+`
27
+ </html>`}function H(e){let t=e;if(t.trim().toLowerCase().startsWith(`<!doctype`)||(t=`<!DOCTYPE html>
28
+ `+t),!t.includes(`data-universal-ssr="true"`)){let e=s(!0);e&&t.includes(`</head>`)&&(t=t.replace(`</head>`,`${e}\n</head>`))}let n=c(!0);if(n&&t.includes(`</head>`)&&(t=t.replace(`</head>`,`${n}\n</head>`)),t.includes(`/src/client/main.js`)||t.includes(`/@vite/client`))return t;let r=t.lastIndexOf(`</body>`);return r===-1?t+`
29
29
  <script type="module" src="/@vite/client"><\/script>
30
30
  <script type="module" src="/src/client/main.js"><\/script>`:t.slice(0,r)+`
31
31
  <script type="module" src="/@vite/client"><\/script>
32
32
  <script type="module" src="/src/client/main.js"><\/script>
33
- `+t.slice(r)}async function H(e,n){let r=n.config.root||process.cwd(),i=globalThis.__avalonConfig,a=`_layout.tsx`,o=[],s=e.split(`/`).filter(Boolean),c=[``];for(let e=0;e<s.length;e++)c.push(`/`+s.slice(0,e+1).join(`/`));async function l(e){try{if((await t(e)).isFile()){let t=e.slice(r.length);o.includes(t)||o.push(t)}}catch{}}if(i?.layoutsDir&&await l(`${`${r}/${i.layoutsDir}`}/${a}`),i?.modules){let e=`${r}/${i.modules.dir}`,t=i.modules.layoutsDirName,n=s[0]||``,o=[`home`,`root`,`main`,`index`];if(!n||o.includes(n.toLowerCase()))for(let n of o)await l(`${e}/${n}/${t}/${a}`);else await l(`${e}/${n}/${t}/${a}`)}let u=`${r}/src/layouts`;for(let e of c)await l(e===``?`${u}/${a}`:`${u}${e}/${a}`);return o}async function U(e,n,r){let i=e;i.endsWith(`/`)&&i!==`/`&&(i=i.slice(0,-1)),i===`/`&&(i=`/index`);let a=[`.tsx`,`.ts`,`.jsx`,`.js`,`.mdx`,`.md`],o=r.config.root||process.cwd();async function s(e){try{if((await t(`${o}/${e}`)).isFile())return`/${e}`}catch{}return null}if(n.modules){let t=n.modules.dir,r=n.modules.pagesDirName,o=e.split(`/`).filter(Boolean),c=o[0]||``,l=[`home`,`root`,`main`,`index`],u,d;if(!c||l.includes(c.toLowerCase()))u=`home`,d=i;else{u=c;let e=o.slice(1);d=e.length>0?`/`+e.join(`/`):`/index`}for(let e of a){let n=await s(`${t}/${u}/${r}${d}${e}`);if(n)return n}if(!d.endsWith(`/index`))for(let e of a){let n=await s(`${t}/${u}/${r}${d}/index${e}`);if(n)return n}}let c=n.pagesDir;for(let e of a){let t=await s(`${c}${i}${e}`);if(t)return t}if(!i.endsWith(`/index`))for(let e of a){let t=await s(`${c}${i}/index${e}`);if(t)return t}return null}async function W(e,t,n,r,i){let a=t.metadata||{};try{I||=await i.ssrLoadModule(b(`src/render/ssr.ts`));let o=I;L||=await i.ssrLoadModule(b(`src/core/layout/enhanced-layout-resolver.ts`));let s=L,c={component:()=>typeof e==`function`?e():e,options:{title:a.title||`Avalon App`},frontmatter:t.frontmatter};if(o.renderToHtmlWithLayouts&&s.EnhancedLayoutResolver&&s.EnhancedLayoutResolverUtils)try{let e=i.config.root||process.cwd();if(!globalThis.__avalonLayoutResolver){let t=s.EnhancedLayoutResolver,n=r.layoutsDir||`src/layouts`;globalThis.__avalonLayoutResolver=new t({baseDirectory:`${e}/${n}`,filePattern:`_layout.tsx`,excludeDirectories:[`node_modules`,`.git`,`dist`,`build`],enableWatching:!0,developmentMode:!1,enableCaching:!0,cacheTTL:60*1e3,maxCacheSize:100,enableStreaming:!0,enableErrorBoundaries:!0,enableMetrics:!1,enableDebugInfo:!1,modulesDir:r.modules?`${e}/${r.modules.dir}`:void 0,modulesLayoutsDirName:r.modules?.layoutsDirName})}let t=`http://localhost${n}`,l={params:{},query:{},url:t,request:{method:`GET`,url:t,headers:new Headers}};return await o.renderToHtmlWithLayouts(c,globalThis.__avalonLayoutResolver,l,n,{title:a.title||`Avalon App`},void 0,{suppressWarnings:!0})}catch{}if(o.renderToHtml)return await o.renderToHtml(c,{title:a.title||`Avalon App`},void 0,{suppressWarnings:!0})}catch{}let o=a.title||`Avalon App`,s=a.description||``,c=``;try{let t=await i.ssrLoadModule(`preact-render-to-string`);t.render&&typeof e==`function`&&(c=t.render(e()))}catch{c=`<p>Loading page: ${G(n)}</p>`}return`<!DOCTYPE html>
33
+ `+t.slice(r)}async function U(e,n){let r=n.config.root||process.cwd(),i=globalThis.__avalonConfig,a=`_layout.tsx`,o=[],s=e.split(`/`).filter(Boolean),c=[``];for(let e=0;e<s.length;e++)c.push(`/`+s.slice(0,e+1).join(`/`));async function l(e){try{if((await t(e)).isFile()){let t=e.slice(r.length);o.includes(t)||o.push(t)}}catch{}}if(i?.layoutsDir&&await l(`${`${r}/${i.layoutsDir}`}/${a}`),i?.modules){let e=`${r}/${i.modules.dir}`,t=i.modules.layoutsDirName,n=s[0]||``,o=[`home`,`root`,`main`,`index`];if(!n||o.includes(n.toLowerCase()))for(let n of o)await l(`${e}/${n}/${t}/${a}`);else await l(`${e}/${n}/${t}/${a}`)}let u=`${r}/src/layouts`;for(let e of c)await l(e===``?`${u}/${a}`:`${u}${e}/${a}`);return o}async function W(e,n,r){let i=e;i.endsWith(`/`)&&i!==`/`&&(i=i.slice(0,-1)),i===`/`&&(i=`/index`);let a=[`.tsx`,`.ts`,`.jsx`,`.js`,`.mdx`,`.md`],o=r.config.root||process.cwd();async function s(e){try{if((await t(`${o}/${e}`)).isFile())return`/${e}`}catch{}return null}if(n.modules){let t=n.modules.dir,r=n.modules.pagesDirName,o=e.split(`/`).filter(Boolean),c=o[0]||``,l=[`home`,`root`,`main`,`index`],u,d;if(!c||l.includes(c.toLowerCase()))u=`home`,d=i;else{u=c;let e=o.slice(1);d=e.length>0?`/`+e.join(`/`):`/index`}for(let e of a){let n=await s(`${t}/${u}/${r}${d}${e}`);if(n)return n}if(!d.endsWith(`/index`))for(let e of a){let n=await s(`${t}/${u}/${r}${d}/index${e}`);if(n)return n}}let c=n.pagesDir;for(let e of a){let t=await s(`${c}${i}${e}`);if(t)return t}if(!i.endsWith(`/index`))for(let e of a){let t=await s(`${c}${i}/index${e}`);if(t)return t}return null}async function G(e,t,n,r,i){let a=t.metadata||{};try{L||=await i.ssrLoadModule(x(`src/render/ssr.ts`));let o=L;R||=await i.ssrLoadModule(x(`src/core/layout/enhanced-layout-resolver.ts`));let s=R,c={component:()=>typeof e==`function`?e():e,options:{title:a.title||`Avalon App`},frontmatter:t.frontmatter};if(o.renderToHtmlWithLayouts&&s.EnhancedLayoutResolver&&s.EnhancedLayoutResolverUtils)try{let e=i.config.root||process.cwd();if(!globalThis.__avalonLayoutResolver){let t=s.EnhancedLayoutResolver,n=r.layoutsDir||`src/layouts`;globalThis.__avalonLayoutResolver=new t({baseDirectory:`${e}/${n}`,filePattern:`_layout.tsx`,excludeDirectories:[`node_modules`,`.git`,`dist`,`build`],enableWatching:!0,developmentMode:!1,enableCaching:!0,cacheTTL:60*1e3,maxCacheSize:100,enableStreaming:!0,enableErrorBoundaries:!0,enableMetrics:!1,enableDebugInfo:!1,modulesDir:r.modules?`${e}/${r.modules.dir}`:void 0,modulesLayoutsDirName:r.modules?.layoutsDirName})}let t=`http://localhost${n}`,l={params:{},query:{},url:t,request:{method:`GET`,url:t,headers:new Headers}};return await o.renderToHtmlWithLayouts(c,globalThis.__avalonLayoutResolver,l,n,{title:a.title||`Avalon App`},void 0,{suppressWarnings:!0})}catch{}if(o.renderToHtml)return await o.renderToHtml(c,{title:a.title||`Avalon App`},void 0,{suppressWarnings:!0})}catch{}let o=a.title||`Avalon App`,s=a.description||``,c=``;try{let t=await i.ssrLoadModule(`preact-render-to-string`);t.render&&typeof e==`function`&&(c=t.render(e()))}catch{c=`<p>Loading page: ${K(n)}</p>`}return`<!DOCTYPE html>
34
34
  <html lang="en">
35
35
  <head>
36
36
  <meta charset="utf-8">
37
37
  <meta name="viewport" content="width=device-width, initial-scale=1">
38
- <title>${G(o)}</title>
39
- ${s?`<meta name="description" content="${G(s)}">`:``}
38
+ <title>${K(o)}</title>
39
+ ${s?`<meta name="description" content="${K(s)}">`:``}
40
40
  <script type="module" src="/@vite/client"><\/script>
41
41
  </head>
42
42
  <body>
43
43
  <div id="app">${c}</div>
44
44
  <script type="module" src="/src/client/main.js"><\/script>
45
45
  </body>
46
- </html>`}function G(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`"`,`&quot;`).replaceAll(`'`,`&#039;`)}
46
+ </html>`}function K(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`"`,`&quot;`).replaceAll(`'`,`&#039;`)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useavalon/avalon",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "Multi-framework islands architecture for the modern web",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -128,7 +128,7 @@
128
128
  }
129
129
  },
130
130
  "dependencies": {
131
- "@useavalon/core": "workspace:^",
131
+ "@useavalon/core": "^0.1.6",
132
132
  "@mdx-js/rollup": "^3.0.0",
133
133
  "h3": "^2.0.1-rc.16",
134
134
  "marked": "^17.0.4",
@@ -1,34 +0,0 @@
1
- import { Component, ComponentChildren } from 'preact';
2
- import type { LayoutErrorInfo, LayoutContext, LayoutData } from '../types/layout.ts';
3
- export interface LayoutDataErrorBoundaryProps {
4
- children: ComponentChildren;
5
- layoutPath: string;
6
- context: LayoutContext;
7
- onError?: (error: Error, errorInfo: LayoutErrorInfo) => void;
8
- fallbackData?: LayoutData;
9
- retryLoader?: () => Promise<LayoutData>;
10
- }
11
- export interface LayoutDataErrorBoundaryState {
12
- hasError: boolean;
13
- error: Error | null;
14
- errorInfo: LayoutErrorInfo | null;
15
- retryCount: number;
16
- isRetrying: boolean;
17
- fallbackData: LayoutData | null;
18
- }
19
- /**
20
- * Specialized error boundary for layout data loading errors
21
- * Provides specific handling for data loader failures with retry and fallback mechanisms
22
- */
23
- export declare class LayoutDataErrorBoundary extends Component<LayoutDataErrorBoundaryProps, LayoutDataErrorBoundaryState> {
24
- private maxRetries;
25
- constructor(props: LayoutDataErrorBoundaryProps);
26
- static getDerivedStateFromError(error: Error): Partial<LayoutDataErrorBoundaryState>;
27
- componentDidCatch(error: Error, errorInfo: {
28
- componentStack?: string;
29
- }): void;
30
- private handleRetry;
31
- private handleUseFallback;
32
- private renderErrorUI;
33
- render(): ComponentChildren;
34
- }
@@ -1 +0,0 @@
1
- import{Component as e}from"preact";import{jsx as t,jsxs as n}from"preact/jsx-runtime";export class LayoutDataErrorBoundary extends e{maxRetries=3;constructor(e){super(e),this.state={hasError:!1,error:null,errorInfo:null,retryCount:0,isRetrying:!1,fallbackData:e.fallbackData||null}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){let n={layoutPath:this.props.layoutPath,errorType:`loader`,timestamp:Date.now(),componentStack:t.componentStack,errorBoundary:`LayoutDataErrorBoundary`};this.setState({errorInfo:n}),this.props.onError&&this.props.onError(e,n)}handleRetry=async()=>{if(!(this.state.retryCount>=this.maxRetries||!this.props.retryLoader)){this.setState({isRetrying:!0});try{let e=await this.props.retryLoader();this.setState({hasError:!1,error:null,errorInfo:null,retryCount:this.state.retryCount+1,isRetrying:!1,fallbackData:e})}catch(e){this.setState({retryCount:this.state.retryCount+1,isRetrying:!1,error:e instanceof Error?e:Error(String(e))})}}};handleUseFallback=()=>{this.state.fallbackData&&this.setState({hasError:!1,error:null,errorInfo:null})};renderErrorUI(){let{error:e,retryCount:r,isRetrying:i,fallbackData:a}=this.state,o=r<this.maxRetries&&this.props.retryLoader,s=a!==null,c=typeof process<`u`&&process.env?.NODE_ENV===`development`;return t(`div`,{class:`layout-data-error-boundary`,children:n(`div`,{class:`error-container`,children:[t(`h3`,{children:`Data Loading Error`}),n(`p`,{children:[`Failed to load data for layout: `,this.props.layoutPath]}),n(`div`,{class:`error-actions`,children:[o&&t(`button`,{onClick:this.handleRetry,disabled:i,class:`retry-button`,children:i?`Retrying...`:`Retry (${this.maxRetries-r} left)`}),s&&t(`button`,{onClick:this.handleUseFallback,class:`fallback-button`,children:`Use Cached Data`})]}),c&&e&&n(`details`,{class:`error-details`,children:[t(`summary`,{children:`Error Details (Development)`}),n(`div`,{class:`error-info`,children:[n(`p`,{children:[t(`strong`,{children:`Error:`}),` `,e.message]}),n(`p`,{children:[t(`strong`,{children:`Layout:`}),` `,this.props.layoutPath]}),n(`p`,{children:[t(`strong`,{children:`Retry Count:`}),` `,r]})]}),t(`pre`,{class:`error-stack`,children:e.stack})]})]})})}render(){return this.state.hasError?this.renderErrorUI():this.props.children}}
@@ -1,36 +0,0 @@
1
- /** @jsxImportSource preact */
2
- import type { ComponentChildren } from 'preact';
3
- import { type IslandPersistence } from '../core/islands/island-persistence.ts';
4
- interface PersistentIslandProps {
5
- /** Unique ID used as the storage key for this island's state */
6
- persistentId: string;
7
- /** The island component(s) to wrap with persistence context */
8
- children: ComponentChildren;
9
- /** Custom persistence instance (defaults to sessionStorage-backed) */
10
- persistence?: IslandPersistence;
11
- }
12
- /**
13
- * PersistentIsland — provides automatic state persistence context to child islands.
14
- *
15
- * Wrap any island with this component and use `usePersistentIslandContext()` inside
16
- * the island to get `saveState`, `loadState`, and `clearState` functions.
17
- *
18
- * Usage in a page:
19
- * ```tsx
20
- * <PersistentIsland persistentId="my-counter" island={{ condition: 'on:client' }}>
21
- * <MyCounter />
22
- * </PersistentIsland>
23
- * ```
24
- *
25
- * Usage inside the island:
26
- * ```tsx
27
- * import { usePersistentIslandContext } from '@useavalon/avalon';
28
- *
29
- * function MyCounter() {
30
- * const { saveState, loadState, clearState } = usePersistentIslandContext();
31
- * // ...
32
- * }
33
- * ```
34
- */
35
- export declare function PersistentIsland({ persistentId, children, persistence, }: Readonly<PersistentIslandProps>): import("preact").JSX.Element;
36
- export default PersistentIsland;
@@ -1 +0,0 @@
1
- import{PersistentIslandProvider as e}from"../core/islands/persistent-island-context.js";import{defaultIslandPersistence as t}from"../core/islands/island-persistence.js";import{jsx as n}from"preact/jsx-runtime";export function PersistentIsland({persistentId:r,children:i,persistence:a=t}){return n(e,{persistentId:r,persistence:a,children:n(`div`,{"data-persistent-id":r,children:i})})}export default PersistentIsland;
@@ -1,42 +0,0 @@
1
- /**
2
- * StreamingErrorBoundary - Error boundary component for streaming contexts
3
- *
4
- * This component provides error isolation for Suspense boundaries in streaming SSR.
5
- * It ensures that errors in one component don't break the entire page.
6
- */
7
- import { Component, type ComponentChildren } from 'preact';
8
- export interface StreamingErrorBoundaryProps {
9
- children: ComponentChildren;
10
- fallback?: (error: Error, retry: () => void) => ComponentChildren;
11
- onError?: (error: Error, errorInfo: any) => void;
12
- componentId?: string;
13
- isolateError?: boolean;
14
- }
15
- export interface StreamingErrorBoundaryState {
16
- hasError: boolean;
17
- error: Error | null;
18
- errorInfo: any;
19
- }
20
- /**
21
- * Error boundary component for streaming contexts
22
- *
23
- * Wraps Suspense boundaries to provide error isolation and recovery.
24
- * Prevents errors in one component from breaking the entire page.
25
- */
26
- export declare class StreamingErrorBoundary extends Component<StreamingErrorBoundaryProps, StreamingErrorBoundaryState> {
27
- constructor(props: StreamingErrorBoundaryProps);
28
- static getDerivedStateFromError(error: Error): Partial<StreamingErrorBoundaryState>;
29
- componentDidCatch(error: Error, errorInfo: any): void;
30
- private handleRetry;
31
- private renderFallback;
32
- render(): ComponentChildren;
33
- }
34
- /**
35
- * Higher-order component to wrap components with streaming error boundaries
36
- */
37
- export declare function withStreamingErrorBoundary<P extends object>(WrappedComponent: (props: P) => ComponentChildren, options?: {
38
- fallback?: (error: Error, retry: () => void) => ComponentChildren;
39
- componentId?: string;
40
- isolateError?: boolean;
41
- onError?: (error: Error, errorInfo: any) => void;
42
- }): (props: P) => import("preact").JSX.Element;
@@ -1 +0,0 @@
1
- import{Component as e}from"preact";import{jsx as t,jsxs as n}from"preact/jsx-runtime";export class StreamingErrorBoundary extends e{constructor(e){super(e),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){if(this.setState({errorInfo:t}),console.error(`[StreamingErrorBoundary] Caught error:`,{componentId:this.props.componentId,error:e.message,stack:e.stack,componentStack:t.componentStack}),this.props.onError&&this.props.onError(e,t),!this.props.isolateError)throw e}handleRetry=()=>{this.setState({hasError:!1,error:null,errorInfo:null})};renderFallback(){let{error:e}=this.state,{fallback:r,componentId:i}=this.props;if(r&&e)return r(e,this.handleRetry);let a=typeof process<`u`&&process.env?.NODE_ENV!==`production`;return n(`div`,{class:`streaming-error-boundary`,"data-error-boundary":`true`,"data-component-id":i,style:{background:`#fff3cd`,border:`2px solid #ffc107`,borderRadius:`8px`,padding:`20px`,margin:`20px 0`,fontFamily:`system-ui, -apple-system, sans-serif`},children:[n(`div`,{class:`error-boundary-header`,style:{display:`flex`,alignItems:`center`,gap:`10px`,marginBottom:`10px`},children:[t(`span`,{style:{fontSize:`24px`},children:`⚠️`}),t(`h3`,{style:{margin:0,color:`#856404`},children:`Component Error`})]}),t(`p`,{style:{margin:`10px 0`,color:`#856404`},children:`An error occurred while rendering this component. The rest of the page should work normally.`}),t(`button`,{onClick:this.handleRetry,style:{background:`#ffc107`,border:`none`,borderRadius:`4px`,padding:`8px 16px`,cursor:`pointer`,fontWeight:`bold`,color:`#856404`,marginTop:`10px`},children:`Retry`}),a&&e&&n(`details`,{style:{marginTop:`15px`},children:[t(`summary`,{style:{cursor:`pointer`,color:`#856404`,fontWeight:`bold`},children:`Error Details (Development Mode)`}),n(`div`,{style:{marginTop:`10px`},children:[i&&n(`p`,{children:[t(`strong`,{children:`Component ID:`}),` `,i]}),n(`p`,{children:[t(`strong`,{children:`Error:`}),` `,e.message]}),e.stack&&t(`pre`,{style:{background:`#f5f5f5`,padding:`10px`,borderRadius:`4px`,overflowX:`auto`,fontSize:`12px`,marginTop:`10px`},children:e.stack}),this.state.errorInfo?.componentStack&&n(`div`,{children:[t(`p`,{children:t(`strong`,{children:`Component Stack:`})}),t(`pre`,{style:{background:`#f5f5f5`,padding:`10px`,borderRadius:`4px`,overflowX:`auto`,fontSize:`12px`,marginTop:`10px`},children:this.state.errorInfo.componentStack})]})]})]})]})}render(){return this.state.hasError?this.renderFallback():this.props.children}}export function withStreamingErrorBoundary(e,n){return function(i){return t(StreamingErrorBoundary,{componentId:n?.componentId,fallback:n?.fallback,isolateError:n?.isolateError??!0,onError:n?.onError,children:t(e,{...i})})}}
@@ -1,83 +0,0 @@
1
- import { ComponentChildren, ComponentType } from 'preact';
2
- import type { StreamingLayoutProps } from '../types/layout.ts';
3
- /**
4
- * Streaming Layout Component Props
5
- */
6
- export interface StreamingLayoutComponentProps extends StreamingLayoutProps {
7
- /**
8
- * Component to render when ready
9
- */
10
- component: ComponentType<any>;
11
- /**
12
- * Props to pass to the component
13
- */
14
- componentProps?: any;
15
- /**
16
- * Function to check if component is ready
17
- */
18
- isReady?: () => Promise<boolean>;
19
- /**
20
- * Timeout for loading (ms)
21
- */
22
- timeout?: number;
23
- /**
24
- * Error boundary fallback
25
- */
26
- onError?: (error: Error) => ComponentChildren;
27
- /**
28
- * Loading state callback
29
- */
30
- onLoadingChange?: (isLoading: boolean) => void;
31
- }
32
- /**
33
- * Streaming Layout Component with Suspense-like behavior
34
- */
35
- export declare function StreamingLayout(props: StreamingLayoutComponentProps): ComponentChildren;
36
- /**
37
- * Suspense-like boundary for streaming components
38
- */
39
- export interface StreamingSuspenseProps {
40
- /**
41
- * Fallback to show while loading
42
- */
43
- fallback?: ComponentChildren;
44
- /**
45
- * Children components
46
- */
47
- children: ComponentChildren;
48
- /**
49
- * Priority for this suspense boundary
50
- */
51
- priority?: 'high' | 'medium' | 'low';
52
- /**
53
- * Timeout for all children (ms)
54
- */
55
- timeout?: number;
56
- /**
57
- * Error boundary for failed components
58
- */
59
- onError?: (error: Error) => ComponentChildren;
60
- }
61
- /**
62
- * Streaming Suspense Boundary Component
63
- */
64
- export declare function StreamingSuspense(props: StreamingSuspenseProps): ComponentChildren;
65
- /**
66
- * Higher-order component to add streaming capabilities
67
- */
68
- export declare function withStreaming<P extends object>(WrappedComponent: ComponentType<P>, streamingOptions?: {
69
- fallback?: ComponentChildren;
70
- priority?: 'high' | 'medium' | 'low';
71
- isReady?: () => Promise<boolean>;
72
- timeout?: number;
73
- }): (props: P) => import("preact").JSX.Element;
74
- /**
75
- * Hook for streaming component state
76
- */
77
- export declare function useStreamingState(isReady?: () => Promise<boolean>, timeout?: number): {
78
- retry: () => void;
79
- isReady: boolean;
80
- isLoading: boolean;
81
- error: Error | null;
82
- hasTimedOut: boolean;
83
- };
@@ -1,29 +0,0 @@
1
- import{Component as e}from"preact";import{useState as t,useEffect as n,useRef as r}from"preact/hooks";import{jsxs as i,jsx as a}from"preact/jsx-runtime";export function StreamingLayout(e){let{component:o,componentProps:c={},children:l,fallback:u,priority:d=`medium`,isReady:f,timeout:p=5e3,onError:m,onLoadingChange:h}=e;if(typeof window>`u`)return l;let[g,_]=t({isReady:!1,isLoading:!0,error:null,hasTimedOut:!1}),v=r(),y=r(!0);return n(()=>()=>{y.current=!1},[]),n(()=>{if(!f){_(e=>({...e,isReady:!0,isLoading:!1})),h?.(!1);return}let e=!1;return(async()=>{try{p>0&&(v.current=setTimeout(()=>{!e&&y.current&&(_(e=>({...e,hasTimedOut:!0,isLoading:!1})),h?.(!1))},p));let t=await f();if(e||!y.current)return;v.current&&clearTimeout(v.current),_(e=>({...e,isReady:t,isLoading:!1,hasTimedOut:!1})),h?.(!1)}catch(t){if(e||!y.current)return;v.current&&clearTimeout(v.current),_(e=>({...e,error:t,isLoading:!1})),h?.(!1)}})(),()=>{e=!0,v.current&&clearTimeout(v.current)}},[f,p,h]),g.error?m?m(g.error):i(`div`,{class:`streaming-error`,"data-priority":d,children:[i(`p`,{children:[`Failed to load component: `,g.error.message]}),a(`button`,{onClick:()=>{_({isReady:!1,isLoading:!0,error:null,hasTimedOut:!1}),h?.(!0)},children:`Retry`})]}):g.hasTimedOut?a(`div`,{class:`streaming-timeout`,"data-priority":d,children:u||i(`div`,{class:`timeout-message`,children:[a(`p`,{children:`Component loading timed out`}),a(`button`,{onClick:()=>{_({isReady:!1,isLoading:!0,error:null,hasTimedOut:!1}),h?.(!0)},children:`Retry`})]})}):g.isLoading||!g.isReady?a(`div`,{class:`streaming-loading`,"data-priority":d,children:u||a(s,{priority:d})}):a(`div`,{class:`streaming-ready`,"data-priority":d,children:a(o,{...c,children:l})})}function s({priority:e}){return i(`div`,{class:`streaming-skeleton ${`skeleton-${e}`}`,children:[i(`div`,{class:`skeleton-content`,children:[a(`div`,{class:`skeleton-line skeleton-line-1`}),a(`div`,{class:`skeleton-line skeleton-line-2`}),a(`div`,{class:`skeleton-line skeleton-line-3`})]}),a(`style`,{children:`
2
- .streaming-skeleton {
3
- padding: 1rem;
4
- border-radius: 0.5rem;
5
- background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
6
- background-size: 200% 100%;
7
- animation: skeleton-loading 1.5s infinite;
8
- }
9
- .skeleton-content {
10
- display: flex;
11
- flex-direction: column;
12
- gap: 0.5rem;
13
- }
14
- .skeleton-line {
15
- height: 1rem;
16
- background: rgba(255, 255, 255, 0.8);
17
- border-radius: 0.25rem;
18
- }
19
- .skeleton-line-1 { width: 100%; }
20
- .skeleton-line-2 { width: 75%; }
21
- .skeleton-line-3 { width: 50%; }
22
- .skeleton-high { border-left: 4px solid #ef4444; }
23
- .skeleton-medium { border-left: 4px solid #f59e0b; }
24
- .skeleton-low { border-left: 4px solid #10b981; }
25
- @keyframes skeleton-loading {
26
- 0% { background-position: 200% 0; }
27
- 100% { background-position: -200% 0; }
28
- }
29
- `})]})}export function StreamingSuspense(e){let{fallback:o,children:c,priority:u=`medium`,timeout:d=5e3,onError:f}=e,[p,m]=t(!0),[h,g]=t(null),[_,v]=t(!1),y=r(),b=r(!0);n(()=>()=>{b.current=!1},[]),n(()=>(d>0&&(y.current=setTimeout(()=>{b.current&&p&&(v(!0),m(!1))},d)),()=>{y.current&&clearTimeout(y.current)}),[d,p]);let x=e=>{g(e),m(!1),y.current&&clearTimeout(y.current)};return h?f?f(h):i(`div`,{class:`streaming-suspense-error`,"data-priority":u,children:[i(`p`,{children:[`Suspense boundary error: `,h.message]}),a(`button`,{onClick:()=>{g(null),m(!0),v(!1)},children:`Retry`})]}):_?a(`div`,{class:`streaming-suspense-timeout`,"data-priority":u,children:o||i(`div`,{class:`suspense-timeout-message`,children:[a(`p`,{children:`Suspense boundary timed out`}),a(`button`,{onClick:()=>{v(!1),m(!0)},children:`Retry`})]})}):p?a(`div`,{class:`streaming-suspense-loading`,"data-priority":u,children:o||a(s,{priority:u})}):a(`div`,{class:`streaming-suspense-ready`,"data-priority":u,children:a(l,{onError:x,children:c})})}class l extends e{constructor(e){super(e),this.state={hasError:!1}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){console.error(`StreamingErrorBoundary caught an error:`,e,t),this.props.onError?.(e)}render(){return this.state.hasError?i(`div`,{class:`streaming-error-boundary`,children:[a(`p`,{children:`Something went wrong in streaming component.`}),a(`button`,{onClick:()=>this.setState({hasError:!1,error:void 0}),children:`Retry`})]}):this.props.children}}export function withStreaming(e,t={}){return function(n){return a(StreamingLayout,{component:e,componentProps:n,priority:`medium`,...t,children:null})}}export function useStreamingState(e,r=5e3){let[i,a]=t({isReady:!1,isLoading:!0,error:null,hasTimedOut:!1});n(()=>{if(!e){a(e=>({...e,isReady:!0,isLoading:!1}));return}let t=!1,n;return(async()=>{try{r>0&&(n=setTimeout(()=>{t||a(e=>({...e,hasTimedOut:!0,isLoading:!1}))},r));let i=await e();if(t)return;n&&clearTimeout(n),a(e=>({...e,isReady:i,isLoading:!1,hasTimedOut:!1}))}catch(e){if(t)return;n&&clearTimeout(n),a(t=>({...t,error:e,isLoading:!1}))}})(),()=>{t=!0,n&&clearTimeout(n)}},[e,r]);let o=()=>{a({isReady:!1,isLoading:!0,error:null,hasTimedOut:!1})};return{...i,retry:o}}