@useavalon/avalon 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +54 -54
  2. package/dist/mod.js +1 -0
  3. package/dist/src/build/integration-bundler-plugin.js +1 -0
  4. package/dist/src/build/integration-config.js +1 -0
  5. package/dist/src/build/integration-detection-plugin.js +1 -0
  6. package/dist/src/build/integration-resolver-plugin.js +1 -0
  7. package/dist/src/build/island-manifest.js +1 -0
  8. package/dist/src/build/island-types-generator.js +5 -0
  9. package/dist/src/build/mdx-island-transform.js +2 -0
  10. package/dist/src/build/mdx-plugin.js +1 -0
  11. package/dist/src/build/page-island-transform.js +3 -0
  12. package/dist/src/build/prop-extractors/index.js +1 -0
  13. package/dist/src/build/prop-extractors/lit.js +1 -0
  14. package/dist/src/build/prop-extractors/qwik.js +1 -0
  15. package/dist/src/build/prop-extractors/solid.js +1 -0
  16. package/dist/src/build/prop-extractors/svelte.js +1 -0
  17. package/dist/src/build/prop-extractors/vue.js +1 -0
  18. package/dist/src/build/sidecar-file-manager.js +1 -0
  19. package/dist/src/build/sidecar-renderer.js +6 -0
  20. package/dist/src/client/adapters/index.js +1 -0
  21. package/dist/src/client/components.js +1 -0
  22. package/dist/src/client/css-hmr-handler.js +1 -0
  23. package/dist/src/client/framework-adapter.js +13 -0
  24. package/dist/src/client/hmr-coordinator.js +1 -0
  25. package/dist/src/client/hmr-error-overlay.js +214 -0
  26. package/dist/src/client/main.js +39 -0
  27. package/{src → dist/src}/client/types/framework-runtime.d.ts +68 -68
  28. package/{src → dist/src}/client/types/vite-hmr.d.ts +46 -46
  29. package/dist/src/client/types/vite-virtual-modules.d.ts +70 -0
  30. package/dist/src/components/Image.js +1 -0
  31. package/dist/src/components/IslandErrorBoundary.js +1 -0
  32. package/dist/src/components/LayoutDataErrorBoundary.js +1 -0
  33. package/dist/src/components/LayoutErrorBoundary.js +1 -0
  34. package/dist/src/components/PersistentIsland.js +1 -0
  35. package/dist/src/components/StreamingErrorBoundary.js +1 -0
  36. package/dist/src/components/StreamingLayout.js +29 -0
  37. package/dist/src/core/components/component-analyzer.js +1 -0
  38. package/dist/src/core/components/component-detection.js +5 -0
  39. package/dist/src/core/components/enhanced-framework-detector.js +1 -0
  40. package/dist/src/core/components/framework-registry.js +1 -0
  41. package/dist/src/core/content/mdx-processor.js +1 -0
  42. package/dist/src/core/integrations/index.js +1 -0
  43. package/dist/src/core/integrations/loader.js +1 -0
  44. package/dist/src/core/integrations/registry.js +1 -0
  45. package/dist/src/core/islands/island-persistence.js +1 -0
  46. package/dist/src/core/islands/island-state-serializer.js +1 -0
  47. package/dist/src/core/islands/persistent-island-context.js +1 -0
  48. package/dist/src/core/islands/use-persistent-state.js +1 -0
  49. package/dist/src/core/layout/enhanced-layout-resolver.js +1 -0
  50. package/dist/src/core/layout/layout-cache-manager.js +1 -0
  51. package/dist/src/core/layout/layout-composer.js +1 -0
  52. package/dist/src/core/layout/layout-data-loader.js +1 -0
  53. package/dist/src/core/layout/layout-discovery.js +1 -0
  54. package/dist/src/core/layout/layout-matcher.js +1 -0
  55. package/dist/src/core/layout/layout-types.js +1 -0
  56. package/dist/src/core/modules/framework-module-resolver.js +1 -0
  57. package/dist/src/islands/component-analysis.js +1 -0
  58. package/dist/src/islands/css-utils.js +17 -0
  59. package/dist/src/islands/discovery/index.js +1 -0
  60. package/dist/src/islands/discovery/registry.js +1 -0
  61. package/dist/src/islands/discovery/resolver.js +2 -0
  62. package/dist/src/islands/discovery/scanner.js +1 -0
  63. package/dist/src/islands/discovery/types.js +1 -0
  64. package/dist/src/islands/discovery/validator.js +18 -0
  65. package/dist/src/islands/discovery/watcher.js +1 -0
  66. package/dist/src/islands/framework-detection.js +1 -0
  67. package/dist/src/islands/integration-loader.js +1 -0
  68. package/dist/src/islands/island.js +1 -0
  69. package/dist/src/islands/render-cache.js +1 -0
  70. package/dist/src/islands/types.js +1 -0
  71. package/dist/src/islands/universal-css-collector.js +5 -0
  72. package/dist/src/islands/universal-head-collector.js +2 -0
  73. package/{src → dist/src}/layout-system.d.ts +592 -592
  74. package/dist/src/layout-system.js +1 -0
  75. package/dist/src/middleware/discovery.js +1 -0
  76. package/dist/src/middleware/executor.js +1 -0
  77. package/dist/src/middleware/index.js +1 -0
  78. package/dist/src/middleware/types.js +1 -0
  79. package/dist/src/nitro/build-config.js +1 -0
  80. package/dist/src/nitro/config.js +1 -0
  81. package/dist/src/nitro/error-handler.js +198 -0
  82. package/dist/src/nitro/index.js +1 -0
  83. package/dist/src/nitro/island-manifest.js +2 -0
  84. package/dist/src/nitro/middleware-adapter.js +1 -0
  85. package/dist/src/nitro/renderer.js +183 -0
  86. package/dist/src/nitro/route-discovery.js +1 -0
  87. package/dist/src/nitro/types.js +1 -0
  88. package/dist/src/render/collect-css.js +3 -0
  89. package/{src/render/error-pages.ts → dist/src/render/error-pages.js} +7 -38
  90. package/dist/src/render/isolated-ssr-renderer.js +1 -0
  91. package/dist/src/render/ssr.js +90 -0
  92. package/dist/src/schemas/api.js +1 -0
  93. package/dist/src/schemas/core.js +1 -0
  94. package/dist/src/schemas/index.js +1 -0
  95. package/dist/src/schemas/layout.js +1 -0
  96. package/dist/src/schemas/routing/index.js +1 -0
  97. package/dist/src/schemas/routing.js +1 -0
  98. package/dist/src/types/as-island.js +1 -0
  99. package/{src → dist/src}/types/image.d.ts +106 -106
  100. package/{src → dist/src}/types/index.d.ts +22 -22
  101. package/{src → dist/src}/types/island-jsx.d.ts +33 -33
  102. package/{src → dist/src}/types/island-prop.d.ts +20 -20
  103. package/dist/src/types/layout.js +1 -0
  104. package/{src → dist/src}/types/mdx.d.ts +6 -6
  105. package/dist/src/types/routing.js +1 -0
  106. package/dist/src/types/types.js +1 -0
  107. package/{src → dist/src}/types/urlpattern.d.ts +49 -49
  108. package/{src → dist/src}/types/vite-env.d.ts +11 -11
  109. package/dist/src/utils/dev-logger.js +12 -0
  110. package/dist/src/utils/fs.js +1 -0
  111. package/dist/src/vite-plugin/auto-discover.js +1 -0
  112. package/dist/src/vite-plugin/config.js +1 -0
  113. package/dist/src/vite-plugin/errors.js +1 -0
  114. package/dist/src/vite-plugin/image-optimization.js +45 -0
  115. package/dist/src/vite-plugin/integration-activator.js +1 -0
  116. package/dist/src/vite-plugin/island-sidecar-plugin.js +1 -0
  117. package/dist/src/vite-plugin/module-discovery.js +1 -0
  118. package/dist/src/vite-plugin/nitro-integration.js +42 -0
  119. package/dist/src/vite-plugin/plugin.js +1 -0
  120. package/dist/src/vite-plugin/types.js +1 -0
  121. package/dist/src/vite-plugin/validation.js +2 -0
  122. package/package.json +57 -26
  123. package/mod.ts +0 -302
  124. package/src/build/integration-bundler-plugin.ts +0 -116
  125. package/src/build/integration-config.ts +0 -168
  126. package/src/build/integration-detection-plugin.ts +0 -117
  127. package/src/build/integration-resolver-plugin.ts +0 -90
  128. package/src/build/island-manifest.ts +0 -269
  129. package/src/build/island-types-generator.ts +0 -476
  130. package/src/build/mdx-island-transform.ts +0 -464
  131. package/src/build/mdx-plugin.ts +0 -98
  132. package/src/build/page-island-transform.ts +0 -598
  133. package/src/build/prop-extractors/index.ts +0 -21
  134. package/src/build/prop-extractors/lit.ts +0 -140
  135. package/src/build/prop-extractors/qwik.ts +0 -16
  136. package/src/build/prop-extractors/solid.ts +0 -125
  137. package/src/build/prop-extractors/svelte.ts +0 -194
  138. package/src/build/prop-extractors/vue.ts +0 -111
  139. package/src/build/sidecar-file-manager.ts +0 -104
  140. package/src/build/sidecar-renderer.ts +0 -30
  141. package/src/client/adapters/index.js +0 -12
  142. package/src/client/adapters/index.ts +0 -13
  143. package/src/client/adapters/lit-adapter.js +0 -467
  144. package/src/client/adapters/lit-adapter.ts +0 -654
  145. package/src/client/adapters/preact-adapter.js +0 -223
  146. package/src/client/adapters/preact-adapter.ts +0 -331
  147. package/src/client/adapters/qwik-adapter.js +0 -259
  148. package/src/client/adapters/qwik-adapter.ts +0 -345
  149. package/src/client/adapters/react-adapter.js +0 -220
  150. package/src/client/adapters/react-adapter.ts +0 -353
  151. package/src/client/adapters/solid-adapter.js +0 -295
  152. package/src/client/adapters/solid-adapter.ts +0 -451
  153. package/src/client/adapters/svelte-adapter.js +0 -368
  154. package/src/client/adapters/svelte-adapter.ts +0 -524
  155. package/src/client/adapters/vue-adapter.js +0 -278
  156. package/src/client/adapters/vue-adapter.ts +0 -467
  157. package/src/client/components.js +0 -23
  158. package/src/client/components.ts +0 -35
  159. package/src/client/css-hmr-handler.js +0 -263
  160. package/src/client/css-hmr-handler.ts +0 -344
  161. package/src/client/framework-adapter.js +0 -283
  162. package/src/client/framework-adapter.ts +0 -462
  163. package/src/client/hmr-coordinator.js +0 -274
  164. package/src/client/hmr-coordinator.ts +0 -396
  165. package/src/client/hmr-error-overlay.js +0 -533
  166. package/src/client/main.js +0 -816
  167. package/src/client/types/vite-virtual-modules.d.ts +0 -60
  168. package/src/components/Image.tsx +0 -123
  169. package/src/components/IslandErrorBoundary.tsx +0 -145
  170. package/src/components/LayoutDataErrorBoundary.tsx +0 -141
  171. package/src/components/LayoutErrorBoundary.tsx +0 -127
  172. package/src/components/PersistentIsland.tsx +0 -52
  173. package/src/components/StreamingErrorBoundary.tsx +0 -233
  174. package/src/components/StreamingLayout.tsx +0 -538
  175. package/src/core/components/component-analyzer.ts +0 -192
  176. package/src/core/components/component-detection.ts +0 -508
  177. package/src/core/components/enhanced-framework-detector.ts +0 -500
  178. package/src/core/components/framework-registry.ts +0 -563
  179. package/src/core/content/mdx-processor.ts +0 -46
  180. package/src/core/integrations/index.ts +0 -19
  181. package/src/core/integrations/loader.ts +0 -125
  182. package/src/core/integrations/registry.ts +0 -175
  183. package/src/core/islands/island-persistence.ts +0 -325
  184. package/src/core/islands/island-state-serializer.ts +0 -258
  185. package/src/core/islands/persistent-island-context.tsx +0 -80
  186. package/src/core/islands/use-persistent-state.ts +0 -68
  187. package/src/core/layout/enhanced-layout-resolver.ts +0 -322
  188. package/src/core/layout/layout-cache-manager.ts +0 -485
  189. package/src/core/layout/layout-composer.ts +0 -357
  190. package/src/core/layout/layout-data-loader.ts +0 -516
  191. package/src/core/layout/layout-discovery.ts +0 -243
  192. package/src/core/layout/layout-matcher.ts +0 -299
  193. package/src/core/layout/layout-types.ts +0 -110
  194. package/src/core/modules/framework-module-resolver.ts +0 -273
  195. package/src/islands/component-analysis.ts +0 -213
  196. package/src/islands/css-utils.ts +0 -565
  197. package/src/islands/discovery/index.ts +0 -80
  198. package/src/islands/discovery/registry.ts +0 -340
  199. package/src/islands/discovery/resolver.ts +0 -477
  200. package/src/islands/discovery/scanner.ts +0 -386
  201. package/src/islands/discovery/types.ts +0 -117
  202. package/src/islands/discovery/validator.ts +0 -544
  203. package/src/islands/discovery/watcher.ts +0 -368
  204. package/src/islands/framework-detection.ts +0 -428
  205. package/src/islands/integration-loader.ts +0 -490
  206. package/src/islands/island.tsx +0 -565
  207. package/src/islands/render-cache.ts +0 -550
  208. package/src/islands/types.ts +0 -80
  209. package/src/islands/universal-css-collector.ts +0 -157
  210. package/src/islands/universal-head-collector.ts +0 -137
  211. package/src/layout-system.ts +0 -218
  212. package/src/middleware/discovery.ts +0 -268
  213. package/src/middleware/executor.ts +0 -315
  214. package/src/middleware/index.ts +0 -76
  215. package/src/middleware/types.ts +0 -99
  216. package/src/nitro/build-config.ts +0 -576
  217. package/src/nitro/config.ts +0 -483
  218. package/src/nitro/error-handler.ts +0 -636
  219. package/src/nitro/index.ts +0 -173
  220. package/src/nitro/island-manifest.ts +0 -584
  221. package/src/nitro/middleware-adapter.ts +0 -260
  222. package/src/nitro/renderer.ts +0 -1471
  223. package/src/nitro/route-discovery.ts +0 -439
  224. package/src/nitro/types.ts +0 -321
  225. package/src/render/collect-css.ts +0 -198
  226. package/src/render/isolated-ssr-renderer.ts +0 -654
  227. package/src/render/ssr.ts +0 -1030
  228. package/src/schemas/api.ts +0 -30
  229. package/src/schemas/core.ts +0 -64
  230. package/src/schemas/index.ts +0 -212
  231. package/src/schemas/layout.ts +0 -279
  232. package/src/schemas/routing/index.ts +0 -38
  233. package/src/schemas/routing.ts +0 -376
  234. package/src/types/as-island.ts +0 -20
  235. package/src/types/layout.ts +0 -285
  236. package/src/types/routing.ts +0 -555
  237. package/src/types/types.ts +0 -5
  238. package/src/utils/dev-logger.ts +0 -299
  239. package/src/utils/fs.ts +0 -151
  240. package/src/vite-plugin/auto-discover.ts +0 -551
  241. package/src/vite-plugin/config.ts +0 -266
  242. package/src/vite-plugin/errors.ts +0 -127
  243. package/src/vite-plugin/image-optimization.ts +0 -156
  244. package/src/vite-plugin/integration-activator.ts +0 -126
  245. package/src/vite-plugin/island-sidecar-plugin.ts +0 -176
  246. package/src/vite-plugin/module-discovery.ts +0 -189
  247. package/src/vite-plugin/nitro-integration.ts +0 -1354
  248. package/src/vite-plugin/plugin.ts +0 -409
  249. package/src/vite-plugin/types.ts +0 -327
  250. package/src/vite-plugin/validation.ts +0 -228
@@ -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
- });