@useavalon/avalon 0.1.0

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 (159) hide show
  1. package/README.md +54 -0
  2. package/mod.ts +301 -0
  3. package/package.json +85 -0
  4. package/src/build/README.md +310 -0
  5. package/src/build/integration-bundler-plugin.ts +116 -0
  6. package/src/build/integration-config.ts +168 -0
  7. package/src/build/integration-detection-plugin.ts +117 -0
  8. package/src/build/integration-resolver-plugin.ts +90 -0
  9. package/src/build/island-manifest.ts +269 -0
  10. package/src/build/island-types-generator.ts +476 -0
  11. package/src/build/mdx-island-transform.ts +464 -0
  12. package/src/build/mdx-plugin.ts +98 -0
  13. package/src/build/page-island-transform.ts +598 -0
  14. package/src/build/prop-extractors/index.ts +21 -0
  15. package/src/build/prop-extractors/lit.ts +140 -0
  16. package/src/build/prop-extractors/qwik.ts +16 -0
  17. package/src/build/prop-extractors/solid.ts +125 -0
  18. package/src/build/prop-extractors/svelte.ts +194 -0
  19. package/src/build/prop-extractors/vue.ts +111 -0
  20. package/src/build/sidecar-file-manager.ts +104 -0
  21. package/src/build/sidecar-renderer.ts +30 -0
  22. package/src/client/adapters/index.ts +13 -0
  23. package/src/client/adapters/lit-adapter.ts +654 -0
  24. package/src/client/adapters/preact-adapter.ts +331 -0
  25. package/src/client/adapters/qwik-adapter.ts +345 -0
  26. package/src/client/adapters/react-adapter.ts +353 -0
  27. package/src/client/adapters/solid-adapter.ts +451 -0
  28. package/src/client/adapters/svelte-adapter.ts +524 -0
  29. package/src/client/adapters/vue-adapter.ts +467 -0
  30. package/src/client/components.ts +35 -0
  31. package/src/client/css-hmr-handler.ts +344 -0
  32. package/src/client/framework-adapter.ts +462 -0
  33. package/src/client/hmr-coordinator.ts +396 -0
  34. package/src/client/hmr-error-overlay.js +533 -0
  35. package/src/client/main.js +816 -0
  36. package/src/client/tests/css-hmr-handler.test.ts +360 -0
  37. package/src/client/tests/framework-adapter.test.ts +519 -0
  38. package/src/client/tests/hmr-coordinator.test.ts +176 -0
  39. package/src/client/tests/hydration-option-parsing.test.ts +107 -0
  40. package/src/client/tests/lit-adapter.test.ts +427 -0
  41. package/src/client/tests/preact-adapter.test.ts +353 -0
  42. package/src/client/tests/qwik-adapter.test.ts +343 -0
  43. package/src/client/tests/react-adapter.test.ts +317 -0
  44. package/src/client/tests/solid-adapter.test.ts +396 -0
  45. package/src/client/tests/svelte-adapter.test.ts +387 -0
  46. package/src/client/tests/vue-adapter.test.ts +407 -0
  47. package/src/client/types/framework-runtime.d.ts +68 -0
  48. package/src/client/types/vite-hmr.d.ts +46 -0
  49. package/src/client/types/vite-virtual-modules.d.ts +60 -0
  50. package/src/components/Image.tsx +123 -0
  51. package/src/components/IslandErrorBoundary.tsx +145 -0
  52. package/src/components/LayoutDataErrorBoundary.tsx +141 -0
  53. package/src/components/LayoutErrorBoundary.tsx +127 -0
  54. package/src/components/PersistentIsland.tsx +52 -0
  55. package/src/components/StreamingErrorBoundary.tsx +233 -0
  56. package/src/components/StreamingLayout.tsx +538 -0
  57. package/src/components/tests/component-analyzer.test.ts +96 -0
  58. package/src/components/tests/component-detection.test.ts +347 -0
  59. package/src/components/tests/persistent-islands.test.ts +398 -0
  60. package/src/core/components/component-analyzer.ts +192 -0
  61. package/src/core/components/component-detection.ts +508 -0
  62. package/src/core/components/enhanced-framework-detector.ts +500 -0
  63. package/src/core/components/framework-registry.ts +563 -0
  64. package/src/core/components/tests/enhanced-framework-detector.test.ts +577 -0
  65. package/src/core/components/tests/framework-registry.test.ts +465 -0
  66. package/src/core/content/mdx-processor.ts +46 -0
  67. package/src/core/integrations/README.md +282 -0
  68. package/src/core/integrations/index.ts +19 -0
  69. package/src/core/integrations/loader.ts +125 -0
  70. package/src/core/integrations/registry.ts +195 -0
  71. package/src/core/islands/island-persistence.ts +325 -0
  72. package/src/core/islands/island-state-serializer.ts +258 -0
  73. package/src/core/islands/persistent-island-context.tsx +80 -0
  74. package/src/core/islands/use-persistent-state.ts +68 -0
  75. package/src/core/layout/enhanced-layout-resolver.ts +322 -0
  76. package/src/core/layout/layout-cache-manager.ts +485 -0
  77. package/src/core/layout/layout-composer.ts +357 -0
  78. package/src/core/layout/layout-data-loader.ts +516 -0
  79. package/src/core/layout/layout-discovery.ts +243 -0
  80. package/src/core/layout/layout-matcher.ts +299 -0
  81. package/src/core/layout/layout-types.ts +110 -0
  82. package/src/core/layout/tests/enhanced-layout-resolver.test.ts +477 -0
  83. package/src/core/layout/tests/layout-cache-optimization.test.ts +149 -0
  84. package/src/core/layout/tests/layout-composer.test.ts +486 -0
  85. package/src/core/layout/tests/layout-data-loader.test.ts +443 -0
  86. package/src/core/layout/tests/layout-discovery.test.ts +253 -0
  87. package/src/core/layout/tests/layout-matcher.test.ts +480 -0
  88. package/src/core/modules/framework-module-resolver.ts +273 -0
  89. package/src/core/modules/tests/framework-module-resolver.test.ts +263 -0
  90. package/src/core/modules/tests/module-resolution-integration.test.ts +117 -0
  91. package/src/islands/component-analysis.ts +213 -0
  92. package/src/islands/css-utils.ts +565 -0
  93. package/src/islands/discovery/index.ts +80 -0
  94. package/src/islands/discovery/registry.ts +340 -0
  95. package/src/islands/discovery/resolver.ts +477 -0
  96. package/src/islands/discovery/scanner.ts +386 -0
  97. package/src/islands/discovery/tests/island-discovery.test.ts +881 -0
  98. package/src/islands/discovery/types.ts +117 -0
  99. package/src/islands/discovery/validator.ts +544 -0
  100. package/src/islands/discovery/watcher.ts +368 -0
  101. package/src/islands/framework-detection.ts +428 -0
  102. package/src/islands/integration-loader.ts +490 -0
  103. package/src/islands/island.tsx +565 -0
  104. package/src/islands/render-cache.ts +550 -0
  105. package/src/islands/types.ts +80 -0
  106. package/src/islands/universal-css-collector.ts +157 -0
  107. package/src/islands/universal-head-collector.ts +137 -0
  108. package/src/layout-system.d.ts +592 -0
  109. package/src/layout-system.ts +218 -0
  110. package/src/middleware/__tests__/discovery.test.ts +107 -0
  111. package/src/middleware/discovery.ts +268 -0
  112. package/src/middleware/executor.ts +315 -0
  113. package/src/middleware/index.ts +76 -0
  114. package/src/middleware/types.ts +99 -0
  115. package/src/nitro/build-config.ts +576 -0
  116. package/src/nitro/config.ts +483 -0
  117. package/src/nitro/error-handler.ts +636 -0
  118. package/src/nitro/index.ts +173 -0
  119. package/src/nitro/island-manifest.ts +584 -0
  120. package/src/nitro/middleware-adapter.ts +260 -0
  121. package/src/nitro/renderer.ts +1458 -0
  122. package/src/nitro/route-discovery.ts +439 -0
  123. package/src/nitro/types.ts +321 -0
  124. package/src/render/collect-css.ts +198 -0
  125. package/src/render/error-pages.ts +79 -0
  126. package/src/render/isolated-ssr-renderer.ts +654 -0
  127. package/src/render/ssr.ts +1030 -0
  128. package/src/schemas/api.ts +30 -0
  129. package/src/schemas/core.ts +64 -0
  130. package/src/schemas/index.ts +212 -0
  131. package/src/schemas/layout.ts +279 -0
  132. package/src/schemas/routing/index.ts +38 -0
  133. package/src/schemas/routing.ts +376 -0
  134. package/src/types/as-island.ts +20 -0
  135. package/src/types/image.d.ts +106 -0
  136. package/src/types/index.d.ts +22 -0
  137. package/src/types/island-jsx.d.ts +33 -0
  138. package/src/types/island-prop.d.ts +20 -0
  139. package/src/types/layout.ts +285 -0
  140. package/src/types/mdx.d.ts +6 -0
  141. package/src/types/routing.ts +555 -0
  142. package/src/types/tests/layout-types.test.ts +197 -0
  143. package/src/types/types.ts +5 -0
  144. package/src/types/urlpattern.d.ts +49 -0
  145. package/src/types/vite-env.d.ts +11 -0
  146. package/src/utils/dev-logger.ts +299 -0
  147. package/src/utils/fs.ts +151 -0
  148. package/src/vite-plugin/auto-discover.ts +551 -0
  149. package/src/vite-plugin/config.ts +266 -0
  150. package/src/vite-plugin/errors.ts +127 -0
  151. package/src/vite-plugin/image-optimization.ts +151 -0
  152. package/src/vite-plugin/integration-activator.ts +126 -0
  153. package/src/vite-plugin/island-sidecar-plugin.ts +176 -0
  154. package/src/vite-plugin/module-discovery.ts +189 -0
  155. package/src/vite-plugin/nitro-integration.ts +1334 -0
  156. package/src/vite-plugin/plugin.ts +329 -0
  157. package/src/vite-plugin/tests/image-optimization.test.ts +54 -0
  158. package/src/vite-plugin/types.ts +327 -0
  159. package/src/vite-plugin/validation.ts +228 -0
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Simplified Middleware Executor
3
+ *
4
+ * This module provides a streamlined middleware execution system that aligns
5
+ * with Nitro's conventions while supporting Avalon's route-scoped middleware.
6
+ *
7
+ * Key features:
8
+ * - Nitro-style handler signature: return void to continue, return Response to terminate
9
+ * - Middleware caching for performance
10
+
11
+ * - Error propagation to Nitro's error handling
12
+ * - Context preservation: event.context modifications persist through the chain
13
+ * - Development logging for context changes
14
+ *
15
+ * Requirements: 1.2, 1.3, 1.4, 2.1, 2.2
16
+ */
17
+
18
+ import type { H3Event } from 'h3';
19
+ import type { MiddlewareHandler, MiddlewareRoute, MiddlewareFileExport, MiddlewareExecutorOptions } from './types.ts';
20
+ import { getMatchingMiddleware } from './discovery.ts';
21
+
22
+ /**
23
+ * Captures a snapshot of the event context for comparison
24
+ * Used in development mode to log context changes
25
+ */
26
+ function captureContextSnapshot(context: Record<string, unknown>): Map<string, unknown> {
27
+ const snapshot = new Map<string, unknown>();
28
+ for (const key of Object.keys(context)) {
29
+ snapshot.set(key, context[key]);
30
+ }
31
+ return snapshot;
32
+ }
33
+
34
+ /**
35
+ * Compares two context snapshots and returns the changes
36
+ * Used in development mode to log context modifications
37
+ */
38
+ function getContextChanges(
39
+ before: Map<string, unknown>,
40
+ after: Record<string, unknown>,
41
+ ): { added: string[]; modified: string[]; removed: string[] } {
42
+ const added: string[] = [];
43
+ const modified: string[] = [];
44
+ const removed: string[] = [];
45
+
46
+ for (const key of Object.keys(after)) {
47
+ if (!before.has(key)) {
48
+ added.push(key);
49
+ } else if (before.get(key) !== after[key]) {
50
+ modified.push(key);
51
+ }
52
+ }
53
+
54
+ for (const key of before.keys()) {
55
+ if (!(key in after)) {
56
+ removed.push(key);
57
+ }
58
+ }
59
+
60
+ return { added, modified, removed };
61
+ }
62
+
63
+ /**
64
+ * Logs context changes in development mode
65
+ * Requirements: 2.1, 2.2
66
+ *
67
+ * Note: Intentionally minimal to reduce log noise.
68
+ * Uncomment the body for debugging middleware context issues.
69
+ */
70
+ function logContextChanges(
71
+ _filePath: string,
72
+ _changes: { added: string[]; modified: string[]; removed: string[] },
73
+ ): void {
74
+ // Uncomment for debugging middleware context issues:
75
+ // const hasChanges = _changes.added.length > 0 || _changes.modified.length > 0 || _changes.removed.length > 0;
76
+ // if (!hasChanges) return;
77
+ // console.log(`[middleware] Context changes in ${_filePath}: ...`);
78
+ }
79
+
80
+ /** Default executor options */
81
+ const DEFAULT_OPTIONS: Required<MiddlewareExecutorOptions> = {
82
+ devMode: false,
83
+ timeout: 30000,
84
+ };
85
+
86
+ /** Middleware cache: maps file paths to loaded handlers */
87
+ const middlewareCache = new Map<string, MiddlewareHandler>();
88
+
89
+ /**
90
+ * Executes a single middleware route handler with context tracking.
91
+ * Returns the Response if the chain should terminate, undefined to continue.
92
+ */
93
+ async function executeMiddlewareRoute(
94
+ event: H3Event,
95
+ route: MiddlewareRoute,
96
+ devMode: boolean,
97
+ timeout: number,
98
+ ): Promise<Response | undefined> {
99
+ const handler = await loadMiddleware(route.filePath, devMode);
100
+ if (!handler) return undefined;
101
+
102
+ const contextBefore = devMode ? captureContextSnapshot(event.context) : null;
103
+
104
+ const result = await executeWithTimeout(() => handler(event), timeout, route.filePath);
105
+
106
+ if (devMode && contextBefore) {
107
+ const changes = getContextChanges(contextBefore, event.context);
108
+ logContextChanges(route.filePath, changes);
109
+ }
110
+
111
+ const response = handleMiddlewareResult(result, route.filePath, devMode);
112
+ if (response && devMode) {
113
+ console.log(`[middleware] Chain terminated by ${route.filePath}`);
114
+ }
115
+ return response;
116
+ }
117
+
118
+ /**
119
+ * Executes route-scoped middleware chain for a request
120
+ *
121
+ * 1. Finds middleware that matches the request URL
122
+ * 2. Executes them in priority order (parent before child)
123
+ * 3. Handles void return (continue) and Response return (terminate)
124
+ * 4. Propagates errors to Nitro's error handling
125
+ * 5. Preserves event.context modifications across the chain
126
+ * 6. Logs context changes in development mode
127
+ *
128
+ * @param event - H3 event object from Nitro
129
+ * @param routes - Discovered middleware routes from discoverScopedMiddleware
130
+ * @param options - Execution options
131
+ * @returns Response if middleware terminated the chain, undefined otherwise
132
+ */
133
+ export async function executeScopedMiddleware(
134
+ event: H3Event,
135
+ routes: MiddlewareRoute[],
136
+ options: MiddlewareExecutorOptions = {},
137
+ ): Promise<Response | undefined> {
138
+ const { devMode, timeout } = { ...DEFAULT_OPTIONS, ...options };
139
+
140
+ const url = buildUrlFromEvent(event);
141
+ const matchingRoutes = getMatchingMiddleware(routes, url);
142
+
143
+ if (matchingRoutes.length === 0) {
144
+ return undefined;
145
+ }
146
+
147
+ for (const route of matchingRoutes) {
148
+ try {
149
+ const response = await executeMiddlewareRoute(event, route, devMode, timeout);
150
+ if (response) return response;
151
+ } catch (error) {
152
+ if (devMode) {
153
+ console.error(`[middleware] Error in ${route.filePath}:`, error);
154
+ }
155
+ throw error;
156
+ }
157
+ }
158
+
159
+ return undefined;
160
+ }
161
+
162
+ /**
163
+ * Builds a URL object from an H3 event.
164
+ * Supports both h3 v2 (event.url / event.req.url) and the dev-mode mock shape (event.path).
165
+ */
166
+ function buildUrlFromEvent(event: H3Event): URL {
167
+ const base = 'http://localhost';
168
+
169
+ // h3 v2: event.url is a string
170
+ if (typeof (event as any).url === 'string') {
171
+ return new URL((event as any).url, base);
172
+ }
173
+
174
+ // h3 v2: event.req is a Web Request
175
+ if ((event as any).req?.url) {
176
+ return new URL((event as any).req.url, base);
177
+ }
178
+
179
+ // Dev-mode mock: event.path
180
+ if ((event as any).path) {
181
+ return new URL((event as any).path, base);
182
+ }
183
+
184
+ // Legacy h3 v1: event.node.req.url
185
+ if ((event as any).node?.req?.url) {
186
+ return new URL((event as any).node.req.url, base);
187
+ }
188
+
189
+ return new URL('/', base);
190
+ }
191
+
192
+ /**
193
+ * Converts an absolute file path to a valid ESM import specifier.
194
+ * Windows absolute paths (C:\...) are converted to file:// URLs.
195
+ * On Unix, the path is returned as-is (no-op).
196
+ */
197
+ export function toImportSpecifier(filePath: string): string {
198
+ if (/^[A-Za-z]:[\\/]/.test(filePath)) {
199
+ return `file:///${filePath.replaceAll('\\', '/')}`;
200
+ }
201
+ return filePath;
202
+ }
203
+
204
+ /**
205
+ * Loads a middleware handler via Vite's ssrLoadModule (dev) or dynamic import (prod/worker).
206
+ */
207
+ async function loadMiddleware(filePath: string, devMode: boolean): Promise<MiddlewareHandler | null> {
208
+ if (!devMode && middlewareCache.has(filePath)) {
209
+ return middlewareCache.get(filePath)!;
210
+ }
211
+
212
+ try {
213
+ let module: MiddlewareFileExport;
214
+
215
+ const viteServer = globalThis.__viteDevServer;
216
+ if (devMode && viteServer) {
217
+ const viteRoot = viteServer.config.root || '';
218
+ const vitePath = filePath.startsWith(viteRoot) ? '/' + filePath.slice(viteRoot.length + 1) : filePath;
219
+ module = (await viteServer.ssrLoadModule(vitePath)) as MiddlewareFileExport;
220
+ } else {
221
+ const importPath = toImportSpecifier(filePath);
222
+ module = (await import(/* @vite-ignore */ importPath)) as MiddlewareFileExport;
223
+ }
224
+
225
+ if (!module.default || typeof module.default !== 'function') {
226
+ if (devMode) {
227
+ console.warn(`[middleware] ${filePath} does not export a default function`);
228
+ }
229
+ return null;
230
+ }
231
+
232
+ if (!devMode) {
233
+ middlewareCache.set(filePath, module.default);
234
+ }
235
+
236
+ return module.default;
237
+ } catch (error) {
238
+ if (devMode) {
239
+ console.error(`[middleware] Failed to load ${filePath}:`, error);
240
+ }
241
+ return null;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Executes a middleware handler with a timeout
247
+ */
248
+ async function executeWithTimeout<T>(fn: () => T | Promise<T>, timeout: number, filePath: string): Promise<T> {
249
+ return Promise.race([
250
+ Promise.resolve(fn()),
251
+ new Promise<never>((_, reject) => {
252
+ setTimeout(() => {
253
+ reject(new Error(`Middleware timeout after ${timeout}ms: ${filePath}`));
254
+ }, timeout);
255
+ }),
256
+ ]);
257
+ }
258
+
259
+ /**
260
+ * Handles the result of a middleware execution.
261
+ * Supports Nitro-style (void/Response) format.
262
+ */
263
+ function handleMiddlewareResult(result: unknown, filePath: string, devMode: boolean): Response | undefined {
264
+ if (result === undefined || result === null) {
265
+ return undefined;
266
+ }
267
+
268
+ if (result instanceof Response) {
269
+ return result;
270
+ }
271
+
272
+ if (devMode) {
273
+ console.warn(
274
+ `[middleware] ${filePath} returned unexpected value: ${typeof result}. ` +
275
+ `Expected void or Response.`,
276
+ );
277
+ }
278
+
279
+ return undefined;
280
+ }
281
+
282
+ /** Clears the middleware cache (e.g. during hot reload) */
283
+ export function clearMiddlewareCache(): void {
284
+ middlewareCache.clear();
285
+ }
286
+
287
+ /** Removes a specific middleware from the cache */
288
+ export function invalidateMiddleware(filePath: string): boolean {
289
+ return middlewareCache.delete(filePath);
290
+ }
291
+
292
+ /** Gets the current size of the middleware cache */
293
+ export function getMiddlewareCacheSize(): number {
294
+ return middlewareCache.size;
295
+ }
296
+
297
+ /** Checks if a key exists in event.context */
298
+ export function hasContextValue(event: H3Event, key: string): boolean {
299
+ return key in event.context;
300
+ }
301
+
302
+ /** Gets a typed value from event.context */
303
+ export function getContextValue<T>(event: H3Event, key: string): T | undefined {
304
+ return event.context[key] as T | undefined;
305
+ }
306
+
307
+ /** Sets a value in event.context with optional development logging */
308
+ export function setContextValue<T>(event: H3Event, key: string, value: T, devMode: boolean = false): void {
309
+ const isNew = !(key in event.context);
310
+ event.context[key] = value;
311
+
312
+ if (devMode) {
313
+ console.log(`[middleware] Context ${isNew ? 'set' : 'updated'}: ${key}`);
314
+ }
315
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Avalon Middleware Module
3
+ *
4
+ * This module provides a Nitro-aligned middleware system for Avalon that supports
5
+ * both global middleware (via Nitro's middleware/ directory) and route-scoped
6
+ * middleware (via _middleware.ts files in page/API directories).
7
+ *
8
+ * Key features:
9
+ * - Nitro-compatible handler signature: return void to continue, return Response to terminate
10
+ * - Route-scoped middleware discovery in src/pages/ and src/api/
11
+ * - Priority-based execution order (parent before child)
12
+ * - Type-safe context augmentation for H3 events
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * // Define middleware with proper typing
17
+ * import { defineMiddleware } from 'avalon/middleware';
18
+ * import { getHeader, createError } from 'h3';
19
+ *
20
+ * export default defineMiddleware(async (event) => {
21
+ * const token = getHeader(event, 'Authorization');
22
+ * if (!token) {
23
+ * throw createError({ statusCode: 401, message: 'Unauthorized' });
24
+ * }
25
+ * event.context.user = await validateToken(token);
26
+ * });
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // Discover and execute middleware in your server
32
+ * import { discoverScopedMiddleware, executeScopedMiddleware } from 'avalon/middleware';
33
+ *
34
+ * const routes = await discoverScopedMiddleware({ baseDir: 'src', devMode: true });
35
+ * const response = await executeScopedMiddleware(event, routes);
36
+ * if (response) return response;
37
+ * ```
38
+ *
39
+ * Requirements: 4.3
40
+ */
41
+
42
+ // =============================================================================
43
+ // Type Exports
44
+ // =============================================================================
45
+
46
+ export type {
47
+ MiddlewareHandler,
48
+ MiddlewareFileExport,
49
+ MiddlewareRoute,
50
+ MiddlewareDiscoveryOptions,
51
+ MiddlewareExecutorOptions,
52
+ } from './types.ts';
53
+
54
+ // =============================================================================
55
+ // Helper Functions (defineMiddleware removed — use defineHandler from 'nitro/h3')
56
+ // =============================================================================
57
+
58
+ // =============================================================================
59
+ // Discovery Functions
60
+ // =============================================================================
61
+
62
+ export { discoverScopedMiddleware, getMatchingMiddleware, clearDiscoveryCache } from './discovery.ts';
63
+
64
+ // =============================================================================
65
+ // Executor Functions
66
+ // =============================================================================
67
+
68
+ export {
69
+ executeScopedMiddleware,
70
+ clearMiddlewareCache,
71
+ invalidateMiddleware,
72
+ getMiddlewareCacheSize,
73
+ hasContextValue,
74
+ getContextValue,
75
+ setContextValue,
76
+ } from './executor.ts';
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Nitro-Aligned Middleware Types
3
+ *
4
+ * This module defines types for Avalon's middleware system that align with
5
+ * Nitro's conventions while preserving route-scoped middleware features.
6
+ *
7
+ * Key differences from old middleware system:
8
+ * - Handler signature: (event: H3Event) => void | Response | Promise<void | Response>
9
+ * - Return void to continue, return Response to terminate
10
+ * - Uses event.context for data passing instead of custom state/locals
11
+ *
12
+ * Requirements: 1.1
13
+ */
14
+
15
+ import type { H3Event } from 'h3';
16
+
17
+ /**
18
+ * Nitro-aligned middleware handler signature
19
+ *
20
+ * This signature matches Nitro's middleware conventions:
21
+ * - Return nothing (void/undefined) to continue to next middleware
22
+ * - Return a Response to terminate the chain and send that response
23
+ * - Throw an error to trigger Nitro's error handling
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const handler: MiddlewareHandler = async (event) => {
28
+ * // Check auth
29
+ * if (!event.context.user) {
30
+ * return new Response('Unauthorized', { status: 401 });
31
+ * }
32
+ * // Continue to next middleware
33
+ * };
34
+ * ```
35
+ */
36
+ export type MiddlewareHandler = (
37
+ event: H3Event
38
+ ) => void | Response | Promise<void | Response>;
39
+
40
+ /**
41
+ * Route-scoped middleware file export interface
42
+ *
43
+ * Middleware files should export a default function matching the MiddlewareHandler signature.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * // src/pages/admin/_middleware.ts
48
+ * export default async (event) => {
49
+ * // middleware logic
50
+ * };
51
+ * ```
52
+ */
53
+ export interface MiddlewareFileExport {
54
+ /** Default export must be a MiddlewareHandler function */
55
+ default: MiddlewareHandler;
56
+ }
57
+
58
+ /**
59
+ * Discovered middleware route configuration
60
+ *
61
+ * Represents a middleware file discovered during scanning, with its
62
+ * URL pattern, file path, execution priority, and type.
63
+ */
64
+ export interface MiddlewareRoute {
65
+ /** URL pattern for matching requests */
66
+ pattern: URLPattern;
67
+ /** Absolute path to the middleware file */
68
+ filePath: string;
69
+ /** Execution priority (lower numbers execute first) */
70
+ priority: number;
71
+ /** Middleware type - determines which routes it applies to */
72
+ type: 'global' | 'pages';
73
+ }
74
+
75
+ /**
76
+ * Middleware discovery options
77
+ */
78
+ export interface MiddlewareDiscoveryOptions {
79
+ /** Base directory to scan (e.g., 'src') */
80
+ baseDir: string;
81
+ /** File pattern to match (default: '_middleware.ts') */
82
+ filePattern?: string;
83
+ /** Directories to exclude from scanning */
84
+ excludeDirs?: string[];
85
+ /** Enable development mode logging */
86
+ devMode?: boolean;
87
+ }
88
+
89
+ /**
90
+ * Middleware execution options
91
+ */
92
+ export interface MiddlewareExecutorOptions {
93
+ /** Enable development mode logging */
94
+ devMode?: boolean;
95
+ /** Timeout for middleware execution in milliseconds */
96
+ timeout?: number;
97
+ }
98
+
99
+