@useavalon/avalon 0.1.23 → 0.1.24
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.d.ts +50 -0
- package/dist/src/build/integration-bundler-plugin.d.ts +25 -0
- package/dist/src/build/integration-config.d.ts +44 -0
- package/dist/src/build/integration-detection-plugin.d.ts +20 -0
- package/dist/src/build/integration-resolver-plugin.d.ts +10 -0
- package/dist/src/build/island-manifest.d.ts +57 -0
- package/dist/src/build/island-types-generator.d.ts +49 -0
- package/dist/src/build/mdx-island-transform.d.ts +23 -0
- package/dist/src/build/mdx-plugin.d.ts +36 -0
- package/dist/src/build/page-island-transform.d.ts +41 -0
- package/dist/src/build/prop-extractors/index.d.ts +8 -0
- package/dist/src/build/prop-extractors/lit.d.ts +11 -0
- package/dist/src/build/prop-extractors/qwik.d.ts +9 -0
- package/dist/src/build/prop-extractors/solid.d.ts +12 -0
- package/dist/src/build/prop-extractors/svelte.d.ts +13 -0
- package/dist/src/build/prop-extractors/vue.d.ts +19 -0
- package/dist/src/build/sidecar-file-manager.d.ts +23 -0
- package/dist/src/build/sidecar-renderer.d.ts +22 -0
- package/dist/src/client/adapters/index.d.ts +15 -0
- package/dist/src/client/components.d.ts +21 -0
- package/dist/src/client/css-hmr-handler.d.ts +94 -0
- package/dist/src/client/framework-adapter.d.ts +225 -0
- package/dist/src/client/hmr-coordinator.d.ts +88 -0
- package/dist/src/components/Image.d.ts +61 -0
- package/dist/src/components/IslandErrorBoundary.d.ts +37 -0
- package/dist/src/components/IslandErrorBoundary.js +1 -1
- package/dist/src/components/LayoutDataErrorBoundary.d.ts +34 -0
- package/dist/src/components/LayoutDataErrorBoundary.js +1 -1
- package/dist/src/components/LayoutErrorBoundary.d.ts +25 -0
- package/dist/src/components/LayoutErrorBoundary.js +1 -1
- package/dist/src/components/PersistentIsland.d.ts +36 -0
- package/dist/src/components/StreamingErrorBoundary.d.ts +42 -0
- package/dist/src/components/StreamingErrorBoundary.js +1 -1
- package/dist/src/components/StreamingLayout.d.ts +83 -0
- package/dist/src/components/StreamingLayout.js +1 -1
- package/dist/src/core/components/component-analyzer.d.ts +48 -0
- package/dist/src/core/components/component-detection.d.ts +72 -0
- package/dist/src/core/components/enhanced-framework-detector.d.ts +78 -0
- package/dist/src/core/components/framework-registry.d.ts +114 -0
- package/dist/src/core/content/mdx-processor.d.ts +14 -0
- package/dist/src/core/integrations/index.d.ts +6 -0
- package/dist/src/core/integrations/loader.d.ts +35 -0
- package/dist/src/core/integrations/registry.d.ts +51 -0
- package/dist/src/core/islands/island-persistence.d.ts +74 -0
- package/dist/src/core/islands/island-state-serializer.d.ts +53 -0
- package/dist/src/core/islands/persistent-island-context.d.ts +36 -0
- package/dist/src/core/islands/use-persistent-state.d.ts +17 -0
- package/dist/src/core/layout/enhanced-layout-resolver.d.ts +73 -0
- package/dist/src/core/layout/layout-cache-manager.d.ts +66 -0
- package/dist/src/core/layout/layout-composer.d.ts +63 -0
- package/dist/src/core/layout/layout-data-loader.d.ts +146 -0
- package/dist/src/core/layout/layout-discovery.d.ts +51 -0
- package/dist/src/core/layout/layout-matcher.d.ts +77 -0
- package/dist/src/core/layout/layout-types.d.ts +94 -0
- package/dist/src/core/modules/framework-module-resolver.d.ts +85 -0
- package/dist/src/islands/component-analysis.d.ts +38 -0
- package/dist/src/islands/css-utils.d.ts +81 -0
- package/dist/src/islands/discovery/index.d.ts +16 -0
- package/dist/src/islands/discovery/registry.d.ts +141 -0
- package/dist/src/islands/discovery/resolver.d.ts +190 -0
- package/dist/src/islands/discovery/scanner.d.ts +55 -0
- package/dist/src/islands/discovery/types.d.ts +92 -0
- package/dist/src/islands/discovery/validator.d.ts +89 -0
- package/dist/src/islands/discovery/watcher.d.ts +95 -0
- package/dist/src/islands/framework-detection.d.ts +53 -0
- package/dist/src/islands/integration-loader.d.ts +139 -0
- package/dist/src/islands/island.d.ts +55 -0
- package/dist/src/islands/render-cache.d.ts +203 -0
- package/dist/src/islands/types.d.ts +63 -0
- package/dist/src/islands/universal-css-collector.d.ts +41 -0
- package/dist/src/islands/universal-head-collector.d.ts +42 -0
- package/dist/src/layout-system.d.ts +92 -592
- package/dist/src/middleware/discovery.d.ts +70 -0
- package/dist/src/middleware/executor.d.ts +52 -0
- package/dist/src/middleware/index.d.ts +43 -0
- package/dist/src/middleware/types.d.ts +89 -0
- package/dist/src/nitro/build-config.d.ts +163 -0
- package/dist/src/nitro/config.d.ts +268 -0
- package/dist/src/nitro/error-handler.d.ts +151 -0
- package/dist/src/nitro/index.d.ts +15 -0
- package/dist/src/nitro/island-manifest.d.ts +191 -0
- package/dist/src/nitro/middleware-adapter.d.ts +151 -0
- package/dist/src/nitro/renderer.d.ts +342 -0
- package/dist/src/nitro/route-discovery.d.ts +142 -0
- package/dist/src/nitro/types.d.ts +278 -0
- package/dist/src/render/collect-css.d.ts +28 -0
- package/dist/src/render/error-pages.d.ts +14 -0
- package/dist/src/render/isolated-ssr-renderer.d.ts +127 -0
- package/dist/src/render/ssr.d.ts +56 -0
- package/dist/src/schemas/api.d.ts +27 -0
- package/dist/src/schemas/core.d.ts +75 -0
- package/dist/src/schemas/index.d.ts +79 -0
- package/dist/src/schemas/index.js +1 -1
- package/dist/src/schemas/layout.d.ts +282 -0
- package/dist/src/schemas/routing/index.d.ts +181 -0
- package/dist/src/schemas/routing.d.ts +388 -0
- package/dist/src/types/as-island.d.ts +17 -0
- package/dist/src/types/layout.d.ts +177 -0
- package/dist/src/types/routing.d.ts +297 -0
- package/dist/src/types/types.d.ts +6 -0
- package/dist/src/utils/dev-logger.d.ts +84 -0
- package/dist/src/utils/fs.d.ts +41 -0
- package/dist/src/vite-plugin/auto-discover.d.ts +72 -0
- package/dist/src/vite-plugin/config.d.ts +82 -0
- package/dist/src/vite-plugin/errors.d.ts +62 -0
- package/dist/src/vite-plugin/image-optimization.d.ts +36 -0
- package/dist/src/vite-plugin/integration-activator.d.ts +48 -0
- package/dist/src/vite-plugin/island-sidecar-plugin.d.ts +17 -0
- package/dist/src/vite-plugin/module-discovery.d.ts +66 -0
- package/dist/src/vite-plugin/nitro-integration.d.ts +56 -0
- package/dist/src/vite-plugin/plugin.d.ts +51 -0
- package/dist/src/vite-plugin/types.d.ts +281 -0
- package/dist/src/vite-plugin/validation.d.ts +93 -0
- package/package.json +33 -9
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework HMR Adapter Interface
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for framework-specific HMR adapters.
|
|
5
|
+
* Each supported framework (React, Preact, Vue, Svelte, Solid, Lit) implements this interface
|
|
6
|
+
* to provide framework-specific hot module replacement behavior.
|
|
7
|
+
*
|
|
8
|
+
* Requirements: 2.1-2.7
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* State snapshot for preserving component state across HMR updates
|
|
12
|
+
*/
|
|
13
|
+
export interface StateSnapshot {
|
|
14
|
+
/**
|
|
15
|
+
* Framework name (e.g., 'react', 'vue', 'svelte')
|
|
16
|
+
*/
|
|
17
|
+
framework: string;
|
|
18
|
+
/**
|
|
19
|
+
* Timestamp when state was captured
|
|
20
|
+
*/
|
|
21
|
+
timestamp: number;
|
|
22
|
+
/**
|
|
23
|
+
* Framework-specific state data
|
|
24
|
+
* - React: hooks state, context values
|
|
25
|
+
* - Vue: reactive data, computed properties
|
|
26
|
+
* - Svelte: component state, store subscriptions
|
|
27
|
+
* - Solid: signal values, reactive computations
|
|
28
|
+
* - Lit: element properties, attributes
|
|
29
|
+
*/
|
|
30
|
+
data: Record<string, unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* DOM state (scroll, focus, form values)
|
|
33
|
+
*/
|
|
34
|
+
dom?: {
|
|
35
|
+
scrollPosition?: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
};
|
|
39
|
+
focusedElement?: string;
|
|
40
|
+
formValues?: Record<string, unknown>;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Framework-specific HMR adapter interface
|
|
45
|
+
*
|
|
46
|
+
* Each framework adapter implements this interface to provide:
|
|
47
|
+
* - Component identification (canHandle)
|
|
48
|
+
* - State preservation (preserveState, restoreState)
|
|
49
|
+
* - Hot updates (update)
|
|
50
|
+
* - Error handling (handleError)
|
|
51
|
+
*/
|
|
52
|
+
export interface FrameworkHMRAdapter {
|
|
53
|
+
/**
|
|
54
|
+
* Framework name (e.g., 'react', 'preact', 'vue', 'svelte', 'solid', 'lit')
|
|
55
|
+
*/
|
|
56
|
+
readonly name: string;
|
|
57
|
+
/**
|
|
58
|
+
* Check if this adapter can handle HMR for a given component
|
|
59
|
+
*
|
|
60
|
+
* @param component - The component to check
|
|
61
|
+
* @returns true if this adapter can handle the component
|
|
62
|
+
*
|
|
63
|
+
* Example:
|
|
64
|
+
* - React: Check for React.Component or function with hooks
|
|
65
|
+
* - Vue: Check for Vue component options object
|
|
66
|
+
* - Svelte: Check for Svelte component class
|
|
67
|
+
*/
|
|
68
|
+
canHandle(component: unknown): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Preserve component state before HMR update
|
|
71
|
+
*
|
|
72
|
+
* Captures the current state of the component so it can be restored after update.
|
|
73
|
+
* Returns null if state preservation is not supported or fails.
|
|
74
|
+
*
|
|
75
|
+
* @param island - The island DOM element containing the component
|
|
76
|
+
* @returns State snapshot or null if preservation fails
|
|
77
|
+
*
|
|
78
|
+
* Requirements: 1.3, 4.1-4.5
|
|
79
|
+
*/
|
|
80
|
+
preserveState(island: HTMLElement): StateSnapshot | null;
|
|
81
|
+
/**
|
|
82
|
+
* Update the component with a new module
|
|
83
|
+
*
|
|
84
|
+
* Performs the actual hot module replacement:
|
|
85
|
+
* - Unmounts old component (if needed)
|
|
86
|
+
* - Mounts new component with same props
|
|
87
|
+
* - Integrates with framework-specific HMR APIs
|
|
88
|
+
*
|
|
89
|
+
* @param island - The island DOM element
|
|
90
|
+
* @param newComponent - The new component class/function
|
|
91
|
+
* @param props - Component props
|
|
92
|
+
*
|
|
93
|
+
* Requirements: 2.1-2.6
|
|
94
|
+
*/
|
|
95
|
+
update(island: HTMLElement, newComponent: unknown, props: Record<string, unknown>): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Restore component state after HMR update
|
|
98
|
+
*
|
|
99
|
+
* Applies the previously captured state to the updated component.
|
|
100
|
+
* Should handle cases where state structure has changed.
|
|
101
|
+
*
|
|
102
|
+
* @param island - The island DOM element
|
|
103
|
+
* @param state - Previously captured state snapshot
|
|
104
|
+
*
|
|
105
|
+
* Requirements: 1.3, 4.1-4.5
|
|
106
|
+
*/
|
|
107
|
+
restoreState(island: HTMLElement, state: StateSnapshot): void;
|
|
108
|
+
/**
|
|
109
|
+
* Handle errors during HMR update
|
|
110
|
+
*
|
|
111
|
+
* Provides framework-specific error handling:
|
|
112
|
+
* - Display error overlay
|
|
113
|
+
* - Preserve SSR HTML as fallback
|
|
114
|
+
* - Log diagnostic information
|
|
115
|
+
*
|
|
116
|
+
* @param island - The island DOM element
|
|
117
|
+
* @param error - The error that occurred
|
|
118
|
+
*
|
|
119
|
+
* Requirements: 1.4, 7.1-7.5
|
|
120
|
+
*/
|
|
121
|
+
handleError(island: HTMLElement, error: Error): void;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Adapter registry for managing framework-specific HMR adapters
|
|
125
|
+
*/
|
|
126
|
+
export declare class AdapterRegistry {
|
|
127
|
+
private adapters;
|
|
128
|
+
/**
|
|
129
|
+
* Register a framework-specific HMR adapter
|
|
130
|
+
*
|
|
131
|
+
* @param framework - Framework name (case-insensitive)
|
|
132
|
+
* @param adapter - The adapter implementation
|
|
133
|
+
* @throws Error if adapter is invalid or already registered
|
|
134
|
+
*
|
|
135
|
+
* Requirements: 2.1-2.7
|
|
136
|
+
*/
|
|
137
|
+
register(framework: string, adapter: FrameworkHMRAdapter): void;
|
|
138
|
+
/**
|
|
139
|
+
* Get an adapter for a specific framework
|
|
140
|
+
*
|
|
141
|
+
* @param framework - Framework name (case-insensitive)
|
|
142
|
+
* @returns The adapter or undefined if not found
|
|
143
|
+
*/
|
|
144
|
+
get(framework: string): FrameworkHMRAdapter | undefined;
|
|
145
|
+
/**
|
|
146
|
+
* Check if an adapter is registered for a framework
|
|
147
|
+
*
|
|
148
|
+
* @param framework - Framework name (case-insensitive)
|
|
149
|
+
* @returns true if adapter is registered
|
|
150
|
+
*/
|
|
151
|
+
has(framework: string): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Get all registered framework names
|
|
154
|
+
*
|
|
155
|
+
* @returns Array of registered framework names
|
|
156
|
+
*/
|
|
157
|
+
getRegisteredFrameworks(): string[];
|
|
158
|
+
/**
|
|
159
|
+
* Find an adapter that can handle a specific component
|
|
160
|
+
*
|
|
161
|
+
* Iterates through all registered adapters and returns the first one
|
|
162
|
+
* that can handle the component.
|
|
163
|
+
*
|
|
164
|
+
* @param component - The component to check
|
|
165
|
+
* @returns The adapter that can handle the component, or undefined
|
|
166
|
+
*/
|
|
167
|
+
findAdapter(component: unknown): FrameworkHMRAdapter | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* Unregister an adapter
|
|
170
|
+
*
|
|
171
|
+
* @param framework - Framework name (case-insensitive)
|
|
172
|
+
* @returns true if adapter was removed, false if not found
|
|
173
|
+
*/
|
|
174
|
+
unregister(framework: string): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Clear all registered adapters
|
|
177
|
+
*/
|
|
178
|
+
clear(): void;
|
|
179
|
+
/**
|
|
180
|
+
* Get the number of registered adapters
|
|
181
|
+
*/
|
|
182
|
+
get size(): number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Base adapter class with common functionality
|
|
186
|
+
*
|
|
187
|
+
* Framework-specific adapters can extend this class to inherit common behavior
|
|
188
|
+
* and only override framework-specific methods.
|
|
189
|
+
*/
|
|
190
|
+
export declare abstract class BaseFrameworkAdapter implements FrameworkHMRAdapter {
|
|
191
|
+
abstract readonly name: string;
|
|
192
|
+
abstract canHandle(component: unknown): boolean;
|
|
193
|
+
abstract update(island: HTMLElement, newComponent: unknown, props: Record<string, unknown>): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Default state preservation implementation
|
|
196
|
+
* Captures DOM state (scroll, focus, form values)
|
|
197
|
+
*
|
|
198
|
+
* Subclasses should override to add framework-specific state
|
|
199
|
+
*/
|
|
200
|
+
preserveState(island: HTMLElement): StateSnapshot | null;
|
|
201
|
+
/**
|
|
202
|
+
* Default state restoration implementation
|
|
203
|
+
* Restores DOM state (scroll, focus, form values)
|
|
204
|
+
*
|
|
205
|
+
* Subclasses should override to add framework-specific state restoration
|
|
206
|
+
*/
|
|
207
|
+
restoreState(island: HTMLElement, state: StateSnapshot): void;
|
|
208
|
+
/**
|
|
209
|
+
* Default error handling implementation
|
|
210
|
+
* Shows error indicator and preserves SSR HTML
|
|
211
|
+
*/
|
|
212
|
+
handleError(island: HTMLElement, error: Error): void;
|
|
213
|
+
/**
|
|
214
|
+
* Capture DOM state (scroll, focus, form values)
|
|
215
|
+
*/
|
|
216
|
+
protected captureDOMState(island: HTMLElement): StateSnapshot['dom'];
|
|
217
|
+
/**
|
|
218
|
+
* Restore DOM state (scroll, focus, form values)
|
|
219
|
+
*/
|
|
220
|
+
protected restoreDOMState(island: HTMLElement, dom: StateSnapshot['dom']): void;
|
|
221
|
+
/**
|
|
222
|
+
* Get a CSS selector for an element
|
|
223
|
+
*/
|
|
224
|
+
protected getElementSelector(element: HTMLElement): string | null;
|
|
225
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMR Coordinator
|
|
3
|
+
*
|
|
4
|
+
* Central orchestrator for all HMR operations in Avalon.
|
|
5
|
+
* Integrates with Vite's HMR API and coordinates island updates across frameworks.
|
|
6
|
+
*/
|
|
7
|
+
import { type FrameworkHMRAdapter, AdapterRegistry } from './framework-adapter.ts';
|
|
8
|
+
/**
|
|
9
|
+
* Vite HMR types (defined locally to avoid import issues)
|
|
10
|
+
*/
|
|
11
|
+
export interface HMRPayload {
|
|
12
|
+
type: string;
|
|
13
|
+
updates?: Update[];
|
|
14
|
+
timestamp?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ErrorPayload {
|
|
17
|
+
type: 'error';
|
|
18
|
+
err: {
|
|
19
|
+
message: string;
|
|
20
|
+
stack: string;
|
|
21
|
+
id?: string;
|
|
22
|
+
frame?: string;
|
|
23
|
+
plugin?: string;
|
|
24
|
+
pluginCode?: string;
|
|
25
|
+
loc?: {
|
|
26
|
+
file?: string;
|
|
27
|
+
line: number;
|
|
28
|
+
column: number;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface Update {
|
|
33
|
+
type: 'js-update' | 'css-update';
|
|
34
|
+
path: string;
|
|
35
|
+
acceptedPath: string;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
explicitImportRequired?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* HMR update payload from Vite
|
|
41
|
+
*/
|
|
42
|
+
export interface HMRUpdatePayload extends HMRPayload {
|
|
43
|
+
type: 'update' | 'full-reload' | 'prune' | 'error';
|
|
44
|
+
updates?: ModuleUpdate[];
|
|
45
|
+
timestamp?: number;
|
|
46
|
+
err?: ErrorPayload;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Individual module update information
|
|
50
|
+
*/
|
|
51
|
+
export interface ModuleUpdate {
|
|
52
|
+
type: 'js-update' | 'css-update';
|
|
53
|
+
path: string;
|
|
54
|
+
acceptedPath: string;
|
|
55
|
+
timestamp: number;
|
|
56
|
+
}
|
|
57
|
+
export type { FrameworkHMRAdapter, StateSnapshot } from './framework-adapter.ts';
|
|
58
|
+
/**
|
|
59
|
+
* HMR Coordinator class
|
|
60
|
+
* Manages HMR lifecycle and coordinates updates across islands
|
|
61
|
+
*/
|
|
62
|
+
export declare class HMRCoordinator {
|
|
63
|
+
private readonly registry;
|
|
64
|
+
private readonly stateSnapshots;
|
|
65
|
+
private readonly updateQueue;
|
|
66
|
+
private isProcessing;
|
|
67
|
+
/**
|
|
68
|
+
* Initialize the HMR coordinator
|
|
69
|
+
* Sets up Vite HMR listeners and accepts updates
|
|
70
|
+
*/
|
|
71
|
+
initialize(): void;
|
|
72
|
+
registerAdapter(framework: string, adapter: FrameworkHMRAdapter): void;
|
|
73
|
+
getRegistry(): AdapterRegistry;
|
|
74
|
+
handleUpdate(payload: HMRUpdatePayload): Promise<void>;
|
|
75
|
+
private processCSSUpdates;
|
|
76
|
+
private queueJSUpdates;
|
|
77
|
+
private processUpdateQueue;
|
|
78
|
+
findAffectedIslands(modulePath: string): HTMLElement[];
|
|
79
|
+
updateIsland(island: HTMLElement): Promise<void>;
|
|
80
|
+
private resolveComponent;
|
|
81
|
+
private handleBeforeFullReload;
|
|
82
|
+
private handleError;
|
|
83
|
+
private normalizePath;
|
|
84
|
+
private isIslandModule;
|
|
85
|
+
private getIslandId;
|
|
86
|
+
}
|
|
87
|
+
export declare function getHMRCoordinator(): HMRCoordinator;
|
|
88
|
+
export declare function initializeHMR(): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Component for Avalon
|
|
3
|
+
*
|
|
4
|
+
* A responsive image component that works with vite-imagetools to provide
|
|
5
|
+
* optimized images with automatic srcset generation.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { Image } from '@useavalon/avalon/client';
|
|
10
|
+
* import heroSrc from './hero.jpg?w=400;800;1200&format=webp&as=srcset';
|
|
11
|
+
*
|
|
12
|
+
* <Image
|
|
13
|
+
* src={heroSrc}
|
|
14
|
+
* alt="Hero image"
|
|
15
|
+
* sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
|
|
16
|
+
* />
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Or with the simpler single-image approach:
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import heroSrc from './hero.jpg?w=800&format=webp';
|
|
22
|
+
*
|
|
23
|
+
* <Image src={heroSrc} alt="Hero image" width={800} height={600} />
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import type { JSX } from "preact";
|
|
27
|
+
export interface ImageProps {
|
|
28
|
+
/**
|
|
29
|
+
* Image source - can be:
|
|
30
|
+
* - A string URL (single image)
|
|
31
|
+
* - A srcset string from ?as=srcset (contains " Xw" width descriptors)
|
|
32
|
+
* - An object with src/srcset/width/height from vite-imagetools
|
|
33
|
+
*/
|
|
34
|
+
src: string | {
|
|
35
|
+
src: string;
|
|
36
|
+
srcset?: string;
|
|
37
|
+
width?: number;
|
|
38
|
+
height?: number;
|
|
39
|
+
};
|
|
40
|
+
/** Alt text for accessibility (required) */
|
|
41
|
+
alt: string;
|
|
42
|
+
/** Sizes attribute for responsive images (required when using srcset) */
|
|
43
|
+
sizes?: string;
|
|
44
|
+
/** Loading strategy */
|
|
45
|
+
loading?: "lazy" | "eager";
|
|
46
|
+
/** Decoding hint */
|
|
47
|
+
decoding?: "async" | "sync" | "auto";
|
|
48
|
+
/** Optional width (auto-detected from srcset if available) */
|
|
49
|
+
width?: number | string;
|
|
50
|
+
/** Optional height (auto-detected from srcset if available) */
|
|
51
|
+
height?: number | string;
|
|
52
|
+
/** CSS class name */
|
|
53
|
+
className?: string;
|
|
54
|
+
/** Inline styles */
|
|
55
|
+
style?: string | Record<string, string | number>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Responsive image component with built-in optimization support
|
|
59
|
+
*/
|
|
60
|
+
export declare function Image({ src, alt, sizes, loading, decoding, width, height, className, style, }: Readonly<ImageProps>): JSX.Element;
|
|
61
|
+
export default Image;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Component, ComponentChildren, ComponentType } from 'preact';
|
|
2
|
+
import type { LayoutErrorInfo } from '../types/layout.ts';
|
|
3
|
+
export interface IslandErrorBoundaryProps {
|
|
4
|
+
children: ComponentChildren;
|
|
5
|
+
islandId: string;
|
|
6
|
+
onError?: (error: Error, errorInfo: LayoutErrorInfo) => void;
|
|
7
|
+
fallback?: (error: Error, islandId: string) => ComponentChildren;
|
|
8
|
+
isolateError?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface IslandErrorBoundaryState {
|
|
11
|
+
hasError: boolean;
|
|
12
|
+
error: Error | null;
|
|
13
|
+
errorInfo: LayoutErrorInfo | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Specialized error boundary for island components
|
|
17
|
+
* Provides error isolation to prevent island errors from affecting the main layout
|
|
18
|
+
*/
|
|
19
|
+
export declare class IslandErrorBoundary extends Component<IslandErrorBoundaryProps, IslandErrorBoundaryState> {
|
|
20
|
+
constructor(props: IslandErrorBoundaryProps);
|
|
21
|
+
static getDerivedStateFromError(error: Error): Partial<IslandErrorBoundaryState>;
|
|
22
|
+
componentDidCatch(error: Error, errorInfo: {
|
|
23
|
+
componentStack?: string;
|
|
24
|
+
}): void;
|
|
25
|
+
private handleRemoveIsland;
|
|
26
|
+
private handleReloadIsland;
|
|
27
|
+
private renderFallback;
|
|
28
|
+
render(): ComponentChildren;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Higher-order component to wrap islands with error boundaries
|
|
32
|
+
*/
|
|
33
|
+
export declare function withIslandErrorBoundary<P extends object>(WrappedComponent: ComponentType<P>, islandId: string, options?: {
|
|
34
|
+
fallback?: (error: Error, islandId: string) => ComponentChildren;
|
|
35
|
+
isolateError?: boolean;
|
|
36
|
+
onError?: (error: Error, errorInfo: LayoutErrorInfo) => void;
|
|
37
|
+
}): (props: P) => import("preact").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Component as e}from"preact";import{jsx as t,jsxs as n}from"preact/jsx-runtime";export class IslandErrorBoundary 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){let n={layoutPath:`island:${this.props.islandId}`,errorType:`island`,timestamp:Date.now(),componentStack:t.componentStack,errorBoundary:`IslandErrorBoundary`};if(this.setState({errorInfo:n}),this.props.onError&&this.props.onError(e,n),typeof
|
|
1
|
+
import{Component as e}from"preact";import{jsx as t,jsxs as n}from"preact/jsx-runtime";export class IslandErrorBoundary 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){let n={layoutPath:`island:${this.props.islandId}`,errorType:`island`,timestamp:Date.now(),componentStack:t.componentStack,errorBoundary:`IslandErrorBoundary`};if(this.setState({errorInfo:n}),this.props.onError&&this.props.onError(e,n),typeof process<`u`&&process.env?.NODE_ENV===`development`&&console.error(`Island Error [${this.props.islandId}]:`,e),!this.props.isolateError)throw e}handleRemoveIsland=()=>{let e=document.querySelector(`[data-island-id="${this.props.islandId}"]`);e&&e.remove()};handleReloadIsland=()=>{this.setState({hasError:!1,error:null,errorInfo:null})};renderFallback(){let{error:e}=this.state,{fallback:r,islandId:i}=this.props;if(r&&e)return r(e,i);let a=typeof process<`u`&&process.env?.NODE_ENV===`development`;return t(`div`,{class:`island-error-boundary`,"data-island-error":i,children:n(`div`,{class:`island-error-container`,children:[n(`div`,{class:`island-error-header`,children:[t(`span`,{class:`island-error-icon`,children:`⚠️`}),t(`span`,{class:`island-error-title`,children:`Island Error`})]}),n(`p`,{class:`island-error-message`,children:[`An error occurred in island "`,i,`". The rest of the page should work normally.`]}),n(`div`,{class:`island-error-actions`,children:[t(`button`,{onClick:this.handleReloadIsland,class:`island-reload-button`,children:`Reload Island`}),t(`button`,{onClick:this.handleRemoveIsland,class:`island-remove-button`,children:`Remove Island`})]}),a&&e&&n(`details`,{class:`island-error-details`,children:[t(`summary`,{children:`Error Details (Development)`}),n(`div`,{class:`island-error-info`,children:[n(`p`,{children:[t(`strong`,{children:`Island ID:`}),` `,i]}),n(`p`,{children:[t(`strong`,{children:`Error:`}),` `,e.message]})]}),t(`pre`,{class:`island-error-stack`,children:e.stack})]})]})})}render(){return this.state.hasError?this.renderFallback():this.props.children}}export function withIslandErrorBoundary(e,n,i){return function(a){return t(IslandErrorBoundary,{islandId:n,fallback:i?.fallback,isolateError:i?.isolateError??!0,onError:i?.onError,children:t(e,{...a})})}}
|
|
@@ -0,0 +1,34 @@
|
|
|
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 +1 @@
|
|
|
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
|
|
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}}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Component, ComponentChildren } from 'preact';
|
|
2
|
+
import type { LayoutErrorInfo, ErrorRecoveryStrategy } from '../types/layout.ts';
|
|
3
|
+
export interface LayoutErrorBoundaryProps {
|
|
4
|
+
children: ComponentChildren;
|
|
5
|
+
fallback?: (error: Error, retry: () => void) => ComponentChildren;
|
|
6
|
+
onError?: (error: Error, errorInfo: LayoutErrorInfo) => void;
|
|
7
|
+
recoveryStrategy?: ErrorRecoveryStrategy;
|
|
8
|
+
layoutPath?: string;
|
|
9
|
+
errorType?: 'component' | 'loader' | 'rendering' | 'island';
|
|
10
|
+
}
|
|
11
|
+
export interface LayoutErrorBoundaryState {
|
|
12
|
+
hasError: boolean;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
errorInfo: LayoutErrorInfo | null;
|
|
15
|
+
retryCount: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class LayoutErrorBoundary extends Component<LayoutErrorBoundaryProps, LayoutErrorBoundaryState> {
|
|
18
|
+
private maxRetries;
|
|
19
|
+
constructor(props: LayoutErrorBoundaryProps);
|
|
20
|
+
static getDerivedStateFromError(error: Error): Partial<LayoutErrorBoundaryState>;
|
|
21
|
+
componentDidCatch(error: Error, errorInfo: any): void;
|
|
22
|
+
private handleRetry;
|
|
23
|
+
private renderFallback;
|
|
24
|
+
render(): ComponentChildren;
|
|
25
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Component as e}from"preact";import{jsxs as t,jsx as n}from"preact/jsx-runtime";export class LayoutErrorBoundary extends e{maxRetries=3;constructor(e){super(e),this.state={hasError:!1,error:null,errorInfo:null,retryCount:0}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){let n={layoutPath:this.props.layoutPath||`unknown`,errorType:this.props.errorType||`component`,timestamp:Date.now(),componentStack:t.componentStack,errorBoundary:this.constructor.name};this.setState({errorInfo:n}),this.props.onError&&this.props.onError(e,n),typeof
|
|
1
|
+
import{Component as e}from"preact";import{jsxs as t,jsx as n}from"preact/jsx-runtime";export class LayoutErrorBoundary extends e{maxRetries=3;constructor(e){super(e),this.state={hasError:!1,error:null,errorInfo:null,retryCount:0}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){let n={layoutPath:this.props.layoutPath||`unknown`,errorType:this.props.errorType||`component`,timestamp:Date.now(),componentStack:t.componentStack,errorBoundary:this.constructor.name};this.setState({errorInfo:n}),this.props.onError&&this.props.onError(e,n),typeof process<`u`&&process.env?.NODE_ENV===`development`&&(console.error(`Layout Error Boundary caught an error:`,e),console.error(`Error Info:`,n),console.error(`Component Stack:`,t.componentStack))}handleRetry=()=>{this.state.retryCount<this.maxRetries&&this.setState({hasError:!1,error:null,errorInfo:null,retryCount:this.state.retryCount+1})};renderFallback(){let{error:e}=this.state,{fallback:r}=this.props;return r&&e?r(e,this.handleRetry):n(`div`,{class:`layout-error-boundary`,children:t(`div`,{class:`error-container`,children:[n(`h2`,{children:`Something went wrong`}),n(`p`,{children:`An error occurred while rendering this layout.`}),this.state.retryCount<this.maxRetries&&t(`button`,{onClick:this.handleRetry,class:`retry-button`,children:[`Try Again (`,this.maxRetries-this.state.retryCount,` attempts left)`]}),typeof process<`u`&&process.env?.NODE_ENV===`development`&&t(`details`,{class:`error-details`,children:[n(`summary`,{children:`Error Details (Development)`}),n(`pre`,{children:e?.stack}),this.state.errorInfo&&t(`div`,{children:[t(`p`,{children:[n(`strong`,{children:`Layout Path:`}),` `,this.state.errorInfo.layoutPath]}),t(`p`,{children:[n(`strong`,{children:`Error Type:`}),` `,this.state.errorInfo.errorType]}),t(`p`,{children:[n(`strong`,{children:`Timestamp:`}),` `,new Date(this.state.errorInfo.timestamp).toISOString()]})]})]})]})})}render(){return this.state.hasError?this.renderFallback():this.props.children}}
|
|
@@ -0,0 +1,36 @@
|
|
|
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;
|
|
@@ -0,0 +1,42 @@
|
|
|
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 +1 @@
|
|
|
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
|
|
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})})}}
|