@useavalon/avalon 0.1.13 → 0.1.14
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,268 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simplified Middleware Discovery
|
|
3
|
-
*
|
|
4
|
-
* This module provides a streamlined middleware discovery system that scans
|
|
5
|
-
* for _middleware.ts files in src/pages/ directories.
|
|
6
|
-
*
|
|
7
|
-
* Key features:
|
|
8
|
-
* - Scans src/pages/ for page middleware
|
|
9
|
-
* - Calculates priority based on directory depth (parent before child)
|
|
10
|
-
* - Creates URL patterns for route matching
|
|
11
|
-
*
|
|
12
|
-
* Note: API middleware is handled natively by Nitro and is not scanned here.
|
|
13
|
-
*
|
|
14
|
-
* Requirements: 3.1, 3.2, 3.3, 3.4
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { join, relative, resolve } from 'node:path';
|
|
18
|
-
import { stat as fsStat, readdir } from 'node:fs/promises';
|
|
19
|
-
import type { MiddlewareRoute, MiddlewareDiscoveryOptions } from './types.ts';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Default options for middleware discovery
|
|
23
|
-
*/
|
|
24
|
-
const DEFAULT_OPTIONS: Required<Omit<MiddlewareDiscoveryOptions, 'baseDir'>> = {
|
|
25
|
-
filePattern: '_middleware.ts',
|
|
26
|
-
excludeDirs: ['node_modules', '.git', 'dist', '.output', '.vite'],
|
|
27
|
-
devMode: false,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Base priority values for different middleware types
|
|
32
|
-
* Lower values execute first
|
|
33
|
-
*/
|
|
34
|
-
const PRIORITY_BASE = {
|
|
35
|
-
/** Page middleware base priority */
|
|
36
|
-
pages: 50,
|
|
37
|
-
} as const;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Discovers route-scoped middleware files in the project
|
|
41
|
-
*
|
|
42
|
-
* Scans for _middleware.ts files in:
|
|
43
|
-
* - src/pages/ directory (and subdirectories) for page routes
|
|
44
|
-
*
|
|
45
|
-
* API middleware is handled natively by Nitro and is not scanned here.
|
|
46
|
-
*
|
|
47
|
-
* Middleware files are sorted by priority (directory depth), ensuring
|
|
48
|
-
* parent middleware executes before child middleware.
|
|
49
|
-
*
|
|
50
|
-
* @param options - Discovery options
|
|
51
|
-
* @returns Array of discovered middleware routes, sorted by priority
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```ts
|
|
55
|
-
* const routes = await discoverScopedMiddleware({
|
|
56
|
-
* baseDir: 'src',
|
|
57
|
-
* devMode: true,
|
|
58
|
-
* });
|
|
59
|
-
*
|
|
60
|
-
* // Returns routes like:
|
|
61
|
-
* // [
|
|
62
|
-
* // { pattern: URLPattern('/blog/*'), filePath: 'src/pages/blog/_middleware.ts', priority: 51, type: 'pages' },
|
|
63
|
-
* // ]
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export async function discoverScopedMiddleware(
|
|
67
|
-
options: MiddlewareDiscoveryOptions
|
|
68
|
-
): Promise<MiddlewareRoute[]> {
|
|
69
|
-
const {
|
|
70
|
-
baseDir,
|
|
71
|
-
filePattern = DEFAULT_OPTIONS.filePattern,
|
|
72
|
-
excludeDirs = DEFAULT_OPTIONS.excludeDirs,
|
|
73
|
-
devMode = DEFAULT_OPTIONS.devMode,
|
|
74
|
-
} = options;
|
|
75
|
-
|
|
76
|
-
const resolvedBaseDir = resolve(baseDir);
|
|
77
|
-
const routes: MiddlewareRoute[] = [];
|
|
78
|
-
|
|
79
|
-
// Scan pages directory for page middleware
|
|
80
|
-
const pagesDir = join(resolvedBaseDir, 'pages');
|
|
81
|
-
await scanDirectory(pagesDir, 'pages', filePattern, excludeDirs, routes, devMode);
|
|
82
|
-
|
|
83
|
-
// Sort by priority (lower numbers execute first)
|
|
84
|
-
routes.sort((a, b) => a.priority - b.priority);
|
|
85
|
-
|
|
86
|
-
if (devMode && routes.length > 0) {
|
|
87
|
-
console.log(`[middleware] Discovered ${routes.length} route-scoped middleware:`);
|
|
88
|
-
for (const route of routes) {
|
|
89
|
-
console.log(` - ${route.type}: ${route.filePath} (priority: ${route.priority})`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return routes;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Scans a directory recursively for middleware files
|
|
98
|
-
*
|
|
99
|
-
* @param dir - Directory to scan
|
|
100
|
-
* @param type - Middleware type ('pages')
|
|
101
|
-
* @param filePattern - File pattern to match
|
|
102
|
-
* @param excludeDirs - Directories to exclude
|
|
103
|
-
* @param routes - Array to collect discovered routes
|
|
104
|
-
* @param devMode - Whether to log debug information
|
|
105
|
-
*/
|
|
106
|
-
async function scanDirectory(
|
|
107
|
-
dir: string,
|
|
108
|
-
type: 'pages',
|
|
109
|
-
filePattern: string,
|
|
110
|
-
excludeDirs: string[],
|
|
111
|
-
routes: MiddlewareRoute[],
|
|
112
|
-
devMode: boolean
|
|
113
|
-
): Promise<void> {
|
|
114
|
-
try {
|
|
115
|
-
// Check if directory exists
|
|
116
|
-
const dirInfo = await fsStat(dir).catch(() => null);
|
|
117
|
-
if (!dirInfo?.isDirectory()) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Recursively scan directory
|
|
122
|
-
await scanDirectoryRecursive(dir, dir, type, filePattern, excludeDirs, routes, devMode);
|
|
123
|
-
} catch (error) {
|
|
124
|
-
// Directory doesn't exist or can't be read - skip silently
|
|
125
|
-
if (devMode && (!(error instanceof Error) || (error as NodeJS.ErrnoException).code !== 'ENOENT')) {
|
|
126
|
-
console.warn(`[middleware] Error scanning ${dir}: ${error instanceof Error ? error.message : String(error)}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Recursively scans a directory for middleware files
|
|
133
|
-
*
|
|
134
|
-
* @param rootDir - Root directory being scanned
|
|
135
|
-
* @param currentDir - Current directory being scanned
|
|
136
|
-
* @param type - Middleware type
|
|
137
|
-
* @param filePattern - File pattern to match
|
|
138
|
-
* @param excludeDirs - Directories to exclude
|
|
139
|
-
* @param routes - Array to collect discovered routes
|
|
140
|
-
* @param devMode - Whether to log debug information
|
|
141
|
-
*/
|
|
142
|
-
async function scanDirectoryRecursive(
|
|
143
|
-
rootDir: string,
|
|
144
|
-
currentDir: string,
|
|
145
|
-
type: 'pages',
|
|
146
|
-
filePattern: string,
|
|
147
|
-
excludeDirs: string[],
|
|
148
|
-
routes: MiddlewareRoute[],
|
|
149
|
-
devMode: boolean
|
|
150
|
-
): Promise<void> {
|
|
151
|
-
try {
|
|
152
|
-
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
153
|
-
for (const entry of entries) {
|
|
154
|
-
const fullPath = join(currentDir, entry.name);
|
|
155
|
-
|
|
156
|
-
// Skip excluded directories
|
|
157
|
-
if (entry.isDirectory() && excludeDirs.includes(entry.name)) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (entry.isDirectory()) {
|
|
162
|
-
// Recursively scan subdirectories
|
|
163
|
-
await scanDirectoryRecursive(rootDir, fullPath, type, filePattern, excludeDirs, routes, devMode);
|
|
164
|
-
} else if (entry.name === filePattern) {
|
|
165
|
-
// Found a middleware file
|
|
166
|
-
const relativePath = relative(rootDir, currentDir);
|
|
167
|
-
const route = createMiddlewareRoute(fullPath, relativePath, type);
|
|
168
|
-
routes.push(route);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
} catch (error) {
|
|
172
|
-
if (devMode && (!(error instanceof Error) || (error as NodeJS.ErrnoException).code !== 'ENOENT')) {
|
|
173
|
-
console.warn(`[middleware] Error reading ${currentDir}: ${error instanceof Error ? error.message : String(error)}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Creates a middleware route configuration from a file path
|
|
180
|
-
*
|
|
181
|
-
* @param filePath - Absolute path to the middleware file
|
|
182
|
-
* @param relativePath - Path relative to the pages directory
|
|
183
|
-
* @param type - Middleware type
|
|
184
|
-
* @returns Middleware route configuration
|
|
185
|
-
*
|
|
186
|
-
* @example
|
|
187
|
-
* ```ts
|
|
188
|
-
* // For src/pages/blog/_middleware.ts
|
|
189
|
-
* createMiddlewareRoute('/abs/path/src/pages/blog/_middleware.ts', 'blog', 'pages')
|
|
190
|
-
* // Returns: { pattern: URLPattern('/blog/*'), filePath: '...', priority: 51, type: 'pages' }
|
|
191
|
-
* ```
|
|
192
|
-
*/
|
|
193
|
-
function createMiddlewareRoute(
|
|
194
|
-
filePath: string,
|
|
195
|
-
relativePath: string,
|
|
196
|
-
type: 'pages'
|
|
197
|
-
): MiddlewareRoute {
|
|
198
|
-
// Calculate URL pattern from relative path
|
|
199
|
-
// relativePath is the directory path relative to pages/
|
|
200
|
-
// e.g., 'blog' for src/pages/blog/_middleware.ts
|
|
201
|
-
// e.g., '' for src/pages/_middleware.ts (root middleware)
|
|
202
|
-
|
|
203
|
-
// Page middleware: /* or /blog{/*}?
|
|
204
|
-
// Use {/*}? to match both /blog and /blog/anything
|
|
205
|
-
const urlPattern = relativePath ? `/${relativePath}{/*}?` : '/*';
|
|
206
|
-
|
|
207
|
-
// Calculate priority based on directory depth
|
|
208
|
-
// Shallower directories have lower priority (execute first)
|
|
209
|
-
const depth = relativePath ? relativePath.split('/').filter(Boolean).length : 0;
|
|
210
|
-
const priority = PRIORITY_BASE[type] + depth;
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
pattern: new URLPattern({ pathname: urlPattern }),
|
|
214
|
-
filePath,
|
|
215
|
-
priority,
|
|
216
|
-
type,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Gets middleware routes that match a given URL
|
|
222
|
-
*
|
|
223
|
-
* Filters discovered routes to only include those that match the URL,
|
|
224
|
-
* respecting type isolation (page middleware doesn't run for API routes
|
|
225
|
-
* and vice versa).
|
|
226
|
-
*
|
|
227
|
-
* @param routes - All discovered middleware routes
|
|
228
|
-
* @param url - URL to match against
|
|
229
|
-
* @returns Matching routes, sorted by priority
|
|
230
|
-
*
|
|
231
|
-
* @example
|
|
232
|
-
* ```ts
|
|
233
|
-
* const allRoutes = await discoverScopedMiddleware({ baseDir: 'src' });
|
|
234
|
-
* const matchingRoutes = getMatchingMiddleware(allRoutes, new URL('http://localhost/blog/post-1'));
|
|
235
|
-
* ```
|
|
236
|
-
*/
|
|
237
|
-
export function getMatchingMiddleware(
|
|
238
|
-
routes: MiddlewareRoute[],
|
|
239
|
-
url: URL
|
|
240
|
-
): MiddlewareRoute[] {
|
|
241
|
-
const isApiRoute = url.pathname.startsWith('/api');
|
|
242
|
-
|
|
243
|
-
return routes.filter(route => {
|
|
244
|
-
// Check if pattern matches the URL
|
|
245
|
-
if (!route.pattern.test(url)) {
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Type isolation: page middleware doesn't run for API routes
|
|
250
|
-
if (route.type === 'pages' && isApiRoute) {
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return true;
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Clears the middleware discovery cache
|
|
260
|
-
*
|
|
261
|
-
* This is a no-op in the simplified discovery module since we don't
|
|
262
|
-
* maintain a persistent cache. The function is provided for API
|
|
263
|
-
* compatibility with the executor module.
|
|
264
|
-
*/
|
|
265
|
-
export function clearDiscoveryCache(): void {
|
|
266
|
-
// No-op: simplified discovery doesn't maintain a persistent cache
|
|
267
|
-
// Each call to discoverScopedMiddleware scans the file system
|
|
268
|
-
}
|
|
@@ -1,315 +0,0 @@
|
|
|
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
|
-
}
|
package/src/middleware/index.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
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';
|