@useavalon/avalon 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mod.js +1 -0
- package/dist/src/build/integration-bundler-plugin.js +1 -0
- package/dist/src/build/integration-config.js +1 -0
- package/dist/src/build/integration-detection-plugin.js +1 -0
- package/dist/src/build/integration-resolver-plugin.js +1 -0
- package/dist/src/build/island-manifest.js +1 -0
- package/dist/src/build/island-types-generator.js +5 -0
- package/dist/src/build/mdx-island-transform.js +2 -0
- package/dist/src/build/mdx-plugin.js +1 -0
- package/dist/src/build/page-island-transform.js +3 -0
- package/dist/src/build/prop-extractors/index.js +1 -0
- package/dist/src/build/prop-extractors/lit.js +1 -0
- package/dist/src/build/prop-extractors/qwik.js +1 -0
- package/dist/src/build/prop-extractors/solid.js +1 -0
- package/dist/src/build/prop-extractors/svelte.js +1 -0
- package/dist/src/build/prop-extractors/vue.js +1 -0
- package/dist/src/build/sidecar-file-manager.js +1 -0
- package/dist/src/build/sidecar-renderer.js +6 -0
- package/dist/src/client/adapters/index.js +1 -0
- package/dist/src/client/components.js +1 -0
- package/dist/src/client/css-hmr-handler.js +1 -0
- package/dist/src/client/framework-adapter.js +13 -0
- package/dist/src/client/hmr-coordinator.js +1 -0
- package/dist/src/client/hmr-error-overlay.js +214 -0
- package/dist/src/client/main.js +39 -0
- package/dist/src/components/Image.js +1 -0
- package/dist/src/components/IslandErrorBoundary.js +1 -0
- package/dist/src/components/LayoutDataErrorBoundary.js +1 -0
- package/dist/src/components/LayoutErrorBoundary.js +1 -0
- package/dist/src/components/PersistentIsland.js +1 -0
- package/dist/src/components/StreamingErrorBoundary.js +1 -0
- package/dist/src/components/StreamingLayout.js +29 -0
- package/dist/src/core/components/component-analyzer.js +1 -0
- package/dist/src/core/components/component-detection.js +5 -0
- package/dist/src/core/components/enhanced-framework-detector.js +1 -0
- package/dist/src/core/components/framework-registry.js +1 -0
- package/dist/src/core/content/mdx-processor.js +1 -0
- package/dist/src/core/integrations/index.js +1 -0
- package/dist/src/core/integrations/loader.js +1 -0
- package/dist/src/core/integrations/registry.js +1 -0
- package/dist/src/core/islands/island-persistence.js +1 -0
- package/dist/src/core/islands/island-state-serializer.js +1 -0
- package/dist/src/core/islands/persistent-island-context.js +1 -0
- package/dist/src/core/islands/use-persistent-state.js +1 -0
- package/dist/src/core/layout/enhanced-layout-resolver.js +1 -0
- package/dist/src/core/layout/layout-cache-manager.js +1 -0
- package/dist/src/core/layout/layout-composer.js +1 -0
- package/dist/src/core/layout/layout-data-loader.js +1 -0
- package/dist/src/core/layout/layout-discovery.js +1 -0
- package/dist/src/core/layout/layout-matcher.js +1 -0
- package/dist/src/core/layout/layout-types.js +1 -0
- package/dist/src/core/modules/framework-module-resolver.js +1 -0
- package/dist/src/islands/component-analysis.js +1 -0
- package/dist/src/islands/css-utils.js +17 -0
- package/dist/src/islands/discovery/index.js +1 -0
- package/dist/src/islands/discovery/registry.js +1 -0
- package/dist/src/islands/discovery/resolver.js +2 -0
- package/dist/src/islands/discovery/scanner.js +1 -0
- package/dist/src/islands/discovery/types.js +1 -0
- package/dist/src/islands/discovery/validator.js +18 -0
- package/dist/src/islands/discovery/watcher.js +1 -0
- package/dist/src/islands/framework-detection.js +1 -0
- package/dist/src/islands/integration-loader.js +1 -0
- package/dist/src/islands/island.js +1 -0
- package/dist/src/islands/render-cache.js +1 -0
- package/dist/src/islands/types.js +1 -0
- package/dist/src/islands/universal-css-collector.js +5 -0
- package/dist/src/islands/universal-head-collector.js +2 -0
- package/dist/src/layout-system.js +1 -0
- package/dist/src/middleware/discovery.js +1 -0
- package/dist/src/middleware/executor.js +1 -0
- package/dist/src/middleware/index.js +1 -0
- package/dist/src/middleware/types.js +1 -0
- package/dist/src/nitro/build-config.js +1 -0
- package/dist/src/nitro/config.js +1 -0
- package/dist/src/nitro/error-handler.js +198 -0
- package/dist/src/nitro/index.js +1 -0
- package/dist/src/nitro/island-manifest.js +2 -0
- package/dist/src/nitro/middleware-adapter.js +1 -0
- package/dist/src/nitro/renderer.js +183 -0
- package/dist/src/nitro/route-discovery.js +1 -0
- package/dist/src/nitro/types.js +1 -0
- package/dist/src/render/collect-css.js +3 -0
- package/dist/src/render/error-pages.js +48 -0
- package/dist/src/render/isolated-ssr-renderer.js +1 -0
- package/dist/src/render/ssr.js +90 -0
- package/dist/src/schemas/api.js +1 -0
- package/dist/src/schemas/core.js +1 -0
- package/dist/src/schemas/index.js +1 -0
- package/dist/src/schemas/layout.js +1 -0
- package/dist/src/schemas/routing/index.js +1 -0
- package/dist/src/schemas/routing.js +1 -0
- package/dist/src/types/as-island.js +1 -0
- package/dist/src/types/layout.js +1 -0
- package/dist/src/types/routing.js +1 -0
- package/dist/src/types/types.js +1 -0
- package/dist/src/utils/dev-logger.js +12 -0
- package/dist/src/utils/fs.js +1 -0
- package/dist/src/vite-plugin/auto-discover.js +1 -0
- package/dist/src/vite-plugin/config.js +1 -0
- package/dist/src/vite-plugin/errors.js +1 -0
- package/dist/src/vite-plugin/image-optimization.js +45 -0
- package/dist/src/vite-plugin/integration-activator.js +1 -0
- package/dist/src/vite-plugin/island-sidecar-plugin.js +1 -0
- package/dist/src/vite-plugin/module-discovery.js +1 -0
- package/dist/src/vite-plugin/nitro-integration.js +42 -0
- package/dist/src/vite-plugin/plugin.js +1 -0
- package/dist/src/vite-plugin/types.js +1 -0
- package/dist/src/vite-plugin/validation.js +2 -0
- package/package.json +14 -20
- package/mod.ts +0 -302
- package/src/build/integration-bundler-plugin.ts +0 -116
- package/src/build/integration-config.ts +0 -168
- package/src/build/integration-detection-plugin.ts +0 -117
- package/src/build/integration-resolver-plugin.ts +0 -90
- package/src/build/island-manifest.ts +0 -269
- package/src/build/island-types-generator.ts +0 -476
- package/src/build/mdx-island-transform.ts +0 -464
- package/src/build/mdx-plugin.ts +0 -98
- package/src/build/page-island-transform.ts +0 -598
- package/src/build/prop-extractors/index.ts +0 -21
- package/src/build/prop-extractors/lit.ts +0 -140
- package/src/build/prop-extractors/qwik.ts +0 -16
- package/src/build/prop-extractors/solid.ts +0 -125
- package/src/build/prop-extractors/svelte.ts +0 -194
- package/src/build/prop-extractors/vue.ts +0 -111
- package/src/build/sidecar-file-manager.ts +0 -104
- package/src/build/sidecar-renderer.ts +0 -30
- package/src/client/adapters/index.ts +0 -21
- package/src/client/components.ts +0 -35
- package/src/client/css-hmr-handler.ts +0 -344
- package/src/client/framework-adapter.ts +0 -462
- package/src/client/hmr-coordinator.ts +0 -396
- package/src/client/hmr-error-overlay.js +0 -533
- package/src/client/main.js +0 -824
- package/src/components/Image.tsx +0 -123
- package/src/components/IslandErrorBoundary.tsx +0 -145
- package/src/components/LayoutDataErrorBoundary.tsx +0 -141
- package/src/components/LayoutErrorBoundary.tsx +0 -127
- package/src/components/PersistentIsland.tsx +0 -52
- package/src/components/StreamingErrorBoundary.tsx +0 -233
- package/src/components/StreamingLayout.tsx +0 -538
- package/src/core/components/component-analyzer.ts +0 -192
- package/src/core/components/component-detection.ts +0 -508
- package/src/core/components/enhanced-framework-detector.ts +0 -500
- package/src/core/components/framework-registry.ts +0 -563
- package/src/core/content/mdx-processor.ts +0 -46
- package/src/core/integrations/index.ts +0 -19
- package/src/core/integrations/loader.ts +0 -125
- package/src/core/integrations/registry.ts +0 -175
- package/src/core/islands/island-persistence.ts +0 -325
- package/src/core/islands/island-state-serializer.ts +0 -258
- package/src/core/islands/persistent-island-context.tsx +0 -80
- package/src/core/islands/use-persistent-state.ts +0 -68
- package/src/core/layout/enhanced-layout-resolver.ts +0 -322
- package/src/core/layout/layout-cache-manager.ts +0 -485
- package/src/core/layout/layout-composer.ts +0 -357
- package/src/core/layout/layout-data-loader.ts +0 -516
- package/src/core/layout/layout-discovery.ts +0 -243
- package/src/core/layout/layout-matcher.ts +0 -299
- package/src/core/layout/layout-types.ts +0 -110
- package/src/core/modules/framework-module-resolver.ts +0 -273
- package/src/islands/component-analysis.ts +0 -213
- package/src/islands/css-utils.ts +0 -565
- package/src/islands/discovery/index.ts +0 -80
- package/src/islands/discovery/registry.ts +0 -340
- package/src/islands/discovery/resolver.ts +0 -477
- package/src/islands/discovery/scanner.ts +0 -386
- package/src/islands/discovery/types.ts +0 -117
- package/src/islands/discovery/validator.ts +0 -544
- package/src/islands/discovery/watcher.ts +0 -368
- package/src/islands/framework-detection.ts +0 -428
- package/src/islands/integration-loader.ts +0 -490
- package/src/islands/island.tsx +0 -565
- package/src/islands/render-cache.ts +0 -550
- package/src/islands/types.ts +0 -80
- package/src/islands/universal-css-collector.ts +0 -157
- package/src/islands/universal-head-collector.ts +0 -137
- package/src/layout-system.ts +0 -218
- package/src/middleware/discovery.ts +0 -268
- package/src/middleware/executor.ts +0 -315
- package/src/middleware/index.ts +0 -76
- package/src/middleware/types.ts +0 -99
- package/src/nitro/build-config.ts +0 -576
- package/src/nitro/config.ts +0 -483
- package/src/nitro/error-handler.ts +0 -636
- package/src/nitro/index.ts +0 -173
- package/src/nitro/island-manifest.ts +0 -584
- package/src/nitro/middleware-adapter.ts +0 -260
- package/src/nitro/renderer.ts +0 -1471
- package/src/nitro/route-discovery.ts +0 -439
- package/src/nitro/types.ts +0 -321
- package/src/render/collect-css.ts +0 -198
- package/src/render/error-pages.ts +0 -79
- package/src/render/isolated-ssr-renderer.ts +0 -654
- package/src/render/ssr.ts +0 -1030
- package/src/schemas/api.ts +0 -30
- package/src/schemas/core.ts +0 -64
- package/src/schemas/index.ts +0 -212
- package/src/schemas/layout.ts +0 -279
- package/src/schemas/routing/index.ts +0 -38
- package/src/schemas/routing.ts +0 -376
- package/src/types/as-island.ts +0 -20
- package/src/types/layout.ts +0 -285
- package/src/types/routing.ts +0 -555
- package/src/types/types.ts +0 -5
- package/src/utils/dev-logger.ts +0 -299
- package/src/utils/fs.ts +0 -151
- package/src/vite-plugin/auto-discover.ts +0 -551
- package/src/vite-plugin/config.ts +0 -266
- package/src/vite-plugin/errors.ts +0 -127
- package/src/vite-plugin/image-optimization.ts +0 -156
- package/src/vite-plugin/integration-activator.ts +0 -126
- package/src/vite-plugin/island-sidecar-plugin.ts +0 -176
- package/src/vite-plugin/module-discovery.ts +0 -189
- package/src/vite-plugin/nitro-integration.ts +0 -1354
- package/src/vite-plugin/plugin.ts +0 -403
- package/src/vite-plugin/types.ts +0 -327
- package/src/vite-plugin/validation.ts +0 -228
- /package/{src → dist/src}/client/types/framework-runtime.d.ts +0 -0
- /package/{src → dist/src}/client/types/vite-hmr.d.ts +0 -0
- /package/{src → dist/src}/client/types/vite-virtual-modules.d.ts +0 -0
- /package/{src → dist/src}/layout-system.d.ts +0 -0
- /package/{src → dist/src}/types/image.d.ts +0 -0
- /package/{src → dist/src}/types/index.d.ts +0 -0
- /package/{src → dist/src}/types/island-jsx.d.ts +0 -0
- /package/{src → dist/src}/types/island-prop.d.ts +0 -0
- /package/{src → dist/src}/types/mdx.d.ts +0 -0
- /package/{src → dist/src}/types/urlpattern.d.ts +0 -0
- /package/{src → dist/src}/types/vite-env.d.ts +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import{isHttpError as e,createNotFoundError as t,createInternalError as n}from"./types.js";import{createRenderContext as r,getRequestURL as i}from"./renderer.js";let a={initialized:!1};export function clearErrorPageCache(){a={initialized:!1}}export async function discoverErrorPages(e){if(a.initialized&&!e.isDev)return a;let{loadPageModule:t,pagesDir:n=`src/pages`}=e;if(!t)return a.initialized=!0,a;try{a.notFound=await t(`${n}/404.tsx`)}catch{try{a.notFound=await t(`${n}/404.jsx`)}catch{a.notFound=null}}try{a.serverError=await t(`${n}/500.tsx`)}catch{try{a.serverError=await t(`${n}/500.jsx`)}catch{a.serverError=null}}try{a.genericError=await t(`${n}/_error.tsx`)}catch{try{a.genericError=await t(`${n}/_error.jsx`)}catch{a.genericError=null}}return a.initialized=!0,a}export function getErrorPageModule(e,t){return e===404&&t.notFound?t.notFound:e===500&&t.serverError?t.serverError:t.genericError?t.genericError:null}export function createErrorPageProps(t,n,r){let i={statusCode:e(t)?t.statusCode:500,message:t.message,url:n};return r&&(i.error=t,i.stack=t.stack),i}export async function renderErrorPage(e,t,n,r){if(typeof e.default!=`function`)return generateDefaultErrorPage(t.statusCode,t.message,r,t.stack);try{let n=e.metadata||{};return`<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>${u(String(n.title||`Error ${t.statusCode}`))}</title>
|
|
7
|
+
${n.description?`<meta name="description" content="${u(String(n.description))}">`:``}
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 40px;
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
min-height: 100vh;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
background: #f5f5f5;
|
|
19
|
+
}
|
|
20
|
+
.error-page {
|
|
21
|
+
text-align: center;
|
|
22
|
+
max-width: 600px;
|
|
23
|
+
}
|
|
24
|
+
h1 {
|
|
25
|
+
font-size: 48px;
|
|
26
|
+
margin: 0 0 20px 0;
|
|
27
|
+
color: #333;
|
|
28
|
+
}
|
|
29
|
+
p {
|
|
30
|
+
color: #666;
|
|
31
|
+
margin: 0 0 20px 0;
|
|
32
|
+
}
|
|
33
|
+
a {
|
|
34
|
+
color: #0066cc;
|
|
35
|
+
text-decoration: none;
|
|
36
|
+
}
|
|
37
|
+
a:hover {
|
|
38
|
+
text-decoration: underline;
|
|
39
|
+
}
|
|
40
|
+
details {
|
|
41
|
+
margin-top: 20px;
|
|
42
|
+
text-align: left;
|
|
43
|
+
}
|
|
44
|
+
pre {
|
|
45
|
+
background: #1a1a1a;
|
|
46
|
+
color: #e0e0e0;
|
|
47
|
+
padding: 15px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
overflow-x: auto;
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
53
|
+
</head>
|
|
54
|
+
<body>
|
|
55
|
+
<div id="app" data-error-page="true" data-status-code="${t.statusCode}" data-props='${u(JSON.stringify(t))}'>
|
|
56
|
+
<!-- Custom error page content rendered by Avalon SSR pipeline -->
|
|
57
|
+
<div class="error-page">
|
|
58
|
+
<h1>${t.statusCode}</h1>
|
|
59
|
+
<p>${u(t.message)}</p>
|
|
60
|
+
${r&&t.stack?`
|
|
61
|
+
<details>
|
|
62
|
+
<summary>Error details</summary>
|
|
63
|
+
<pre>${u(t.stack)}</pre>
|
|
64
|
+
</details>
|
|
65
|
+
`:``}
|
|
66
|
+
<a href="/">Go back home</a>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</body>
|
|
70
|
+
</html>`}catch(e){return console.error(`[Error Page Render Error]`,e),generateDefaultErrorPage(t.statusCode,t.message,r,t.stack)}}export function generateDefaultErrorPage(e,t,n,r){return n?s(e,t,r):c(e,t)}function s(e,t,n){return`<!DOCTYPE html>
|
|
71
|
+
<html lang="en">
|
|
72
|
+
<head>
|
|
73
|
+
<meta charset="utf-8">
|
|
74
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
75
|
+
<title>Error ${e}</title>
|
|
76
|
+
<style>
|
|
77
|
+
body {
|
|
78
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
79
|
+
margin: 0;
|
|
80
|
+
padding: 40px;
|
|
81
|
+
background: #1a1a1a;
|
|
82
|
+
color: #fff;
|
|
83
|
+
}
|
|
84
|
+
.error-container {
|
|
85
|
+
max-width: 800px;
|
|
86
|
+
margin: 0 auto;
|
|
87
|
+
background: #2d2d2d;
|
|
88
|
+
padding: 40px;
|
|
89
|
+
border-radius: 8px;
|
|
90
|
+
border-left: 4px solid #ff6b6b;
|
|
91
|
+
}
|
|
92
|
+
h1 {
|
|
93
|
+
color: #ff6b6b;
|
|
94
|
+
margin-top: 0;
|
|
95
|
+
font-size: 24px;
|
|
96
|
+
}
|
|
97
|
+
.status-code {
|
|
98
|
+
font-size: 48px;
|
|
99
|
+
font-weight: bold;
|
|
100
|
+
color: #ff6b6b;
|
|
101
|
+
margin-bottom: 10px;
|
|
102
|
+
}
|
|
103
|
+
.message {
|
|
104
|
+
font-size: 18px;
|
|
105
|
+
color: #ccc;
|
|
106
|
+
margin-bottom: 20px;
|
|
107
|
+
}
|
|
108
|
+
pre {
|
|
109
|
+
background: #1a1a1a;
|
|
110
|
+
padding: 20px;
|
|
111
|
+
border-radius: 4px;
|
|
112
|
+
overflow-x: auto;
|
|
113
|
+
font-size: 14px;
|
|
114
|
+
line-height: 1.5;
|
|
115
|
+
color: #e0e0e0;
|
|
116
|
+
}
|
|
117
|
+
.stack-title {
|
|
118
|
+
color: #888;
|
|
119
|
+
font-size: 12px;
|
|
120
|
+
text-transform: uppercase;
|
|
121
|
+
margin-bottom: 10px;
|
|
122
|
+
}
|
|
123
|
+
a {
|
|
124
|
+
color: #6b9fff;
|
|
125
|
+
text-decoration: none;
|
|
126
|
+
}
|
|
127
|
+
a:hover {
|
|
128
|
+
text-decoration: underline;
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
131
|
+
</head>
|
|
132
|
+
<body>
|
|
133
|
+
<div class="error-container">
|
|
134
|
+
<div class="status-code">${e}</div>
|
|
135
|
+
<h1>${l(e)}</h1>
|
|
136
|
+
<p class="message">${u(t)}</p>
|
|
137
|
+
${n?`
|
|
138
|
+
<div class="stack-title">Stack Trace</div>
|
|
139
|
+
<pre>${u(n)}</pre>
|
|
140
|
+
`:``}
|
|
141
|
+
<p><a href="/">← Return to home</a></p>
|
|
142
|
+
</div>
|
|
143
|
+
</body>
|
|
144
|
+
</html>`}function c(e,t){let n=e>=500?`An unexpected error occurred. Please try again later.`:t;return`<!DOCTYPE html>
|
|
145
|
+
<html lang="en">
|
|
146
|
+
<head>
|
|
147
|
+
<meta charset="utf-8">
|
|
148
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
149
|
+
<title>Error ${e}</title>
|
|
150
|
+
<style>
|
|
151
|
+
body {
|
|
152
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
153
|
+
margin: 0;
|
|
154
|
+
padding: 40px;
|
|
155
|
+
background: #f5f5f5;
|
|
156
|
+
display: flex;
|
|
157
|
+
align-items: center;
|
|
158
|
+
justify-content: center;
|
|
159
|
+
min-height: 100vh;
|
|
160
|
+
box-sizing: border-box;
|
|
161
|
+
}
|
|
162
|
+
.error-container {
|
|
163
|
+
text-align: center;
|
|
164
|
+
max-width: 400px;
|
|
165
|
+
}
|
|
166
|
+
.status-code {
|
|
167
|
+
font-size: 72px;
|
|
168
|
+
font-weight: bold;
|
|
169
|
+
color: #333;
|
|
170
|
+
margin-bottom: 10px;
|
|
171
|
+
}
|
|
172
|
+
h1 {
|
|
173
|
+
color: #666;
|
|
174
|
+
font-size: 24px;
|
|
175
|
+
margin: 0 0 20px 0;
|
|
176
|
+
}
|
|
177
|
+
p {
|
|
178
|
+
color: #888;
|
|
179
|
+
margin: 0 0 20px 0;
|
|
180
|
+
}
|
|
181
|
+
a {
|
|
182
|
+
color: #0066cc;
|
|
183
|
+
text-decoration: none;
|
|
184
|
+
}
|
|
185
|
+
a:hover {
|
|
186
|
+
text-decoration: underline;
|
|
187
|
+
}
|
|
188
|
+
</style>
|
|
189
|
+
</head>
|
|
190
|
+
<body>
|
|
191
|
+
<div class="error-container">
|
|
192
|
+
<div class="status-code">${e}</div>
|
|
193
|
+
<h1>${l(e)}</h1>
|
|
194
|
+
<p>${u(n)}</p>
|
|
195
|
+
<p><a href="/">Return to home</a></p>
|
|
196
|
+
</div>
|
|
197
|
+
</body>
|
|
198
|
+
</html>`}function l(e){return{400:`Bad Request`,401:`Unauthorized`,403:`Forbidden`,404:`Page Not Found`,405:`Method Not Allowed`,408:`Request Timeout`,410:`Gone`,429:`Too Many Requests`,500:`Internal Server Error`,502:`Bad Gateway`,503:`Service Unavailable`,504:`Gateway Timeout`}[e]||`Error`}function u(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`)}export async function handleRenderError(t,n,a){let{isDev:o=!1}=a,s=e(t)?t.statusCode:500,c=i(n);console.error(`[Render Error] ${s} - ${t.message}`,{url:c.pathname,stack:o?t.stack:void 0});let l=getErrorPageModule(s,await discoverErrorPages(a)),u;return u=l?await renderErrorPage(l,createErrorPageProps(t,c.pathname,o),r(n,{}),o):generateDefaultErrorPage(s,t.message,o,o?t.stack:void 0),new Response(u,{status:s,headers:{"Content-Type":`text/html; charset=utf-8`}})}export function handleApiError(t,n){let{isDev:r=!1}=n,i=e(t)?t.statusCode:500;console.error(`[API Error] ${i} - ${t.message}`,{stack:r?t.stack:void 0});let a=r?{error:t.message,statusCode:i,stack:t.stack}:{error:i>=500?`Internal Server Error`:t.message,statusCode:i};return new Response(JSON.stringify(a),{status:i,headers:{"Content-Type":`application/json`}})}export async function handleNotFound(e,n,r){return handleRenderError(t(`Page not found: ${e}`),n,r)}export async function handleInternalError(e,t,r){let i=n(e.message);return i.stack=e.stack,handleRenderError(i,t,r)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{createNitroConfig,isValidPreset,mergeRouteRules,createDefaultStaticAssetRouteRules,DEFAULT_NITRO_CONFIG,DEFAULT_STATIC_ASSETS_CONFIG}from"./config.js";export{HttpError,isHttpError,createNotFoundError,createMethodNotAllowedError,createInternalError}from"./types.js";export{createNitroRenderer,createNitroCatchAllRenderer,createRenderContext,renderPage,renderPageStream,createStreamingResponse,injectHydrationScript,validateHydrationMarkers,extractIslandMarkers,ensureHydrationMarkers,processHydrationRequirements,createErrorResponse,getRequestURL as getRendererRequestURL,toRequest as rendererToRequest,setResponseHeader}from"./renderer.js";export{createMiddlewareContext,storeMiddlewareContext,getMiddlewareContext,getOrCreateMiddlewareContext,setMiddlewareState,getMiddlewareState,setMiddlewareLocal,getMiddlewareLocal,hasAvalonContext,ensureAvalonContext,getRequestURL as getMiddlewareRequestURL,getRequestHeaders as getMiddlewareRequestHeaders,toRequest as middlewareToRequest,getRouterParams as getMiddlewareRouterParams}from"./middleware-adapter.js";export{discoverPageRoutes,filePathToPattern,isPrivateFile,calculateRouteSpecificity,sortRoutesBySpecificity,validateRoutePattern,extractParamsFromPattern,matchRoutePattern,PAGE_EXTENSIONS}from"./route-discovery.js";export{createClientBuildConfig,createServerBuildConfig,createCombinedBuildConfig,createNitroBuildPlugin,getPresetOutputConfig,presetSupportsStreaming,validateBuildConfig,createSourceMapConfig,createSourceMapPlugin,getViteSourceMapOption,DEFAULT_BUILD_CONFIG,DEFAULT_SOURCEMAP_CONFIG,PRESET_OUTPUT_CONFIGS}from"./build-config.js";export{createIslandManifestPlugin,createIslandEntry,detectIslandFramework,generateContentHash,extractIslandDependencies,generatePreloadHints,generatePreloadTags,loadIslandManifest,getIslandAssetPath,getPageCssAssets,DEFAULT_MANIFEST_OPTIONS}from"./island-manifest.js";export{discoverErrorPages,getErrorPageModule,renderErrorPage,generateDefaultErrorPage,createErrorPageProps,clearErrorPageCache,handleRenderError,handleApiError,handleNotFound,handleInternalError}from"./error-handler.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{readFile as e}from"node:fs/promises";export const DEFAULT_MANIFEST_OPTIONS={outputPath:`dist/island-manifest.json`,includeSourceMaps:!1,generatePreloadHints:!0,verbose:!1};const n={react:[/from\s+['"]react['"]/,/from\s+['"]react-dom['"]/,/@jsxImportSource\s+react/],preact:[/from\s+['"]preact['"]/,/from\s+['"]preact\/hooks['"]/,/@jsxImportSource\s+preact/],vue:[/from\s+['"]vue['"]/,/\.vue$/],svelte:[/from\s+['"]svelte['"]/,/\.svelte$/],solid:[/from\s+['"]solid-js['"]/,/\.solid\.(tsx|jsx)$/],lit:[/from\s+['"]lit['"]/,/from\s+['"]@lit['"]/,/\.lit\.(ts|js)$/]};export function detectIslandFramework(e,t){if(e.endsWith(`.vue`))return`vue`;if(e.endsWith(`.svelte`))return`svelte`;if(e.includes(`.solid.`))return`solid`;if(e.includes(`.lit.`))return`lit`;for(let[r,i]of Object.entries(n))for(let n of i)if(n.test(t)||n.test(e))return r;return e.endsWith(`.tsx`)||e.endsWith(`.jsx`)?`preact`:`unknown`}export async function generateContentHash(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,`0`)).join(``).slice(0,8)}export function extractIslandDependencies(e){let t=[],n=/import\s+.*?\s+from\s+['"]([^'"]+)['"]/g,r=/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,i;for(;(i=n.exec(e))!==null;){let e=i[1];!e.startsWith(`.`)&&!e.startsWith(`/`)&&t.push(e)}for(;(i=r.exec(e))!==null;){let e=i[1];!e.startsWith(`.`)&&!e.startsWith(`/`)&&t.push(e)}return[...new Set(t)]}export async function createIslandEntry(e,t,n,o){let s=detectIslandFramework(t,n),c=await generateContentHash(n);return{src:o,framework:s,css:[],preload:extractIslandDependencies(n).filter(e=>!e.includes(`/`)),sourcePath:t,chunkName:e,contentHash:c,preloadDeps:[],usesStreaming:!1}}export function generatePreloadHints(e){let t=[];e.clientEntry&&t.push({href:e.clientEntry,as:`script`,type:`text/javascript`});for(let n of e.css??[])t.push({href:n,as:`style`,type:`text/css`});for(let n of Object.values(e.frameworkBundles??{}))t.push({href:n,as:`script`,type:`text/javascript`});return t}export function createIslandManifestPlugin(e,n={}){let r={...DEFAULT_MANIFEST_OPTIONS,...n},a=new Map,o=new Set,c=``;return{name:`avalon:island-manifest`,enforce:`post`,generateBundle(e,t){for(let[e,n]of Object.entries(t))if(e.endsWith(`.css`)&&o.add(`/${e}`),n.type===`chunk`&&(n.name===`client`||n.name===`main`)&&(c=`/${e}`),n.type===`chunk`&&(n.facadeModuleId?.includes(`/islands/`)||n.name?.startsWith(`islands/`))){let t=n.name?.replace(`islands/`,``)??e,r=a.get(t);r?r.src=`/${e}`:a.set(t,{src:`/${e}`,framework:u(n),css:[],preload:[],sourcePath:n.facadeModuleId??``,chunkName:t,contentHash:/\.([a-f0-9]+)\.js$/.exec(e)?.[1]??``,preloadDeps:n.imports??[],usesStreaming:!1})}},async writeBundle(e,t){let n={},u=new Date().toISOString();for(let[e,r]of Object.entries(t)){let t=await l(e,r,u);t&&(n[`/${e}`]=t)}let d={islands:Object.fromEntries(a),clientEntry:c,css:Array.from(o),buildTime:Date.now(),buildHash:await generateContentHash(JSON.stringify(Object.fromEntries(a))),avalonVersion:`1.0.0`,cssAssets:Array.from(o),preloadHints:r.generatePreloadHints?generatePreloadHints({clientEntry:c,css:Array.from(o),islands:Object.fromEntries(a)}):[],frameworkBundles:{},assetMetadata:n},f=JSON.stringify(d,null,2);r.verbose&&(console.log(`📋 Island manifest generated:`),console.log(` Islands: ${a.size}`),console.log(` CSS assets: ${o.size}`),console.log(` Client entry: ${c}`),console.log(` Asset metadata entries: ${Object.keys(n).length}`)),this.emitFile({type:`asset`,fileName:`island-manifest.json`,source:f})}}}async function l(e,t,n){let r;if(t.type===`asset`&&t.source?r=t.source:t.type===`chunk`&&t.code&&(r=t.code),!r)return null;let a=typeof r==`string`?new TextEncoder().encode(r).length:r.length,o=await generateContentHash(typeof r==`string`?r:new TextDecoder().decode(r)),s=e.substring(e.lastIndexOf(`.`));return{type:{".js":`application/javascript`,".mjs":`application/javascript`,".css":`text/css`,".json":`application/json`,".html":`text/html`,".map":`application/json`}[s]??`application/octet-stream`,etag:`"${o}"`,mtime:n,size:a}}function u(e){return detectIslandFramework(e.facadeModuleId??``,e.code??``)}export async function loadIslandManifest(t=`dist/island-manifest.json`){try{let n=await e(t,`utf-8`);return JSON.parse(n)}catch{return null}}export function getIslandAssetPath(e,t){return t?t.islands[e]?.src??null:null}export function getPageCssAssets(e,t){if(!t)return[];let n=new Set;for(let e of t.css)n.add(e);for(let r of e){let e=t.islands[r];if(e?.css)for(let t of e.css)n.add(t)}return Array.from(n)}export function generatePreloadTags(e){let t=[];for(let n of e.preloadHints){let e=[`rel="preload"`,`href="${n.href}"`,`as="${n.as}"`];n.type&&e.push(`type="${n.type}"`),n.crossorigin&&e.push(`crossorigin="${n.crossorigin}"`),t.push(`<link ${e.join(` `)}>`)}return t.join(`
|
|
2
|
+
`)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getRequestURL as e}from"h3";export function getRequestURL(t){return new URL(e(t).pathname,`http://localhost`)}export function getRequestHeaders(e){return new Headers(e.req.headers)}export function toRequest(e){let r=getRequestURL(e),i=e.req.method.toUpperCase();return new Request(r,{method:i,headers:getRequestHeaders(e)})}export function getRouterParams(e){return e.context.params??{}}export function createMiddlewareContext(n,a={}){let{enableLogging:o=!1}=a,s=getRequestURL(n),c=getRouterParams(n),l={};for(let[e,t]of s.searchParams.entries())l[e]?Array.isArray(l[e])?l[e].push(t):l[e]=[l[e],t]:l[e]=t;return o&&console.log(`[Middleware Context] Created for ${n.req.method} ${e(n).pathname}`),{request:toRequest(n),url:s,params:c,query:l,state:new Map,locals:{}}}export function storeMiddlewareContext(e,t){e.context.avalon||(e.context.avalon={}),e.context.avalon.middlewareContext=t}export function getMiddlewareContext(e){return e.context.avalon?.middlewareContext}export function getOrCreateMiddlewareContext(e,t={}){let n=getMiddlewareContext(e);if(n)return n;let r=createMiddlewareContext(e,t);return storeMiddlewareContext(e,r),r}export function setMiddlewareState(e,t,n){getOrCreateMiddlewareContext(e).state.set(t,n)}export function getMiddlewareState(e,t){return getMiddlewareContext(e)?.state.get(t)}export function setMiddlewareLocal(e,t,n){let r=getOrCreateMiddlewareContext(e);r.locals[t]=n}export function getMiddlewareLocal(e,t){return getMiddlewareContext(e)?.locals[t]}export function hasAvalonContext(e){return e.context.avalon!==void 0}export function ensureAvalonContext(e){return e.context.avalon||(e.context.avalon={}),e.context.avalon}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import{getRequestURL as e}from"h3";import{createNotFoundError as t,isHttpError as n}from"./types.js";import{discoverScopedMiddleware as r,executeScopedMiddleware as i}from"../middleware/index.js";import{handleRenderError as a,discoverErrorPages as o}from"./error-handler.js";import{h as s}from"preact";import c from"preact-render-to-string";export function createRenderContext(e,t={}){let n=getRequestURL(e);return{url:n,params:t,query:Object.fromEntries(n.searchParams),request:toRequest(e),event:e}}export function getRequestURL(t){return new URL(e(t).pathname,`http://localhost`)}export function toRequest(e){let t=getRequestURL(e);return new Request(t,{method:e.req.method,headers:getRequestHeaders(e)})}export function getRequestHeaders(e){return new Headers}export function setResponseHeader(e,t,n){e.context.responseHeaders||(e.context.responseHeaders={}),e.context.responseHeaders[t]=n}export function createErrorResponse(e,t){let r=n(e)?e.statusCode:500;if(t){let t=h(e,r);return new Response(t,{status:r,headers:{"Content-Type":`text/html; charset=utf-8`}})}let i=g(r);return new Response(i,{status:r,headers:{"Content-Type":`text/html; charset=utf-8`}})}function h(e,t){return`<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Error ${t}</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 40px;
|
|
12
|
+
background: #1a1a1a;
|
|
13
|
+
color: #fff;
|
|
14
|
+
}
|
|
15
|
+
.error-container {
|
|
16
|
+
max-width: 800px;
|
|
17
|
+
margin: 0 auto;
|
|
18
|
+
background: #2d2d2d;
|
|
19
|
+
padding: 40px;
|
|
20
|
+
border-radius: 8px;
|
|
21
|
+
border-left: 4px solid #ff6b6b;
|
|
22
|
+
}
|
|
23
|
+
h1 {
|
|
24
|
+
color: #ff6b6b;
|
|
25
|
+
margin-top: 0;
|
|
26
|
+
font-size: 24px;
|
|
27
|
+
}
|
|
28
|
+
.status-code {
|
|
29
|
+
font-size: 48px;
|
|
30
|
+
font-weight: bold;
|
|
31
|
+
color: #ff6b6b;
|
|
32
|
+
margin-bottom: 10px;
|
|
33
|
+
}
|
|
34
|
+
.message {
|
|
35
|
+
font-size: 18px;
|
|
36
|
+
color: #ccc;
|
|
37
|
+
margin-bottom: 20px;
|
|
38
|
+
}
|
|
39
|
+
pre {
|
|
40
|
+
background: #1a1a1a;
|
|
41
|
+
padding: 20px;
|
|
42
|
+
border-radius: 4px;
|
|
43
|
+
overflow-x: auto;
|
|
44
|
+
font-size: 14px;
|
|
45
|
+
line-height: 1.5;
|
|
46
|
+
color: #e0e0e0;
|
|
47
|
+
}
|
|
48
|
+
.stack-title {
|
|
49
|
+
color: #888;
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
text-transform: uppercase;
|
|
52
|
+
margin-bottom: 10px;
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<div class="error-container">
|
|
58
|
+
<div class="status-code">${t}</div>
|
|
59
|
+
<h1>${_(t)}</h1>
|
|
60
|
+
<p class="message">${v(e.message)}</p>
|
|
61
|
+
${e.stack?`
|
|
62
|
+
<div class="stack-title">Stack Trace</div>
|
|
63
|
+
<pre>${v(e.stack)}</pre>
|
|
64
|
+
`:``}
|
|
65
|
+
</div>
|
|
66
|
+
</body>
|
|
67
|
+
</html>`}function g(e){return`<!DOCTYPE html>
|
|
68
|
+
<html lang="en">
|
|
69
|
+
<head>
|
|
70
|
+
<meta charset="utf-8">
|
|
71
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
72
|
+
<title>Error ${e}</title>
|
|
73
|
+
<style>
|
|
74
|
+
body {
|
|
75
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 40px;
|
|
78
|
+
background: #f5f5f5;
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: center;
|
|
82
|
+
min-height: 100vh;
|
|
83
|
+
box-sizing: border-box;
|
|
84
|
+
}
|
|
85
|
+
.error-container {
|
|
86
|
+
text-align: center;
|
|
87
|
+
max-width: 400px;
|
|
88
|
+
}
|
|
89
|
+
.status-code {
|
|
90
|
+
font-size: 72px;
|
|
91
|
+
font-weight: bold;
|
|
92
|
+
color: #333;
|
|
93
|
+
margin-bottom: 10px;
|
|
94
|
+
}
|
|
95
|
+
h1 {
|
|
96
|
+
color: #666;
|
|
97
|
+
font-size: 24px;
|
|
98
|
+
margin: 0 0 20px 0;
|
|
99
|
+
}
|
|
100
|
+
p {
|
|
101
|
+
color: #888;
|
|
102
|
+
margin: 0;
|
|
103
|
+
}
|
|
104
|
+
a {
|
|
105
|
+
color: #0066cc;
|
|
106
|
+
text-decoration: none;
|
|
107
|
+
}
|
|
108
|
+
a:hover {
|
|
109
|
+
text-decoration: underline;
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
112
|
+
</head>
|
|
113
|
+
<body>
|
|
114
|
+
<div class="error-container">
|
|
115
|
+
<div class="status-code">${e}</div>
|
|
116
|
+
<h1>${_(e)}</h1>
|
|
117
|
+
<p><a href="/">Return to home</a></p>
|
|
118
|
+
</div>
|
|
119
|
+
</body>
|
|
120
|
+
</html>`}function _(e){return{400:`Bad Request`,401:`Unauthorized`,403:`Forbidden`,404:`Page Not Found`,405:`Method Not Allowed`,500:`Internal Server Error`,502:`Bad Gateway`,503:`Service Unavailable`}[e]||`Error`}function v(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`)}export function extractIslandMarkers(e){let t=[],n=/<[^>]*data-framework="([^"]+)"[^>]*>/g,r;for(;(r=n.exec(e))!==null;){let e=r[0],n=r[1],i=/data-src="([^"]+)"/.exec(e),a=i?i[1]:``,o=/data-props="([^"]*)"/.exec(e),s=o?o[1]:void 0,c=/data-hydrate="([^"]+)"/.exec(e),l=c?c[1]:void 0;t.push({framework:n,src:a,props:s,hydrate:l})}return t}export function ensureHydrationMarkers(e,t){let n=e;return t.framework&&!n.includes(`data-framework=`)&&(n=n.replace(/>/,` data-framework="${t.framework}">`)),t.src&&!n.includes(`data-src=`)&&(n=n.replace(/>/,` data-src="${t.src}">`)),t.props!==void 0&&!n.includes(`data-props=`)&&(n=n.replace(/>/,` data-props="${t.props}">`)),n}export function injectHydrationScript(e,t,n={}){if(!(e.includes(`data-framework=`)||e.includes(`data-src=`))&&!n.forceInject||[`/src/client/main.js`,`/dist/client.js`,`client/main.js`].some(t=>e.includes(t)))return e;let r=n.scriptPath||(t?`/src/client/main.js`:`/dist/client.js`),i=[];i.push(`<script type="module" src="${r}"><\/script>`),n.additionalScripts&&i.push(...n.additionalScripts);let a=i.join(`
|
|
121
|
+
`);return e.includes(`</body>`)?e.replace(`</body>`,`${a}\n</body>`):e+a}export function validateHydrationMarkers(e){let t=extractIslandMarkers(e),n=e.match(/data-framework="[^"]+"/g)||[],r=e.match(/data-src="[^"]+"/g)||[],i=e.match(/data-props="[^"]*"/g)||[],a=e.includes(`/src/client/main.js`)||e.includes(`/dist/client.js`)||e.includes(`client/main.js`),o=t.every(e=>e.framework&&e.src),s=t.length===0||o&&a;return{hasFrameworkAttr:n.length>0,hasSrcAttr:r.length>0,hasPropsAttr:i.length>0,islandCount:n.length,islands:t,hasClientScript:a,isValid:s}}export function processHydrationRequirements(e,t){let n=injectHydrationScript(e,t);return{html:n,validation:validateHydrationMarkers(n)}}export async function renderPage(e,t,n={}){try{let r={};return e.getServerSideProps&&(r=await e.getServerSideProps(t)),{html:await y(e,r,t,n),statusCode:200,headers:{"Content-Type":`text/html; charset=utf-8`}}}catch(e){throw console.error(`[SSR Error]`,e),n.onError&&e instanceof Error&&n.onError(e),e}}async function y(e,t,n,r){let i=e.default,a=e.metadata||{},o;try{let e=i(t);o=e instanceof Promise?await e:e}catch(e){console.error(`[renderer] Error calling page component:`,e),o=s(`div`,null,`Error rendering page`)}let l;try{l=c(o)}catch(e){console.error(`[renderer] Error in preactRenderToString:`,e),l=`<div>Error rendering page</div>`}return`<!DOCTYPE html>
|
|
122
|
+
<html lang="en">
|
|
123
|
+
<head>
|
|
124
|
+
<meta charset="utf-8">
|
|
125
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
126
|
+
<title>${v(String(a.title||`Avalon App`))}</title>
|
|
127
|
+
${a.description?`<meta name="description" content="${v(String(a.description))}">`:``}
|
|
128
|
+
</head>
|
|
129
|
+
<body>
|
|
130
|
+
<div id="app">
|
|
131
|
+
${l}
|
|
132
|
+
</div>
|
|
133
|
+
<script type="module" src="/src/client/main.js"><\/script>
|
|
134
|
+
</body>
|
|
135
|
+
</html>`}export async function renderPageStream(e,t,n={}){let r=new TextEncoder,i=null,a={shellSent:!1,contentSent:!1,closed:!1,error:null},o=n.shellReadyTimeout,s=n.allReadyTimeout,c=null,l=null,u=()=>{c&&=(clearTimeout(c),null),l&&=(clearTimeout(l),null)};function d(e,t,n,r,i,a,o){if(n.error=e,a(),console.error(`[Streaming Error]`,{message:e.message,stack:e.stack,shellSent:n.shellSent,isShellError:t,timestamp:new Date().toISOString()}),t&&o.onShellError&&o.onShellError(e),o.onError&&o.onError(e),!n.closed&&r){if(n.shellSent){let t=C(e);r.enqueue(i.encode(t));let n=S();r.enqueue(i.encode(n))}else{let t=h(e,500);r.enqueue(i.encode(t))}n.closed=!0,r.close()}}async function f(o){i=o;let f={};e.getServerSideProps&&(f=await e.getServerSideProps(t));let p=b(e.metadata||{},t);if(a.closed||(o.enqueue(r.encode(p)),a.shellSent=!0,c&&=(clearTimeout(c),null),n.onShellReady&&n.onShellReady()),s&&s>0&&(l=setTimeout(()=>{!a.contentSent&&!a.closed&&d(Error(`All ready timeout after ${s}ms`),!1,a,i,r,u,n)},s)),!a.closed){let t=x(e,f);o.enqueue(r.encode(t)),a.contentSent=!0}if(!a.closed){let e=S();o.enqueue(r.encode(e))}u(),n.onAllReady&&!a.closed&&n.onAllReady(),a.closed||(a.closed=!0,o.close())}return new ReadableStream({async start(e){i=e,o&&o>0&&(c=setTimeout(()=>{!a.shellSent&&!a.closed&&d(Error(`Shell ready timeout after ${o}ms`),!0,a,i,r,u,n)},o));try{await f(e)}catch(e){d(e instanceof Error?e:Error(String(e)),!a.shellSent,a,i,r,u,n)}},cancel(){if(u(),!a.closed&&i){a.closed=!0;try{i.close()}catch{}}}})}function b(e,t){return`<!DOCTYPE html>
|
|
136
|
+
<html lang="en">
|
|
137
|
+
<head>
|
|
138
|
+
<meta charset="utf-8">
|
|
139
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
140
|
+
<title>${v(String(e.title||`Avalon App`))}</title>
|
|
141
|
+
${e.description?`<meta name="description" content="${v(String(e.description))}">`:``}
|
|
142
|
+
</head>
|
|
143
|
+
<body>
|
|
144
|
+
`}function x(e,t){let n=e.default?.name||`Page`;return` <div id="app" data-page="${v(String(n))}" data-props='${v(JSON.stringify(t))}'>
|
|
145
|
+
<!-- Page content rendered by Avalon SSR pipeline -->
|
|
146
|
+
</div>
|
|
147
|
+
`}function S(){return` </body>
|
|
148
|
+
</html>`}function C(e){let t=process.env.NODE_ENV!==`production`,n=e.stack?`<pre style="
|
|
149
|
+
background: #f5f5f5;
|
|
150
|
+
padding: 10px;
|
|
151
|
+
border-radius: 4px;
|
|
152
|
+
overflow-x: auto;
|
|
153
|
+
font-size: 12px;
|
|
154
|
+
margin-top: 10px;
|
|
155
|
+
">${v(e.stack)}</pre>`:``;return`
|
|
156
|
+
<div class="streaming-error-boundary" data-error-boundary="true" style="
|
|
157
|
+
background: #fff3cd;
|
|
158
|
+
border: 2px solid #ffc107;
|
|
159
|
+
border-radius: 8px;
|
|
160
|
+
padding: 20px;
|
|
161
|
+
margin: 20px 0;
|
|
162
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
163
|
+
">
|
|
164
|
+
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
|
|
165
|
+
<span style="font-size: 24px;">⚠️</span>
|
|
166
|
+
<h3 style="margin: 0; color: #856404;">Streaming Error</h3>
|
|
167
|
+
</div>
|
|
168
|
+
<p style="margin: 10px 0; color: #856404;">
|
|
169
|
+
An error occurred while streaming this page.
|
|
170
|
+
</p>
|
|
171
|
+
${t?`
|
|
172
|
+
<details style="margin-top: 15px;">
|
|
173
|
+
<summary style="cursor: pointer; color: #856404; font-weight: bold;">
|
|
174
|
+
Error Details (Development Mode)
|
|
175
|
+
</summary>
|
|
176
|
+
<div style="margin-top: 10px;">
|
|
177
|
+
<p><strong>Error:</strong> ${v(e.message)}</p>
|
|
178
|
+
${n}
|
|
179
|
+
</div>
|
|
180
|
+
</details>
|
|
181
|
+
`:``}
|
|
182
|
+
</div>
|
|
183
|
+
`}export function createStreamingResponse(e,t={}){let n=new Headers({"Content-Type":`text/html; charset=utf-8`,"Transfer-Encoding":`chunked`,...t.headers});return new Response(e,{status:t.status||200,headers:n})}function w(e,t,n){return async()=>(e.value??=await r({baseDir:t,devMode:n}),e.value)}function T(e,t,n){return async(r,i)=>e?a(r,i,t):createErrorResponse(r,n)}export function createNitroRenderer(e){let{avalonConfig:n,isDev:r=!1,enableCustomErrorPages:a=!0}=e,s={isDev:r,avalonConfig:n,loadPageModule:e.loadPageModule,pagesDir:n.pagesDir};a&&o(s).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let c=w({value:null},n.srcDir||`src`,r),d=T(a,s,r);return async function(a){let o=getRequestURL(a).pathname;try{let s=await i(a,await c(),{devMode:r});if(s)return r&&console.log(`[renderer] Middleware terminated request for ${o}`),s;let u=a.context.route,f=null;if(f=u||(e.resolvePageRoute?await e.resolvePageRoute(o,n.pagesDir):await E(o,n.pagesDir)),!f)return d(t(`Page not found: ${o}`),a);let m=e.loadPageModule?await e.loadPageModule(f.filePath):await D(f.filePath),h=createRenderContext(a,a.context.params||f.params);if(e.resolveLayouts&&(h.layoutContext={layouts:await e.resolveLayouts(o,n)}),n.streaming){let e=await renderPageStream(m,h,{onShellReady:()=>{setResponseHeader(a,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(e,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let e=await renderPage(m,h),t=injectHydrationScript(e.html,r);return new Response(t,{status:e.statusCode,headers:e.headers})}}catch(e){return console.error(`[Nitro Renderer Error]`,e),d(e instanceof Error?e:Error(String(e)),a)}}}async function E(e,t){return e===`/`||e===``?{filePath:`src/pages/index.tsx`,pattern:`/`,params:{}}:{filePath:`src/pages/${e.replace(/^\//,``).replace(/\/$/,``)}.tsx`,pattern:e,params:{}}}async function D(e){return{default:()=>null,metadata:{title:`Avalon Page`}}}export function createNitroCatchAllRenderer(e){let{avalonConfig:n,isDev:r=!1,loadPageModule:a,resolveLayouts:s,enableCustomErrorPages:c=!0}=e,d={isDev:r,avalonConfig:n,loadPageModule:a,pagesDir:n.pagesDir};c&&o(d).catch(e=>{console.warn(`[renderer] Failed to discover error pages:`,e)});let f=w({value:null},n.srcDir||`src`,r),m=T(c,d,r);return async function(e){let o=getRequestURL(e).pathname;try{let c=await i(e,await f(),{devMode:r});if(c)return r&&console.log(`[renderer] Middleware terminated request for ${o}`),c;let u=e.context.params||{},d=u.slug||o.replace(/^\//,``)||`index`,h=`${n.pagesDir}/${d}.tsx`,g;try{g=await a(h)}catch(i){try{g=await a(`${n.pagesDir}/${d}/index.tsx`)}catch(a){return r&&(console.debug(`[renderer] Page not found: ${h}`,i),console.debug(`[renderer] Index fallback not found: ${n.pagesDir}/${d}/index.tsx`,a)),m(t(`Page not found: ${o}`),e)}}let _=createRenderContext(e,u);if(s&&(_.layoutContext={layouts:await s(o,n)}),n.streaming){let t=await renderPageStream(g,_,{onShellReady:()=>{setResponseHeader(e,`Content-Type`,`text/html; charset=utf-8`)}});return new Response(t,{headers:{"Content-Type":`text/html; charset=utf-8`}})}else{let e=await renderPage(g,_),t=injectHydrationScript(e.html,r);return new Response(t,{status:e.statusCode,headers:e.headers})}}catch(t){return console.error(`[Nitro Catch-All Renderer Error]`,t),m(t instanceof Error?t:Error(String(t)),e)}}}export{clearMiddlewareCache as clearRendererMiddlewareCache}from"../middleware/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{stat as e}from"node:fs/promises";import{basename as t,dirname as n,relative as r}from"node:path";import{walk as i}from"../utils/fs.js";export const PAGE_EXTENSIONS=[`.tsx`,`.ts`,`.jsx`,`.js`,`.vue`,`.svelte`,`.md`,`.mdx`];export async function discoverPageRoutesFromMultipleDirs(e,t){let n=[];for(let{dir:r,prefix:i}of e){let e=await discoverPageRoutes(r,t);for(let t of e)i!==`/`&&(t.pattern=t.pattern===`/`?i:i+t.pattern),n.push(t)}return sortRoutesBySpecificity(n)}export async function discoverPageRoutes(t,n){let o=[],s=n?.excludeDirectories??[`node_modules`,`.git`];try{if(!(await e(t)).isDirectory())return n?.developmentMode&&console.warn(`[route-discovery] Pages path is not a directory: ${t}`),[]}catch(e){if(e instanceof Error&&e.code===`ENOENT`)return n?.developmentMode&&console.warn(`[route-discovery] Pages directory not found: ${t}`),[];throw e}let l=PAGE_EXTENSIONS.map(e=>e.slice(1));for await(let e of i(t,{includeDirs:!1,includeSymlinks:!1,exts:l})){if(!e.isFile)continue;let n=r(t,e.path);if(s.some(e=>n.includes(e))||isPrivateFile(n))continue;let{pattern:i,params:a}=filePathToPattern(n);o.push({type:`page`,filePath:e.path,pattern:i,params:a})}return sortRoutesBySpecificity(o)}export function filePathToPattern(e){let r=[],i=e.replace(/\\/g,`/`).replace(/\.(tsx|ts|jsx|js|vue|svelte|md|mdx)$/,``).replace(/\([^)]+\)\//g,``).replace(/\([^)]+\)$/,``);return t(i)===`index`&&(i=n(i),i===`.`&&(i=``)),i=i.replace(/\[([^\]]+)\]/g,(e,t)=>{if(t.startsWith(`...`)){let e=t.slice(3);return r.push(e),`**`}else return r.push(t),`:${t}`}),i.startsWith(`/`)||(i=`/`+i),(i===`/`||i===``)&&(i=`/`),i.length>1&&i.endsWith(`/`)&&(i=i.slice(0,-1)),{pattern:i,params:r}}export function isPrivateFile(e){return e.split(/[/\\]/).some(e=>e.startsWith(`_`))}export function calculateRouteSpecificity(e){let t=e.pattern.split(`/`).filter(e=>e.length>0),n=0;for(let e of t)e===`**`?n+=1e3:e.startsWith(`:`)?n+=100:n+=1;return n+=t.length,n}export function sortRoutesBySpecificity(e){return[...e].sort((e,t)=>calculateRouteSpecificity(e)-calculateRouteSpecificity(t))}export function validateRoutePattern(e){let t=[];e.startsWith(`/`)||t.push(`Route pattern must start with /`);let n=e.match(/\[[^\]]*$/g);n&&t.push(`Malformed dynamic segments: ${n.join(`, `)}. Dynamic segments must be properly closed with ]`),e.match(/\[\]/g)&&t.push(`Empty dynamic segments [] are not allowed. Use [param] for dynamic segments or [...rest] for catch-all`);let r=e.match(/\[[^\]]*\[[^\]]*\]/g);return r&&t.push(`Nested dynamic segments are not supported: ${r.join(`, `)}`),t}export function extractParamsFromPattern(e){let t=[],n=e.matchAll(/:([^/]+)/g);for(let e of n)t.push(e[1]);return e.includes(`**`)&&t.push(`slug`),t}export function matchRoutePattern(e,t){let n={},r=e.replace(/\/$/,``)||`/`,i=t.replace(/\/$/,``)||`/`,a=r.split(`/`).filter(e=>e),o=i.split(`/`).filter(e=>e),s=0,c=0;for(;s<a.length;){let e=a[s];if(e===`**`)return n.slug=o.slice(c).join(`/`),{matches:!0,params:n};if(c>=o.length)return{matches:!1,params:{}};let t=o[c];if(e.startsWith(`:`)){let r=e.slice(1);n[r]=t}else if(e!==t)return{matches:!1,params:{}};s++,c++}return c<o.length?{matches:!1,params:{}}:{matches:!0,params:n}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class HttpError extends Error{statusCode;data;constructor(e,t,n){super(t),this.name=`HttpError`,this.statusCode=e,this.data=n}}export function createNotFoundError(t=`Not Found`){return new HttpError(404,t)}export function createMethodNotAllowedError(t){return new HttpError(405,`Method Not Allowed`,{allowed:t})}export function createInternalError(t=`Internal Server Error`){return new HttpError(500,t)}export function isHttpError(t){return t instanceof HttpError}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export async function collectCssFromModuleGraph(e,r){let i=[],a=new Set,o=await e.moduleGraph.getModuleByUrl(r);if(!o)return i;let s=[o];for(;s.length>0;){let r=s.shift(),o=r.id??r.url;if(!a.has(o)){if(a.add(o),t(o)){let t=await n(e,r);t&&i.push(t)}for(let e of r.importedModules){let t=e.id??e.url;a.has(t)||s.push(e)}}}return i}function t(e){let t=e.split(`?`)[0];return t.endsWith(`.css`)||t.endsWith(`.scss`)||t.endsWith(`.sass`)||t.endsWith(`.less`)||t.endsWith(`.styl`)||t.endsWith(`.stylus`)}async function n(e,t){try{let n=t.url,i=await e.transformRequest(n+`?direct`);return i&&typeof i.code==`string`?r(i.code):null}catch{return null}}function r(e){let t=new RegExp(/const\s+__vite__css\s*=\s*"((?:[^"\\]|\\.)*)"/).exec(e);if(t)return i(t[1]);let n=new RegExp(/__vite_ssr_exports__\.default\s*=\s*"((?:[^"\\]|\\.)*)"/).exec(e);if(n)return i(n[1]);let r=new RegExp(/export\s+default\s+"((?:[^"\\]|\\.)*)"/).exec(e);return r?i(r[1]):!e.includes(`export `)&&!e.includes(`__vite`)?e:null}function i(e){return e.replaceAll(String.raw`\n`,`
|
|
2
|
+
`).replaceAll(String.raw`\t`,` `).replaceAll(String.raw`\r`,`\r`).replaceAll(String.raw`\"`,`"`).replaceAll(`\\\\`,`\\`)}export function injectSsrCss(e,t){if(t.length===0)return e;let n=t.map(e=>`<style data-avalon-ssr-css>${o(e)}</style>`).join(`
|
|
3
|
+
`);return e.includes(`</head>`)?e.replace(`</head>`,`${n}\n</head>`):e.includes(`<head>`)?e.replace(`<head>`,`<head>\n${n}`):n+e}function o(e){return e.replaceAll(/<\/style/gi,String.raw`<\/style`)}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
function e(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`)}export function generateErrorPage(t){return`<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>SSR Error</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 40px;
|
|
12
|
+
background: #1a1a1a;
|
|
13
|
+
color: #fff;
|
|
14
|
+
}
|
|
15
|
+
.error-container {
|
|
16
|
+
max-width: 800px;
|
|
17
|
+
margin: 0 auto;
|
|
18
|
+
background: #2d2d2d;
|
|
19
|
+
padding: 40px;
|
|
20
|
+
border-radius: 8px;
|
|
21
|
+
border-left: 4px solid #ff6b6b;
|
|
22
|
+
}
|
|
23
|
+
h1 { color: #ff6b6b; margin-top: 0; font-size: 24px; }
|
|
24
|
+
.message { font-size: 18px; color: #ccc; margin-bottom: 20px; }
|
|
25
|
+
pre {
|
|
26
|
+
background: #1a1a1a;
|
|
27
|
+
padding: 20px;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
overflow-x: auto;
|
|
30
|
+
font-size: 14px;
|
|
31
|
+
line-height: 1.5;
|
|
32
|
+
color: #e0e0e0;
|
|
33
|
+
}
|
|
34
|
+
.stack-title { color: #888; font-size: 12px; text-transform: uppercase; margin-bottom: 10px; }
|
|
35
|
+
</style>
|
|
36
|
+
</head>
|
|
37
|
+
<body>
|
|
38
|
+
<div class="error-container">
|
|
39
|
+
<h1>SSR Error</h1>
|
|
40
|
+
<p class="message">${e(t.message)}</p>
|
|
41
|
+
${t.stack?`
|
|
42
|
+
<div class="stack-title">Stack Trace</div>
|
|
43
|
+
<pre>${e(t.stack)}</pre>
|
|
44
|
+
`:``}
|
|
45
|
+
</div>
|
|
46
|
+
<script type="module" src="/@vite/client"><\/script>
|
|
47
|
+
</body>
|
|
48
|
+
</html>`}export function generateFallback404(t){return`<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>404 - Page Not Found</h1><p>The page ${e(t)} was not found.</p></body></html>`}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{render as e}from"preact-render-to-string";import{readFile as t}from"node:fs/promises";import{EnhancedFrameworkDetector as n}from"../core/components/enhanced-framework-detector.js";import{toImportSpecifier as r}from"../middleware/executor.js";export class IsolatedSSRRenderer{contexts;detector;config;activeContext=null;constructor(e={}){this.contexts=new Map,this.detector=new n,this.config={enableStrictIsolation:!0,allowedCrossFrameworkImports:[`preact`,`preact-render-to-string`],errorHandling:`fallback`,debugLogging:!1,...e},this.initializeFrameworkContexts()}async renderWithIsolation(e){let t=[],n=[];try{let r=await this.resolveFramework(e,n);return await this.renderInContext(e,r,t,n)}catch(r){return t.push(`SSR rendering failed: ${r instanceof Error?r.message:String(r)}`),await this.tryFallbackRender(e,t,n)}}async resolveFramework(e,t){if(e.framework)return e.framework;try{let n=await this.getComponentContent(e.componentPath),r=this.detector.detectFramework(e.componentPath,n);return r.confidence===`low`&&t.push(`Low confidence framework detection for ${e.componentPath}: ${r.framework}`),this.config.debugLogging&&(console.log(`[SSR Isolation] Detected framework: ${r.framework} for ${e.componentPath}`),console.log(`[SSR Isolation] Evidence: ${r.evidence.join(`, `)}`)),r.framework}catch{return t.push(`Could not read component file for framework detection: ${e.componentPath}, defaulting to preact`),`preact`}}async renderInContext(e,t,n,r){let i=this.getFrameworkContext(t);if(!i)throw Error(`No SSR context available for framework: ${t}`);await this.switchToContext(t);try{let a=e.component(),o=a instanceof Promise?await a:a;return{html:await i.renderFunction(o,e.props||{}),framework:t,success:!0,errors:n,warnings:r}}finally{this.cleanupContext(t)}}async tryFallbackRender(t,n,r){if(this.config.errorHandling!==`fallback`)return{html:``,framework:t.framework||`unknown`,success:!1,errors:n,warnings:r};try{let i=e(await t.component());return r.push(`Fell back to Preact rendering due to framework-specific error`),{html:i,framework:`preact`,success:!0,errors:n,warnings:r}}catch(e){return n.push(`Fallback rendering also failed: ${e instanceof Error?e.message:String(e)}`),{html:``,framework:t.framework||`unknown`,success:!1,errors:n,warnings:r}}}initializeFrameworkContexts(){this.contexts.set(`preact`,{framework:`preact`,imports:new Map,renderFunction:t=>Promise.resolve(e(t)),cleanup:()=>{this.clearFrameworkGlobals(`preact`)},isActive:!1}),this.contexts.set(`solid`,{framework:`solid`,imports:new Map,renderFunction:async e=>{try{let t=await this.importFrameworkModule(`solid-js/web`,`solid`);if(t&&typeof t.renderToString==`function`)return t.renderToString(()=>e);throw Error(`Solid renderToString not available`)}catch(e){throw Error(`Solid SSR failed: ${e instanceof Error?e.message:String(e)}`)}},cleanup:()=>{this.clearFrameworkGlobals(`solid`)},isActive:!1}),this.contexts.set(`vue`,{framework:`vue`,imports:new Map,renderFunction:async e=>{try{let t=await this.importFrameworkModule(`vue/server-renderer`,`vue`);if(t&&typeof t.renderToString==`function`)return await t.renderToString(e);throw Error(`Vue renderToString not available`)}catch(e){throw Error(`Vue SSR failed: ${e instanceof Error?e.message:String(e)}`)}},cleanup:()=>{this.clearFrameworkGlobals(`vue`)},isActive:!1}),this.contexts.set(`svelte`,{framework:`svelte`,imports:new Map,renderFunction:e=>{try{if(e&&typeof e==`object`&&`render`in e){let t=e.render();return Promise.resolve(t.html||``)}throw Error(`Svelte component does not have render method`)}catch(e){throw Error(`Svelte SSR failed: ${e instanceof Error?e.message:String(e)}`)}},cleanup:()=>{this.clearFrameworkGlobals(`svelte`)},isActive:!1}),this.contexts.set(`unknown`,{framework:`unknown`,imports:new Map,renderFunction:t=>Promise.resolve(e(t)),cleanup:()=>{},isActive:!1})}getFrameworkContext(e){return this.contexts.get(e)||this.contexts.get(`unknown`)||null}async switchToContext(e){this.activeContext&&this.activeContext!==e&&this.cleanupContext(this.activeContext);let t=this.contexts.get(e);if(!t)throw Error(`Framework context not found: ${e}`);t.isActive=!0,this.activeContext=e,await this.setupFrameworkEnvironment(e)}cleanupContext(e){let t=this.contexts.get(e);t&&(t.cleanup(),t.isActive=!1,t.imports.clear(),this.activeContext===e&&(this.activeContext=null))}async setupFrameworkEnvironment(e){switch(e){case`solid`:await this.ensureSolidEnvironment();break;case`vue`:await this.ensureVueEnvironment();break;case`svelte`:this.ensureSvelteEnvironment();break;default:break}}async importFrameworkModule(e,t){let n=this.contexts.get(t);if(!n)throw Error(`No context for framework: ${t}`);if(n.imports.has(e))return n.imports.get(e);if(this.config.enableStrictIsolation&&!this.isImportAllowed(e,t))throw Error(`Import not allowed in ${t} context: ${e}`);try{let i=await import(r(e));return n.imports.set(e,i),this.config.debugLogging&&console.log(`[SSR Isolation] Imported ${e} in ${t} context`),i}catch(n){throw Error(`Failed to import ${e} in ${t} context: ${n instanceof Error?n.message:String(n)}`)}}isImportAllowed(e,t){let n=this.detector.getFrameworkConfigs().get(t);return n&&[...n.ssrModules,...n.hydrationModules].some(t=>e.startsWith(t))?!0:this.config.allowedCrossFrameworkImports.some(t=>e.startsWith(t))}clearFrameworkGlobals(e){let t=globalThis;switch(e){case`solid`:typeof globalThis<`u`&&(delete t._$HY,delete t.Solid);break;case`vue`:typeof globalThis<`u`&&(delete t.__VUE__,delete t.Vue);break;case`svelte`:typeof globalThis<`u`&&delete t.__SVELTE__;break}}async ensureSolidEnvironment(){try{await this.importFrameworkModule(`solid-js/web`,`solid`)}catch(e){this.config.debugLogging&&console.warn(`[SSR Isolation] Failed to set up Solid environment:`,e)}}async ensureVueEnvironment(){try{await this.importFrameworkModule(`vue/server-renderer`,`vue`)}catch(e){this.config.debugLogging&&console.warn(`[SSR Isolation] Failed to set up Vue environment:`,e)}}ensureSvelteEnvironment(){try{this.config.debugLogging&&console.log(`[SSR Isolation] Svelte environment ready`)}catch(e){this.config.debugLogging&&console.warn(`[SSR Isolation] Failed to set up Svelte environment:`,e)}}async getComponentContent(e){try{let n=e;e.startsWith(`/`)&&(n=e.substring(1));let r=[n,`src/islands/${n.split(`/`).pop()}`,`islands/${n.split(`/`).pop()}`,`examples/${n.split(`/`).pop()}`];for(let e of r)try{return await t(e,`utf-8`)}catch{continue}throw Error(`Component file not found: ${e}`)}catch(e){throw Error(`Failed to read component content: ${e instanceof Error?e.message:String(e)}`)}}getActiveContext(){return this.activeContext}getContexts(){return new Map(this.contexts)}updateConfig(e){this.config={...this.config,...e}}resetAllContexts(){for(let[e]of this.contexts)this.cleanupContext(e);this.activeContext=null}async renderWithFallback(e,t){let n=[],r=[];try{let i={componentPath:`fallback-component`,component:e,framework:t},a=await this.renderWithIsolation(i);if(a.success)return a;n.push(...a.errors),r.push(...a.warnings)}catch(e){n.push(`Preferred framework (${t}) failed: ${e instanceof Error?e.message:String(e)}`)}for(let i of[`preact`,`unknown`])if(i!==t)try{let a={componentPath:`fallback-component`,component:e,framework:i},o=await this.renderWithIsolation(a);if(o.success)return r.push(`Fell back to ${i} rendering from ${t}`),{...o,warnings:[...r,...o.warnings]};n.push(...o.errors)}catch(e){n.push(`Fallback framework (${i}) failed: ${e instanceof Error?e.message:String(e)}`)}return{html:``,framework:t,success:!1,errors:n,warnings:r}}async validateFrameworkContext(e){if(!this.contexts.get(e))return!1;try{return await this.setupFrameworkEnvironment(e),!0}catch(t){return this.config.debugLogging&&console.warn(`[SSR Isolation] Framework context validation failed for ${e}:`,t),!1}}getErrorRecoveryStrategies(e){return{solid:[`Ensure solid-js and solid-js/web are installed`,`Check that Solid components use proper JSX import source: /** @jsxImportSource solid-js */`,`Verify Solid components export default function`],vue:[`Ensure vue and vue/server-renderer are installed`,`Check that Vue components have proper <template>, <script>, and <style> sections`,`Verify Vue components are properly compiled for SSR`],svelte:[`Ensure svelte is installed and components are compiled`,`Check that Svelte components export default class or function`,`Verify Svelte components have proper script and style sections`],preact:[`Ensure preact and preact-render-to-string are installed`,`Check that Preact components use proper JSX import source: /** @jsxImportSource preact */`,`Verify Preact components export default function`]}[e]||[`Check that the framework is properly installed`,`Verify component syntax is correct for the detected framework`,`Consider adding explicit framework detection hints`]}}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import{h as e}from"preact";import{render as t}from"preact-render-to-string";import{readFile as n}from"node:fs/promises";import{getUniversalCSSForHead as r}from"../islands/universal-css-collector.js";import{getUniversalHeadForInjection as i}from"../islands/universal-head-collector.js";import{analyzeComponentContent as a}from"../core/components/component-analyzer.js";import{IsolatedSSRRenderer as o}from"./isolated-ssr-renderer.js";function s(e){let t=e;if(!(e.includes(`data-framework=`)||e.includes(`data-src=`)))return e;if(!e.includes(`data-universal-ssr="true"`)){let n=r(!0);n&&e.includes(`</head>`)&&(t=t.replace(`</head>`,`${n}\n</head>`))}let n=i(!0);if(n&&e.includes(`</head>`)&&(t=t.replace(`</head>`,` ${n}\n</head>`)),e.includes(`/src/client/main.js`)||e.includes(`main.js`))return t;let a=`<script type="module" src="/src/client/main.js"><\/script>`;return t.includes(`</body>`)?t.replace(`</body>`,`${a}\n</body>`):t+a}const c={solid:[`solid-js`,`SolidIsland`,`createSignal`,`.solid.`,`data-solid-hydrate`],vue:[`data-vue-hydrate`,`.vue`,`Vue`],svelte:[`data-framework="svelte"`,`.svelte`,`s-`]};let l=null;function u(){return l||=new o({enableStrictIsolation:!0,allowedCrossFrameworkImports:[`preact`,`preact-render-to-string`],errorHandling:`fallback`,debugLogging:process.env.NODE_ENV!==`production`}),l}function d(e){return{solid:c.solid.some(t=>e.includes(t)),vue:c.vue.some(t=>e.includes(t)),svelte:c.svelte.some(t=>e.includes(t))}}function f(e,t,n){let r=[],i=/^import\s[^'"]*['"]([^'"]+)['"]/gm,a=[],o;for(;(o=i.exec(t))!==null;)a.push(o[1]);let s=n;e.includes(`.solid.`)?s=`solid`:e.includes(`.preact.`)&&(s=`preact`);let c=new Map([[`preact`,[`solid-js`,`solid-js/web`,`vue`,`svelte`]],[`solid`,[`preact`,`preact-render-to-string`,`vue`,`svelte`]],[`vue`,[`preact`,`solid-js`,`svelte`]],[`svelte`,[`preact`,`solid-js`,`vue`]]]).get(s)||[];for(let t of a)for(let n of c)t.startsWith(n)&&r.push(`Cross-framework import detected: ${s} component (${e}) importing ${t}`);return r}function p(e,t){return t.type===`ssr-only`?e.replaceAll(/data-hydrate="[^"]*"\s*/g,``).replace(`>`,` data-render-strategy="${t.type}" data-ssr-reason="${t.reason}">`):e.replace(`>`,` data-render-strategy="${t.type}" data-hydrate-reason="${t.reason}">`)}async function m(e,t={}){let n=/(<[^>]*data-hydrate="([^"]*)"[^>]*>)/g,r=e,i=Array.from(e.matchAll(n));for(let e of i){let[n,i,a]=e;try{if(n.includes(`data-render-strategy`))continue;let e=await g(a,t);await h(a,t),r=r.replace(n,p(n,e)),t.logDecisions===!0&&(console.log(`[SSR Strategy] ${a} -> ${e.type.toUpperCase()}: ${e.reason}`),e.warnings&&e.warnings.length>0&&!t.suppressWarnings&&e.warnings.forEach(e=>console.warn(`[SSR Warning] ${a}: ${e}`)))}catch(e){console.warn(`Failed to analyze component ${a}:`,e);let t=n.replace(`>`,` data-render-strategy="hydrate" data-error="analysis-failed">`);r=r.replace(n,t)}}return r}async function h(e,t={}){try{let r,i=e;e.startsWith(`/`)&&(i=e.substring(1));let a=[i,`examples/${i.split(`/`).pop()}`,`src/islands/${i.split(`/`).pop()}`,`islands/${i.split(`/`).pop()}`],o=``;for(let e of a)try{r=await n(e,`utf-8`),o=e;break}catch{continue}if(!o||!r)return;let s=d(r),c=`preact`;s.solid?c=`solid`:s.vue?c=`vue`:s.svelte&&(c=`svelte`);let l=f(o,r,c);l.length>0&&!t.suppressWarnings&&l.forEach(e=>console.warn(`[Import Validation] ${e}`))}catch(n){t.logDecisions!==!1&&console.warn(`Import validation failed for ${e}:`,n)}}async function g(e,t={}){if(t.forceSSROnly)return{type:`ssr-only`,reason:`Explicitly configured for SSR-only rendering`};if(e.includes(`NoHydrate`)||e.includes(`Static`)||e.includes(`SSROnly`))return{type:`ssr-only`,reason:`Component name explicitly indicates SSR-only rendering`};if(t.detectScripts===!1)return{type:`hydrate`,reason:`Script detection disabled, defaulting to hydration`};try{let r,i=e;e.startsWith(`/`)&&(i=e.substring(1));let o=[i,`examples/${i.split(`/`).pop()}`,`src/islands/${i.split(`/`).pop()}`,`islands/${i.split(`/`).pop()}`],s=null;for(let e of o)try{r=await n(e,`utf-8`);let i={forceSSROnly:t.forceSSROnly,detectScripts:t.detectScripts,suppressWarnings:t.suppressWarnings,logDecisions:!1};s=a(e,r,i);break}catch{continue}return s?{type:s.decision.shouldHydrate?`hydrate`:`ssr-only`,reason:s.decision.reason,warnings:s.decision.warnings}:_(e)}catch(t){return console.warn(`Component analysis failed for ${e}:`,t),{type:`ssr-only`,reason:`Analysis failed, defaulting to SSR-only for safety`,warnings:[`Component analysis error: ${t instanceof Error?t.message:String(t)}`]}}}function _(e){return e.endsWith(`.vue`)||e.endsWith(`.svelte`)||e.endsWith(`.tsx`)||e.endsWith(`.jsx`)?{type:`ssr-only`,reason:`Framework component detected, defaulting to SSR-only (hydration requires explicit hydrate function)`}:{type:`ssr-only`,reason:`Unknown component type, defaulting to SSR-only for safety`}}function v(e){return e.meta?.map(({name:e,content:t})=>`<meta name="${e}" content="${t}">`).join(`
|
|
2
|
+
`)||``}function y(e){return e.styles?.map(e=>`<link rel="stylesheet" href="${e}">`).join(`
|
|
3
|
+
`)||``}function b(e){return e.scripts?.map(e=>typeof e==`string`?`<script src="${e}" defer><\/script>`:`<script ${e.src?`src="${e.src}"`:``} ${e.type?`type="${e.type}"`:``}>${e.content||``}<\/script>`).join(`
|
|
4
|
+
`)||``}function x(e,t){return`
|
|
5
|
+
<script type="module" src="${e?`/src/client/main.js`:`/dist/client.js`}"><\/script>`}function S(e,t){return e&&t?`
|
|
6
|
+
<script type="module">
|
|
7
|
+
if (import.meta.hot) {
|
|
8
|
+
import.meta.hot.accept();
|
|
9
|
+
}
|
|
10
|
+
<\/script>`:``}function C(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`)}function w(e,t,n){let a=process.env.NODE_ENV!==`production`,o=v(e),s=y(e),c=b(e),l=x(a,t),u=S(a,n),d=r(!0),f=i(!0);return`
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="utf-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
14
|
+
${o}
|
|
15
|
+
<title>${C(String(e.title||`Avalon App`))}</title>
|
|
16
|
+
|
|
17
|
+
<script type="importmap">
|
|
18
|
+
{
|
|
19
|
+
"imports": {
|
|
20
|
+
"@useavalon/preact/client": "/packages/integrations/preact/client/index.ts",
|
|
21
|
+
"@useavalon/vue/client": "/packages/integrations/vue/client/index.ts",
|
|
22
|
+
"@useavalon/solid/client": "/packages/integrations/solid/client/index.ts",
|
|
23
|
+
"@useavalon/svelte/client": "/packages/integrations/svelte/client/index.ts",
|
|
24
|
+
"@useavalon/shared": "/packages/integrations/core/types.ts"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
<\/script>
|
|
28
|
+
${s}
|
|
29
|
+
${d}
|
|
30
|
+
${f}
|
|
31
|
+
${c}${l}${u}
|
|
32
|
+
</head>`.trim()}export async function renderToHtml(e,n={},r,i={}){try{let a,o;if(i.forceSSROnly===!0){let n=e.component();a=t(n instanceof Promise?await n:n),o=d(a)}else ({content:a,frameworks:o}=await D(e,i));return a=await m(a,i),`<!DOCTYPE html>\n<html lang="en">\n${w({...n,...e.options},o,r)}\n<body>\n${a}\n</body>\n</html>`}catch(e){throw console.error(`Error rendering component:`,e),Error(`Failed to render component`)}}export async function renderToHtmlWithLayouts(e,t,n,r,i={},a,o={}){try{let s=e,c={default:e.component,layoutConfig:s.layoutConfig,loader:s.loader,frontmatter:e.frontmatter},l=await t.resolveAndRender(r,c,n);return l.handlers.length===0?await renderToHtml(e,i,a,o):T(await m(await A(await k(e,r,o),l,c,n,r),o),e,i,a)}catch(t){console.error(`Error rendering component with layouts:`,t);try{return await renderToHtml(e,i,a,o)}catch(e){throw console.error(`Fallback rendering also failed:`,e),Error(`Failed to render component with layouts and fallback failed`)}}}function T(e,t,n,r){if(e.trim().startsWith(`<!DOCTYPE html>`)||e.trim().startsWith(`<html`))return s(e);let i=d(e);return s(`<!DOCTYPE html>\n<html lang="en">\n${w({...n,...t.options},i,r)}\n<body>\n${e}\n</body>\n</html>`)}async function E(e,n,r,i){let a,o;if(i.forceSSROnly===!0){let n=e.component();a=t(n instanceof Promise?await n:n),o=d(a)}else ({content:a,frameworks:o}=await D(e,i));return a=await m(a,i),{head:w({...n,...e.options},o,r),content:a}}async function D(e,n){try{let t=await u().renderWithIsolation({componentPath:`route-component`,component:e.component});if(!t.success)throw Error(`Isolated rendering failed: ${t.errors.join(`, `)}`);return t.warnings.length>0&&!n.suppressWarnings&&t.warnings.forEach(e=>console.warn(`[SSR Isolation] ${e}`)),{content:t.html,frameworks:d(t.html)}}catch(n){console.warn(`[SSR] Isolated rendering failed, falling back to standard rendering:`,n);let r=e.component(),i=t(r instanceof Promise?await r:r);return{content:i,frameworks:d(i)}}}function O(e,t,n,r,i,a=`Streaming Error`,o=`route-component`){if(console.error(`[${a}]`,{message:e.message,stack:e.stack,shellSent:t,timestamp:new Date().toISOString()}),i.onError?.(e),t){console.log(`[${a}] Mid-stream error detected, injecting error boundary`);try{n.enqueue(r.encode(M(e,o))),n.enqueue(r.encode(`
|
|
33
|
+
</body>
|
|
34
|
+
</html>`))}catch(e){console.error(`[${a}] Failed to inject error boundary:`,e)}}else i.onShellError?.(e),n.enqueue(r.encode(j(e)));n.close()}export async function renderToHtmlStream(e,t={},n,r={}){let i=new TextEncoder,a=null,o=!1;return new ReadableStream({async start(s){a=s;try{let{head:s,content:c}=await E(e,t,n,r);a.enqueue(i.encode(`<!DOCTYPE html>\n<html lang="en">\n${s}\n<body>\n`)),o=!0,r.onShellReady?.(),a.enqueue(i.encode(c)),a.enqueue(i.encode(`
|
|
35
|
+
</body>
|
|
36
|
+
</html>`)),r.onAllReady?.(),a.close()}catch(e){O(e instanceof Error?e:Error(String(e)),o,a,i,r)}},cancel(){try{a?.close()}catch{}}})}export async function renderToHtmlStreamWithLayouts(e,t,n,r,i={},a,o={}){let c=new TextEncoder,l=null,u=!1;return new ReadableStream({async start(f){l=f;try{let f=e,p={default:e.component,layoutConfig:f.layoutConfig,loader:f.loader,frontmatter:e.frontmatter},h=await t.resolveAndRender(r,p,n);if(h.handlers.length===0){let t=(await renderToHtmlStream(e,i,a,o)).getReader();try{for(;;){let{done:e,value:n}=await t.read();if(e)break;l.enqueue(n)}}finally{t.releaseLock()}l.close();return}let g=await m(await A(await k(e,r,o),h,p,n,r),o);if(g.trim().startsWith(`<!DOCTYPE html>`)||g.trim().startsWith(`<html`)){let e=s(g);l.enqueue(c.encode(e)),u=!0,o.onShellReady?.(),o.onAllReady?.(),l.close();return}let _=d(g),v=w({...i,...e.options},_,a);l.enqueue(c.encode(`<!DOCTYPE html>\n<html lang="en">\n${v}\n<body>\n`)),u=!0,o.onShellReady?.(),l.enqueue(c.encode(g)),l.enqueue(c.encode(`
|
|
37
|
+
</body>
|
|
38
|
+
</html>`)),o.onAllReady?.(),l.close()}catch(e){O(e instanceof Error?e:Error(String(e)),u,l,c,o,`Streaming Error with Layouts`,`layout-${r}`)}},cancel(){try{l?.close()}catch{}}})}async function k(e,n,r){if(r.forceSSROnly===!0){let n=e.component();return t(n instanceof Promise?await n:n)}try{let t=await u().renderWithIsolation({componentPath:n,component:e.component});if(!t.success)throw Error(`Isolated rendering failed: ${t.errors.join(`, `)}`);return t.warnings.length>0&&!r.suppressWarnings&&t.warnings.forEach(e=>console.warn(`[SSR Isolation] ${e}`)),t.html}catch(n){console.warn(`[SSR] Isolated page rendering failed, falling back to standard rendering:`,n);let r=e.component();return t(r instanceof Promise?await r:r)}}async function A(n,r,i,a,o){let s=e(`avalon-page-content`,{dangerouslySetInnerHTML:{__html:n}}),c=null;for(let n=r.handlers.length-1;n>=0;n--){let l=r.handlers[n],u={data:r.dataLoaders[n]?await r.dataLoaders[n](a):{},frontmatter:i.frontmatter||{},route:{path:o,params:a.params,query:a.query}},d=l.component,f=d({...u,children:s});if(f instanceof Promise){let r=t(await f);n===0?c=r:s=e(`avalon-layout-fragment`,{dangerouslySetInnerHTML:{__html:r}})}else s=e(d,u,s)}if(c!==null)return c;try{let e=await u().renderWithIsolation({componentPath:`layout-chain-${o}`,component:()=>s});if(e.success)return e.html}catch{}return t(s)}function j(e){let t=process.env.NODE_ENV!==`production`;return`<!DOCTYPE html>
|
|
39
|
+
<html lang="en">
|
|
40
|
+
<head>
|
|
41
|
+
<meta charset="utf-8">
|
|
42
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
43
|
+
<title>Error</title>
|
|
44
|
+
<style>
|
|
45
|
+
body {
|
|
46
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
47
|
+
margin: 0;
|
|
48
|
+
padding: 40px;
|
|
49
|
+
background: #f5f5f5;
|
|
50
|
+
}
|
|
51
|
+
.error-container {
|
|
52
|
+
max-width: 600px;
|
|
53
|
+
margin: 0 auto;
|
|
54
|
+
background: white;
|
|
55
|
+
padding: 40px;
|
|
56
|
+
border-radius: 8px;
|
|
57
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
58
|
+
}
|
|
59
|
+
h1 {
|
|
60
|
+
color: #d32f2f;
|
|
61
|
+
margin-top: 0;
|
|
62
|
+
}
|
|
63
|
+
pre {
|
|
64
|
+
background: #f5f5f5;
|
|
65
|
+
padding: 16px;
|
|
66
|
+
border-radius: 4px;
|
|
67
|
+
overflow-x: auto;
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
70
|
+
</head>
|
|
71
|
+
<body>
|
|
72
|
+
<div class="error-container">
|
|
73
|
+
<h1>Server Error</h1>
|
|
74
|
+
<p>An error occurred while rendering the page:</p>
|
|
75
|
+
<pre>${e.message}</pre>
|
|
76
|
+
${t&&e.stack?`<pre>${e.stack}</pre>`:``}
|
|
77
|
+
</div>
|
|
78
|
+
</body>
|
|
79
|
+
</html>`}function M(e,t){let n=process.env.NODE_ENV!==`production`,r=t?`<p><strong>Component ID:</strong> ${t}</p>`:``,i=e.stack?`<pre style="background:#f5f5f5;padding:10px;border-radius:4px;overflow-x:auto;font-size:12px;margin-top:10px">${e.stack}</pre>`:``,a=n?`<details style="margin-top:15px"><summary style="cursor:pointer;color:#856404;font-weight:bold">Error Details (Development Mode)</summary><div style="margin-top:10px">${r}<p><strong>Error:</strong> ${e.message}</p>${i}</div></details>`:``;return`
|
|
80
|
+
<div class="streaming-error-boundary" data-error-boundary="true"${t?` data-component-id="${t}"`:``}>
|
|
81
|
+
<div class="error-boundary-container" style="background:#fff3cd;border:2px solid #ffc107;border-radius:8px;padding:20px;margin:20px 0;font-family:system-ui,-apple-system,sans-serif">
|
|
82
|
+
<div class="error-boundary-header" style="display:flex;align-items:center;gap:10px;margin-bottom:10px">
|
|
83
|
+
<span style="font-size:24px">⚠️</span>
|
|
84
|
+
<h3 style="margin:0;color:#856404">Component Error</h3>
|
|
85
|
+
</div>
|
|
86
|
+
<p style="margin:10px 0;color:#856404">An error occurred while rendering this component. The rest of the page should work normally.</p>
|
|
87
|
+
${a}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
`}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as e}from"zod";export const ApiMethodSchema=e.enum([`GET`,`POST`,`PUT`,`DELETE`,`PATCH`,`HEAD`,`OPTIONS`]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as e}from"zod";export const MetaTagSchema=e.object({name:e.string().min(1),content:e.string()});export const ScriptConfigSchema=e.union([e.string().min(1),e.object({src:e.string().min(1).optional(),content:e.string().optional(),data:e.union([e.record(e.string(),e.unknown()),e.array(e.unknown()),e.string()]).optional(),type:e.string().optional(),async:e.boolean().optional(),defer:e.boolean().optional(),crossorigin:e.enum([`anonymous`,`use-credentials`]).optional(),integrity:e.string().optional(),nomodule:e.boolean().optional(),referrerpolicy:e.enum([`no-referrer`,`no-referrer-when-downgrade`,`origin`,`origin-when-cross-origin`,`same-origin`,`strict-origin`,`strict-origin-when-cross-origin`,`unsafe-url`]).optional(),attributes:e.record(e.string(),e.string()).optional()}).refine(e=>e.src||e.content||e.data,{message:`Script must have either 'src', 'content', or 'data'`})]);export const RenderOptionsSchema=e.object({title:e.string().optional(),scripts:e.array(ScriptConfigSchema).optional(),styles:e.array(e.string().min(1)).optional(),meta:e.array(MetaTagSchema).optional()});
|