@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
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { registry } from "./registry.ts";
|
|
2
|
-
import type { Integration } from "@useavalon/core";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Cache for loaded integrations to avoid repeated dynamic imports
|
|
6
|
-
*/
|
|
7
|
-
const integrationCache = new Map<string, Integration>();
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Load an integration by name, using cache if available
|
|
11
|
-
*/
|
|
12
|
-
export async function loadIntegration(framework: string): Promise<Integration> {
|
|
13
|
-
// Check cache first
|
|
14
|
-
if (integrationCache.has(framework)) {
|
|
15
|
-
return integrationCache.get(framework)!;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Load from registry (which handles dynamic imports)
|
|
19
|
-
const integration = await registry.load(framework);
|
|
20
|
-
|
|
21
|
-
// Cache the loaded integration
|
|
22
|
-
integrationCache.set(framework, integration);
|
|
23
|
-
|
|
24
|
-
return integration;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Detect framework from file path and load the appropriate integration
|
|
29
|
-
*/
|
|
30
|
-
export async function detectAndLoadIntegration(src: string): Promise<Integration> {
|
|
31
|
-
const framework = detectFrameworkFromPath(src);
|
|
32
|
-
return await loadIntegration(framework);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Detect framework from file path based on extension and naming conventions
|
|
37
|
-
*/
|
|
38
|
-
export function detectFrameworkFromPath(src: string): string {
|
|
39
|
-
// Vue files
|
|
40
|
-
if (src.endsWith(".vue")) {
|
|
41
|
-
return "vue";
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Svelte files
|
|
45
|
-
if (src.endsWith(".svelte")) {
|
|
46
|
-
return "svelte";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Solid files (convention: .solid.tsx or .solid.jsx)
|
|
50
|
-
if (src.includes(".solid.")) {
|
|
51
|
-
return "solid";
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Qwik files (convention: .qwik.tsx or .qwik.jsx)
|
|
55
|
-
if (src.includes(".qwik.")) {
|
|
56
|
-
return "qwik";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Default to Preact for .tsx and .jsx files
|
|
60
|
-
return "preact";
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Detect framework from file content by analyzing imports and patterns
|
|
65
|
-
*/
|
|
66
|
-
export function detectFrameworkFromContent(
|
|
67
|
-
src: string,
|
|
68
|
-
content?: string
|
|
69
|
-
): string {
|
|
70
|
-
// First try path-based detection
|
|
71
|
-
const pathFramework = detectFrameworkFromPath(src);
|
|
72
|
-
|
|
73
|
-
// If we have a definitive answer from path, use it
|
|
74
|
-
if (pathFramework !== "preact" || !content) {
|
|
75
|
-
return pathFramework;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// For .tsx/.jsx files, analyze content to distinguish between Preact and Solid
|
|
79
|
-
if (content.includes("solid-js")) {
|
|
80
|
-
return "solid";
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (content.includes("@builder.io/qwik")) {
|
|
84
|
-
return "qwik";
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (content.includes("preact")) {
|
|
88
|
-
return "preact";
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Default to Preact
|
|
92
|
-
return "preact";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Preload integrations for the given frameworks
|
|
97
|
-
* Useful for warming up the cache during build or startup
|
|
98
|
-
*/
|
|
99
|
-
export async function preloadIntegrations(frameworks: string[]): Promise<void> {
|
|
100
|
-
await Promise.all(
|
|
101
|
-
frameworks.map(framework => loadIntegration(framework))
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get all currently loaded integrations
|
|
107
|
-
*/
|
|
108
|
-
export function getLoadedIntegrations(): Integration[] {
|
|
109
|
-
return Array.from(integrationCache.values());
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Clear the integration cache
|
|
114
|
-
* Useful for testing or hot module replacement
|
|
115
|
-
*/
|
|
116
|
-
export function clearIntegrationCache(): void {
|
|
117
|
-
integrationCache.clear();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check if an integration is loaded in cache
|
|
122
|
-
*/
|
|
123
|
-
export function isIntegrationLoaded(framework: string): boolean {
|
|
124
|
-
return integrationCache.has(framework);
|
|
125
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import type { Integration } from "@useavalon/core";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { statSync } from "node:fs";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Find the root of the Avalon monorepo by looking for packages/integrations
|
|
7
|
-
*/
|
|
8
|
-
function findMonorepoRoot(): string {
|
|
9
|
-
let currentDir = process.cwd();
|
|
10
|
-
|
|
11
|
-
// Walk up the directory tree looking for packages/integrations
|
|
12
|
-
for (let i = 0; i < 10; i++) {
|
|
13
|
-
try {
|
|
14
|
-
const integrationsPath = join(currentDir, "packages", "integrations");
|
|
15
|
-
const stat = statSync(integrationsPath);
|
|
16
|
-
if (stat.isDirectory()) {
|
|
17
|
-
return currentDir;
|
|
18
|
-
}
|
|
19
|
-
} catch {
|
|
20
|
-
// Directory doesn't exist, try parent
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const parent = dirname(currentDir);
|
|
24
|
-
if (parent === currentDir) {
|
|
25
|
-
// Reached root, stop
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
currentDir = parent;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Fallback to cwd
|
|
32
|
-
return process.cwd();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* IntegrationRegistry manages loaded framework integrations.
|
|
37
|
-
* It provides registration, retrieval, and dynamic loading of integrations.
|
|
38
|
-
*/
|
|
39
|
-
export class IntegrationRegistry {
|
|
40
|
-
private readonly integrations = new Map<string, Integration>();
|
|
41
|
-
private readonly loadingPromises = new Map<string, Promise<Integration>>();
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Register an integration instance
|
|
45
|
-
*/
|
|
46
|
-
register(integration: Integration): void {
|
|
47
|
-
if (!integration.name) {
|
|
48
|
-
throw new Error("Integration must have a name");
|
|
49
|
-
}
|
|
50
|
-
this.integrations.set(integration.name, integration);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Get a registered integration by name
|
|
55
|
-
*/
|
|
56
|
-
get(name: string): Integration | undefined {
|
|
57
|
-
return this.integrations.get(name);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Check if an integration is registered
|
|
62
|
-
*/
|
|
63
|
-
has(name: string): boolean {
|
|
64
|
-
return this.integrations.has(name);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Dynamically load an integration by name
|
|
69
|
-
* Returns cached integration if already loaded
|
|
70
|
-
*/
|
|
71
|
-
async load(name: string): Promise<Integration> {
|
|
72
|
-
// Check if already loaded
|
|
73
|
-
const existing = this.integrations.get(name);
|
|
74
|
-
if (existing) {
|
|
75
|
-
return existing;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check if currently loading (prevent duplicate loads)
|
|
79
|
-
const loadingPromise = this.loadingPromises.get(name);
|
|
80
|
-
if (loadingPromise) {
|
|
81
|
-
return loadingPromise;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Start loading
|
|
85
|
-
const promise = this.loadIntegration(name);
|
|
86
|
-
this.loadingPromises.set(name, promise);
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const integration = await promise;
|
|
90
|
-
this.register(integration);
|
|
91
|
-
return integration;
|
|
92
|
-
} finally {
|
|
93
|
-
this.loadingPromises.delete(name);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private async loadIntegration(name: string): Promise<Integration> {
|
|
98
|
-
const integrationKey = `${name}Integration`;
|
|
99
|
-
|
|
100
|
-
// 1. Try loading from the installed npm package first (@useavalon/<name>)
|
|
101
|
-
try {
|
|
102
|
-
const packageName = `@useavalon/${name}`;
|
|
103
|
-
const module = await import(/* @vite-ignore */ packageName);
|
|
104
|
-
const integration = module[integrationKey] || module.default;
|
|
105
|
-
if (integration) return integration as Integration;
|
|
106
|
-
} catch {
|
|
107
|
-
// Package not installed or import failed — try monorepo path
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// 2. Monorepo fallback: resolve via packages/integrations/<name>/mod.ts
|
|
111
|
-
try {
|
|
112
|
-
const monorepoRoot = findMonorepoRoot();
|
|
113
|
-
const integrationPath = join(monorepoRoot, "packages", "integrations", name, "mod.ts");
|
|
114
|
-
const fileUrl = `file://${integrationPath}`;
|
|
115
|
-
const module = await import(/* @vite-ignore */ fileUrl);
|
|
116
|
-
const integration = module[integrationKey] || module.default;
|
|
117
|
-
if (integration) return integration as Integration;
|
|
118
|
-
} catch {
|
|
119
|
-
// Monorepo path also failed
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
throw new Error(
|
|
123
|
-
`Failed to load integration for framework '${name}'. ` +
|
|
124
|
-
`Make sure @useavalon/${name} is installed.\n` +
|
|
125
|
-
`Install it with: bun add @useavalon/${name}`,
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Get all registered integrations
|
|
131
|
-
*/
|
|
132
|
-
getAll(): Integration[] {
|
|
133
|
-
return Array.from(this.integrations.values());
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Get all registered integration names
|
|
138
|
-
*/
|
|
139
|
-
getAllNames(): string[] {
|
|
140
|
-
return Array.from(this.integrations.keys());
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Unregister an integration
|
|
145
|
-
*/
|
|
146
|
-
unregister(name: string): boolean {
|
|
147
|
-
return this.integrations.delete(name);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Clear all registered integrations
|
|
152
|
-
*/
|
|
153
|
-
clear(): void {
|
|
154
|
-
this.integrations.clear();
|
|
155
|
-
this.loadingPromises.clear();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Get the count of registered integrations
|
|
160
|
-
*/
|
|
161
|
-
get size(): number {
|
|
162
|
-
return this.integrations.size;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Global singleton registry instance
|
|
167
|
-
// Use globalThis to ensure the registry is shared across all module contexts
|
|
168
|
-
// This is important because Vite's ssrLoadModule creates new module contexts
|
|
169
|
-
declare global {
|
|
170
|
-
var __avalonIntegrationRegistry: IntegrationRegistry | undefined;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
globalThis.__avalonIntegrationRegistry ??= new IntegrationRegistry();
|
|
174
|
-
|
|
175
|
-
export const registry = globalThis.__avalonIntegrationRegistry;
|
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
import type { IslandState } from '../../schemas/layout.ts';
|
|
2
|
-
import type { IIslandPersistence } from '../../types/layout.ts';
|
|
3
|
-
import { IslandStateSerializer } from './island-state-serializer.ts';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* IslandPersistence class for state management across navigation
|
|
7
|
-
*
|
|
8
|
-
* Handles saving, loading, and clearing island state using browser storage
|
|
9
|
-
* with support for both sessionStorage and localStorage persistence strategies.
|
|
10
|
-
*/
|
|
11
|
-
export class IslandPersistence implements IIslandPersistence {
|
|
12
|
-
private storageType: 'session' | 'local';
|
|
13
|
-
private keyPrefix: string;
|
|
14
|
-
private storage: Storage | null = null;
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
options: {
|
|
18
|
-
storageType?: 'session' | 'local';
|
|
19
|
-
keyPrefix?: string;
|
|
20
|
-
} = {}
|
|
21
|
-
) {
|
|
22
|
-
this.storageType = options.storageType || 'session';
|
|
23
|
-
this.keyPrefix = options.keyPrefix || 'island-state';
|
|
24
|
-
|
|
25
|
-
// Initialize storage if available (browser environment)
|
|
26
|
-
if (typeof window !== 'undefined') {
|
|
27
|
-
this.storage = this.storageType === 'session' ? sessionStorage : localStorage;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Save island state to browser storage
|
|
33
|
-
*/
|
|
34
|
-
saveState(id: string, state: IslandState): void {
|
|
35
|
-
if (!this.storage) {
|
|
36
|
-
console.warn('Island persistence: Storage not available (server-side or unsupported browser)');
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const key = this.getStorageKey(id);
|
|
42
|
-
|
|
43
|
-
// Use the IslandStateSerializer for proper serialization
|
|
44
|
-
const serializedState = IslandStateSerializer.serialize({
|
|
45
|
-
state,
|
|
46
|
-
timestamp: Date.now(),
|
|
47
|
-
version: '1.0',
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
this.storage.setItem(key, serializedState);
|
|
51
|
-
console.log(`Island state saved for ${id}`);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
console.error(`Failed to save island state for ${id}:`, error);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Load island state from browser storage
|
|
59
|
-
*/
|
|
60
|
-
loadState(id: string): IslandState | null {
|
|
61
|
-
if (!this.storage) {
|
|
62
|
-
console.warn('Island persistence: Storage not available (server-side or unsupported browser)');
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const key = this.getStorageKey(id);
|
|
68
|
-
const serializedState = this.storage.getItem(key);
|
|
69
|
-
|
|
70
|
-
if (!serializedState) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Use the IslandStateSerializer for proper deserialization
|
|
75
|
-
const parsed = IslandStateSerializer.deserialize(serializedState);
|
|
76
|
-
|
|
77
|
-
// Validate the stored data structure
|
|
78
|
-
if (!parsed.state || !parsed.timestamp || !parsed.version) {
|
|
79
|
-
console.warn(`Invalid island state format for ${id}, clearing...`);
|
|
80
|
-
this.clearState(id);
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
console.log(`Island state loaded for ${id}`);
|
|
85
|
-
return parsed.state as Record<string, unknown>;
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.error(`Failed to load island state for ${id}:`, error);
|
|
88
|
-
// Clear corrupted state
|
|
89
|
-
this.clearState(id);
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Clear island state from browser storage
|
|
96
|
-
*/
|
|
97
|
-
clearState(id: string): void {
|
|
98
|
-
if (!this.storage) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const key = this.getStorageKey(id);
|
|
104
|
-
this.storage.removeItem(key);
|
|
105
|
-
console.log(`Island state cleared for ${id}`);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error(`Failed to clear island state for ${id}:`, error);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Check if state exists for an island
|
|
113
|
-
*/
|
|
114
|
-
hasState(id: string): boolean {
|
|
115
|
-
if (!this.storage) {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
const key = this.getStorageKey(id);
|
|
121
|
-
return this.storage.getItem(key) !== null;
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error(`Failed to check island state for ${id}:`, error);
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Get all stored island IDs
|
|
130
|
-
*/
|
|
131
|
-
getStoredIds(): string[] {
|
|
132
|
-
if (!this.storage) {
|
|
133
|
-
return [];
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const ids: string[] = [];
|
|
138
|
-
const prefixLength = this.keyPrefix.length + 1; // +1 for the separator
|
|
139
|
-
|
|
140
|
-
for (let i = 0; i < this.storage.length; i++) {
|
|
141
|
-
const key = this.storage.key(i);
|
|
142
|
-
if (key && key.startsWith(this.keyPrefix + ':')) {
|
|
143
|
-
ids.push(key.substring(prefixLength));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return ids;
|
|
148
|
-
} catch (error) {
|
|
149
|
-
console.error('Failed to get stored island IDs:', error);
|
|
150
|
-
return [];
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Clear all stored states
|
|
156
|
-
*/
|
|
157
|
-
clearAllStates(): void {
|
|
158
|
-
if (!this.storage) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
const keysToRemove: string[] = [];
|
|
164
|
-
|
|
165
|
-
for (let i = 0; i < this.storage.length; i++) {
|
|
166
|
-
const key = this.storage.key(i);
|
|
167
|
-
if (key && key.startsWith(this.keyPrefix + ':')) {
|
|
168
|
-
keysToRemove.push(key);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
keysToRemove.forEach(key => this.storage!.removeItem(key));
|
|
173
|
-
console.log(`Cleared ${keysToRemove.length} island states`);
|
|
174
|
-
} catch (error) {
|
|
175
|
-
console.error('Failed to clear all island states:', error);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Get the storage key for an island ID
|
|
181
|
-
*/
|
|
182
|
-
private getStorageKey(id: string): string {
|
|
183
|
-
return `${this.keyPrefix}:${id}`;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Get current storage configuration
|
|
188
|
-
*/
|
|
189
|
-
getConfig(): { storageType: string; keyPrefix: string; available: boolean } {
|
|
190
|
-
return {
|
|
191
|
-
storageType: this.storageType,
|
|
192
|
-
keyPrefix: this.keyPrefix,
|
|
193
|
-
available: this.storage !== null,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Get storage usage statistics
|
|
199
|
-
*/
|
|
200
|
-
getStorageStats(): { totalKeys: number; islandKeys: number; estimatedSize: number } {
|
|
201
|
-
if (!this.storage) {
|
|
202
|
-
return { totalKeys: 0, islandKeys: 0, estimatedSize: 0 };
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
let islandKeys = 0;
|
|
207
|
-
let estimatedSize = 0;
|
|
208
|
-
|
|
209
|
-
for (let i = 0; i < this.storage.length; i++) {
|
|
210
|
-
const key = this.storage.key(i);
|
|
211
|
-
if (key && key.startsWith(this.keyPrefix + ':')) {
|
|
212
|
-
islandKeys++;
|
|
213
|
-
const value = this.storage.getItem(key);
|
|
214
|
-
if (value) {
|
|
215
|
-
estimatedSize += key.length + value.length;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
totalKeys: this.storage.length,
|
|
222
|
-
islandKeys,
|
|
223
|
-
estimatedSize,
|
|
224
|
-
};
|
|
225
|
-
} catch (error) {
|
|
226
|
-
console.error('Failed to get storage stats:', error);
|
|
227
|
-
return { totalKeys: 0, islandKeys: 0, estimatedSize: 0 };
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* JSON.stringify replacer function to handle special types
|
|
233
|
-
*/
|
|
234
|
-
private replacer(key: string, value: unknown): unknown {
|
|
235
|
-
// Handle Date objects
|
|
236
|
-
if (value instanceof Date) {
|
|
237
|
-
return {
|
|
238
|
-
__type: 'Date',
|
|
239
|
-
__value: value.toISOString(),
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Handle RegExp objects
|
|
244
|
-
if (value instanceof RegExp) {
|
|
245
|
-
return {
|
|
246
|
-
__type: 'RegExp',
|
|
247
|
-
__value: {
|
|
248
|
-
source: value.source,
|
|
249
|
-
flags: value.flags,
|
|
250
|
-
},
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Handle Map objects
|
|
255
|
-
if (value instanceof Map) {
|
|
256
|
-
return {
|
|
257
|
-
__type: 'Map',
|
|
258
|
-
__value: Array.from(value.entries()),
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Handle Set objects
|
|
263
|
-
if (value instanceof Set) {
|
|
264
|
-
return {
|
|
265
|
-
__type: 'Set',
|
|
266
|
-
__value: Array.from(value.values()),
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Handle functions (convert to null - functions can't be serialized)
|
|
271
|
-
if (typeof value === 'function') {
|
|
272
|
-
console.warn(`Function found in island state at key "${key}", converting to null`);
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Handle undefined (convert to null)
|
|
277
|
-
if (value === undefined) {
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return value;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* JSON.parse reviver function to restore special types
|
|
286
|
-
*/
|
|
287
|
-
private reviver(key: string, value: unknown): unknown {
|
|
288
|
-
// Check if this is a special type object
|
|
289
|
-
if (value && typeof value === 'object') {
|
|
290
|
-
const obj = value as Record<string, unknown>;
|
|
291
|
-
if (obj.__type && obj.__value !== undefined) {
|
|
292
|
-
switch (obj.__type) {
|
|
293
|
-
case 'Date':
|
|
294
|
-
return new Date(obj.__value as string);
|
|
295
|
-
|
|
296
|
-
case 'RegExp': {
|
|
297
|
-
const rv = obj.__value as { source: string; flags: string };
|
|
298
|
-
return new RegExp(rv.source, rv.flags);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
case 'Map':
|
|
302
|
-
return new Map(obj.__value as Iterable<[unknown, unknown]>);
|
|
303
|
-
|
|
304
|
-
case 'Set':
|
|
305
|
-
return new Set(obj.__value as Iterable<unknown>);
|
|
306
|
-
|
|
307
|
-
default:
|
|
308
|
-
console.warn(`Unknown special type "${obj.__type}" in serialized state`);
|
|
309
|
-
return obj.__value;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return value;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Default island persistence instance
|
|
320
|
-
* Uses sessionStorage by default for better privacy and performance
|
|
321
|
-
*/
|
|
322
|
-
export const defaultIslandPersistence = new IslandPersistence({
|
|
323
|
-
storageType: 'session',
|
|
324
|
-
keyPrefix: 'island-state',
|
|
325
|
-
});
|