@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.
- package/README.md +54 -0
- package/mod.ts +301 -0
- package/package.json +85 -0
- package/src/build/README.md +310 -0
- package/src/build/integration-bundler-plugin.ts +116 -0
- package/src/build/integration-config.ts +168 -0
- package/src/build/integration-detection-plugin.ts +117 -0
- package/src/build/integration-resolver-plugin.ts +90 -0
- package/src/build/island-manifest.ts +269 -0
- package/src/build/island-types-generator.ts +476 -0
- package/src/build/mdx-island-transform.ts +464 -0
- package/src/build/mdx-plugin.ts +98 -0
- package/src/build/page-island-transform.ts +598 -0
- package/src/build/prop-extractors/index.ts +21 -0
- package/src/build/prop-extractors/lit.ts +140 -0
- package/src/build/prop-extractors/qwik.ts +16 -0
- package/src/build/prop-extractors/solid.ts +125 -0
- package/src/build/prop-extractors/svelte.ts +194 -0
- package/src/build/prop-extractors/vue.ts +111 -0
- package/src/build/sidecar-file-manager.ts +104 -0
- package/src/build/sidecar-renderer.ts +30 -0
- package/src/client/adapters/index.ts +13 -0
- package/src/client/adapters/lit-adapter.ts +654 -0
- package/src/client/adapters/preact-adapter.ts +331 -0
- package/src/client/adapters/qwik-adapter.ts +345 -0
- package/src/client/adapters/react-adapter.ts +353 -0
- package/src/client/adapters/solid-adapter.ts +451 -0
- package/src/client/adapters/svelte-adapter.ts +524 -0
- package/src/client/adapters/vue-adapter.ts +467 -0
- package/src/client/components.ts +35 -0
- package/src/client/css-hmr-handler.ts +344 -0
- package/src/client/framework-adapter.ts +462 -0
- package/src/client/hmr-coordinator.ts +396 -0
- package/src/client/hmr-error-overlay.js +533 -0
- package/src/client/main.js +816 -0
- package/src/client/tests/css-hmr-handler.test.ts +360 -0
- package/src/client/tests/framework-adapter.test.ts +519 -0
- package/src/client/tests/hmr-coordinator.test.ts +176 -0
- package/src/client/tests/hydration-option-parsing.test.ts +107 -0
- package/src/client/tests/lit-adapter.test.ts +427 -0
- package/src/client/tests/preact-adapter.test.ts +353 -0
- package/src/client/tests/qwik-adapter.test.ts +343 -0
- package/src/client/tests/react-adapter.test.ts +317 -0
- package/src/client/tests/solid-adapter.test.ts +396 -0
- package/src/client/tests/svelte-adapter.test.ts +387 -0
- package/src/client/tests/vue-adapter.test.ts +407 -0
- package/src/client/types/framework-runtime.d.ts +68 -0
- package/src/client/types/vite-hmr.d.ts +46 -0
- package/src/client/types/vite-virtual-modules.d.ts +60 -0
- package/src/components/Image.tsx +123 -0
- package/src/components/IslandErrorBoundary.tsx +145 -0
- package/src/components/LayoutDataErrorBoundary.tsx +141 -0
- package/src/components/LayoutErrorBoundary.tsx +127 -0
- package/src/components/PersistentIsland.tsx +52 -0
- package/src/components/StreamingErrorBoundary.tsx +233 -0
- package/src/components/StreamingLayout.tsx +538 -0
- package/src/components/tests/component-analyzer.test.ts +96 -0
- package/src/components/tests/component-detection.test.ts +347 -0
- package/src/components/tests/persistent-islands.test.ts +398 -0
- package/src/core/components/component-analyzer.ts +192 -0
- package/src/core/components/component-detection.ts +508 -0
- package/src/core/components/enhanced-framework-detector.ts +500 -0
- package/src/core/components/framework-registry.ts +563 -0
- package/src/core/components/tests/enhanced-framework-detector.test.ts +577 -0
- package/src/core/components/tests/framework-registry.test.ts +465 -0
- package/src/core/content/mdx-processor.ts +46 -0
- package/src/core/integrations/README.md +282 -0
- package/src/core/integrations/index.ts +19 -0
- package/src/core/integrations/loader.ts +125 -0
- package/src/core/integrations/registry.ts +195 -0
- package/src/core/islands/island-persistence.ts +325 -0
- package/src/core/islands/island-state-serializer.ts +258 -0
- package/src/core/islands/persistent-island-context.tsx +80 -0
- package/src/core/islands/use-persistent-state.ts +68 -0
- package/src/core/layout/enhanced-layout-resolver.ts +322 -0
- package/src/core/layout/layout-cache-manager.ts +485 -0
- package/src/core/layout/layout-composer.ts +357 -0
- package/src/core/layout/layout-data-loader.ts +516 -0
- package/src/core/layout/layout-discovery.ts +243 -0
- package/src/core/layout/layout-matcher.ts +299 -0
- package/src/core/layout/layout-types.ts +110 -0
- package/src/core/layout/tests/enhanced-layout-resolver.test.ts +477 -0
- package/src/core/layout/tests/layout-cache-optimization.test.ts +149 -0
- package/src/core/layout/tests/layout-composer.test.ts +486 -0
- package/src/core/layout/tests/layout-data-loader.test.ts +443 -0
- package/src/core/layout/tests/layout-discovery.test.ts +253 -0
- package/src/core/layout/tests/layout-matcher.test.ts +480 -0
- package/src/core/modules/framework-module-resolver.ts +273 -0
- package/src/core/modules/tests/framework-module-resolver.test.ts +263 -0
- package/src/core/modules/tests/module-resolution-integration.test.ts +117 -0
- package/src/islands/component-analysis.ts +213 -0
- package/src/islands/css-utils.ts +565 -0
- package/src/islands/discovery/index.ts +80 -0
- package/src/islands/discovery/registry.ts +340 -0
- package/src/islands/discovery/resolver.ts +477 -0
- package/src/islands/discovery/scanner.ts +386 -0
- package/src/islands/discovery/tests/island-discovery.test.ts +881 -0
- package/src/islands/discovery/types.ts +117 -0
- package/src/islands/discovery/validator.ts +544 -0
- package/src/islands/discovery/watcher.ts +368 -0
- package/src/islands/framework-detection.ts +428 -0
- package/src/islands/integration-loader.ts +490 -0
- package/src/islands/island.tsx +565 -0
- package/src/islands/render-cache.ts +550 -0
- package/src/islands/types.ts +80 -0
- package/src/islands/universal-css-collector.ts +157 -0
- package/src/islands/universal-head-collector.ts +137 -0
- package/src/layout-system.d.ts +592 -0
- package/src/layout-system.ts +218 -0
- package/src/middleware/__tests__/discovery.test.ts +107 -0
- package/src/middleware/discovery.ts +268 -0
- package/src/middleware/executor.ts +315 -0
- package/src/middleware/index.ts +76 -0
- package/src/middleware/types.ts +99 -0
- package/src/nitro/build-config.ts +576 -0
- package/src/nitro/config.ts +483 -0
- package/src/nitro/error-handler.ts +636 -0
- package/src/nitro/index.ts +173 -0
- package/src/nitro/island-manifest.ts +584 -0
- package/src/nitro/middleware-adapter.ts +260 -0
- package/src/nitro/renderer.ts +1458 -0
- package/src/nitro/route-discovery.ts +439 -0
- package/src/nitro/types.ts +321 -0
- package/src/render/collect-css.ts +198 -0
- package/src/render/error-pages.ts +79 -0
- package/src/render/isolated-ssr-renderer.ts +654 -0
- package/src/render/ssr.ts +1030 -0
- package/src/schemas/api.ts +30 -0
- package/src/schemas/core.ts +64 -0
- package/src/schemas/index.ts +212 -0
- package/src/schemas/layout.ts +279 -0
- package/src/schemas/routing/index.ts +38 -0
- package/src/schemas/routing.ts +376 -0
- package/src/types/as-island.ts +20 -0
- package/src/types/image.d.ts +106 -0
- package/src/types/index.d.ts +22 -0
- package/src/types/island-jsx.d.ts +33 -0
- package/src/types/island-prop.d.ts +20 -0
- package/src/types/layout.ts +285 -0
- package/src/types/mdx.d.ts +6 -0
- package/src/types/routing.ts +555 -0
- package/src/types/tests/layout-types.test.ts +197 -0
- package/src/types/types.ts +5 -0
- package/src/types/urlpattern.d.ts +49 -0
- package/src/types/vite-env.d.ts +11 -0
- package/src/utils/dev-logger.ts +299 -0
- package/src/utils/fs.ts +151 -0
- package/src/vite-plugin/auto-discover.ts +551 -0
- package/src/vite-plugin/config.ts +266 -0
- package/src/vite-plugin/errors.ts +127 -0
- package/src/vite-plugin/image-optimization.ts +151 -0
- package/src/vite-plugin/integration-activator.ts +126 -0
- package/src/vite-plugin/island-sidecar-plugin.ts +176 -0
- package/src/vite-plugin/module-discovery.ts +189 -0
- package/src/vite-plugin/nitro-integration.ts +1334 -0
- package/src/vite-plugin/plugin.ts +329 -0
- package/src/vite-plugin/tests/image-optimization.test.ts +54 -0
- package/src/vite-plugin/types.ts +327 -0
- package/src/vite-plugin/validation.ts +228 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported HTTP methods for API routes
|
|
5
|
+
*/
|
|
6
|
+
export const ApiMethodSchema = z.enum([
|
|
7
|
+
'GET',
|
|
8
|
+
'POST',
|
|
9
|
+
'PUT',
|
|
10
|
+
'DELETE',
|
|
11
|
+
'PATCH',
|
|
12
|
+
'HEAD',
|
|
13
|
+
'OPTIONS',
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
export type ApiMethod = z.infer<typeof ApiMethodSchema>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Discovered API route with metadata
|
|
20
|
+
*/
|
|
21
|
+
export interface ApiRoute {
|
|
22
|
+
/** URL pattern for matching requests */
|
|
23
|
+
pattern: URLPattern;
|
|
24
|
+
/** Route configuration with handlers */
|
|
25
|
+
config: unknown;
|
|
26
|
+
/** Original file path relative to src/api */
|
|
27
|
+
filePath: string;
|
|
28
|
+
/** Extracted dynamic parameter names */
|
|
29
|
+
paramNames: string[];
|
|
30
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Schema for meta tags
|
|
5
|
+
*/
|
|
6
|
+
export const MetaTagSchema = z.object({
|
|
7
|
+
name: z.string().min(1),
|
|
8
|
+
content: z.string(),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Script configuration schema - supports both simple URLs and complex script objects
|
|
13
|
+
*/
|
|
14
|
+
export const ScriptConfigSchema = z.union([
|
|
15
|
+
// Simple string URL (backward compatible)
|
|
16
|
+
z.string().min(1),
|
|
17
|
+
// Complex script object with attributes
|
|
18
|
+
z
|
|
19
|
+
.object({
|
|
20
|
+
src: z.string().min(1).optional(),
|
|
21
|
+
content: z.string().optional(), // For inline scripts
|
|
22
|
+
data: z.union([z.record(z.string(), z.unknown()), z.array(z.unknown()), z.string()]).optional(), // For structured data (JSON-LD)
|
|
23
|
+
type: z.string().optional(),
|
|
24
|
+
async: z.boolean().optional(),
|
|
25
|
+
defer: z.boolean().optional(),
|
|
26
|
+
crossorigin: z.enum(['anonymous', 'use-credentials']).optional(),
|
|
27
|
+
integrity: z.string().optional(),
|
|
28
|
+
nomodule: z.boolean().optional(),
|
|
29
|
+
referrerpolicy: z
|
|
30
|
+
.enum([
|
|
31
|
+
'no-referrer',
|
|
32
|
+
'no-referrer-when-downgrade',
|
|
33
|
+
'origin',
|
|
34
|
+
'origin-when-cross-origin',
|
|
35
|
+
'same-origin',
|
|
36
|
+
'strict-origin',
|
|
37
|
+
'strict-origin-when-cross-origin',
|
|
38
|
+
'unsafe-url',
|
|
39
|
+
])
|
|
40
|
+
.optional(),
|
|
41
|
+
// Allow custom attributes
|
|
42
|
+
attributes: z.record(z.string(), z.string()).optional(),
|
|
43
|
+
})
|
|
44
|
+
.refine(data => data.src || data.content || data.data, {
|
|
45
|
+
message: "Script must have either 'src', 'content', or 'data'",
|
|
46
|
+
}),
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Simplified render options for Vite-powered architecture
|
|
51
|
+
*/
|
|
52
|
+
export const RenderOptionsSchema = z.object({
|
|
53
|
+
title: z.string().optional(),
|
|
54
|
+
scripts: z.array(ScriptConfigSchema).optional(),
|
|
55
|
+
styles: z.array(z.string().min(1)).optional(),
|
|
56
|
+
meta: z.array(MetaTagSchema).optional(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
// === Simplified TypeScript types ===
|
|
61
|
+
|
|
62
|
+
export type MetaTag = z.infer<typeof MetaTagSchema>;
|
|
63
|
+
export type ScriptConfig = z.infer<typeof ScriptConfigSchema>;
|
|
64
|
+
export type RenderOptions = z.infer<typeof RenderOptionsSchema>;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RenderOptionsSchema } from './core.ts';
|
|
3
|
+
import {
|
|
4
|
+
LayoutContextSchema,
|
|
5
|
+
LayoutDataSchema,
|
|
6
|
+
LayoutHandlerSchema,
|
|
7
|
+
LayoutDiscoveryOptionsSchema as LayoutDiscoverySchema,
|
|
8
|
+
LayoutConfigSchema,
|
|
9
|
+
ResolvedLayoutSchema,
|
|
10
|
+
} from './layout.ts';
|
|
11
|
+
import {
|
|
12
|
+
FileSystemRouteSchema,
|
|
13
|
+
RoutePageModuleSchema,
|
|
14
|
+
RouteDiscoveryOptionsSchema,
|
|
15
|
+
FileSystemRouterConfigSchema,
|
|
16
|
+
MetadataSchema,
|
|
17
|
+
ResolvedMetadataSchema,
|
|
18
|
+
} from './routing.ts';
|
|
19
|
+
import type { RenderOptions } from './core.ts';
|
|
20
|
+
import type {
|
|
21
|
+
LayoutContext,
|
|
22
|
+
LayoutData,
|
|
23
|
+
LayoutHandler,
|
|
24
|
+
LayoutDiscoveryOptions,
|
|
25
|
+
LayoutConfig,
|
|
26
|
+
ResolvedLayout,
|
|
27
|
+
} from './layout.ts';
|
|
28
|
+
import type {
|
|
29
|
+
FileSystemRoute,
|
|
30
|
+
RoutePageModule,
|
|
31
|
+
RouteDiscoveryOptions,
|
|
32
|
+
FileSystemRouterConfig,
|
|
33
|
+
Metadata,
|
|
34
|
+
ResolvedMetadata,
|
|
35
|
+
} from './routing.ts';
|
|
36
|
+
|
|
37
|
+
export * from './core.ts';
|
|
38
|
+
export * from './api.ts';
|
|
39
|
+
export * from './layout.ts';
|
|
40
|
+
export * from './routing.ts';
|
|
41
|
+
|
|
42
|
+
export interface ValidationSuccess<T> {
|
|
43
|
+
success: true;
|
|
44
|
+
data: T;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ValidationFailure {
|
|
48
|
+
success: false;
|
|
49
|
+
error: ValidationError;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;
|
|
53
|
+
|
|
54
|
+
export class ValidationError extends Error {
|
|
55
|
+
constructor(message: string, public readonly zodError: z.ZodError) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = 'ValidationError';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getFormattedErrors(): string[] {
|
|
61
|
+
return this.zodError.issues.map((issue): string => {
|
|
62
|
+
const path = issue.path.length > 0 ? `${issue.path.join('.')}: ` : '';
|
|
63
|
+
return `${path}${issue.message}`;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getErrorMessage(): string {
|
|
68
|
+
return this.getFormattedErrors().join('; ');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createValidationError(message: string, zodError: z.ZodError): ValidationError {
|
|
73
|
+
return new ValidationError(message, zodError);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function safeValidate<TOutput>(
|
|
77
|
+
schema: z.ZodType<TOutput>,
|
|
78
|
+
data: unknown,
|
|
79
|
+
errorMessage = 'Validation failed'
|
|
80
|
+
): ValidationResult<TOutput> {
|
|
81
|
+
const result = schema.safeParse(data);
|
|
82
|
+
if (result.success) {
|
|
83
|
+
return { success: true, data: result.data };
|
|
84
|
+
}
|
|
85
|
+
return { success: false, error: createValidationError(errorMessage, result.error) };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function validate<TOutput>(
|
|
89
|
+
schema: z.ZodType<TOutput>,
|
|
90
|
+
data: unknown,
|
|
91
|
+
errorMessage = 'Validation failed'
|
|
92
|
+
): TOutput {
|
|
93
|
+
const result = schema.safeParse(data);
|
|
94
|
+
if (result.success) {
|
|
95
|
+
return result.data;
|
|
96
|
+
}
|
|
97
|
+
throw createValidationError(errorMessage, result.error);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const validators = {
|
|
101
|
+
renderOptions: (data: unknown): RenderOptions => validate(RenderOptionsSchema, data, 'Invalid render options'),
|
|
102
|
+
layoutContext: (data: unknown): LayoutContext => validate(LayoutContextSchema, data, 'Invalid layout context'),
|
|
103
|
+
layoutData: (data: unknown): LayoutData => validate(LayoutDataSchema, data, 'Invalid layout data'),
|
|
104
|
+
layoutHandler: (data: unknown): LayoutHandler => validate(LayoutHandlerSchema, data, 'Invalid layout handler'),
|
|
105
|
+
layoutDiscoveryOptions: (data: unknown): LayoutDiscoveryOptions => validate(LayoutDiscoverySchema, data, 'Invalid layout discovery options'),
|
|
106
|
+
layoutConfig: (data: unknown): LayoutConfig => validate(LayoutConfigSchema, data, 'Invalid layout config'),
|
|
107
|
+
resolvedLayout: (data: unknown): ResolvedLayout => validate(ResolvedLayoutSchema, data, 'Invalid resolved layout'),
|
|
108
|
+
fileSystemRoute: (data: unknown): FileSystemRoute => validate(FileSystemRouteSchema, data, 'Invalid file system route'),
|
|
109
|
+
routePageModule: (data: unknown): RoutePageModule => validate(RoutePageModuleSchema, data, 'Invalid route page module'),
|
|
110
|
+
routeDiscoveryOptions: (data: unknown): RouteDiscoveryOptions => validate(RouteDiscoveryOptionsSchema, data, 'Invalid route discovery options'),
|
|
111
|
+
fileSystemRouterConfig: (data: unknown): FileSystemRouterConfig => validate(FileSystemRouterConfigSchema, data, 'Invalid file system router config'),
|
|
112
|
+
metadata: (data: unknown): Metadata => validate(MetadataSchema, data, 'Invalid metadata'),
|
|
113
|
+
resolvedMetadata: (data: unknown): ResolvedMetadata => validate(ResolvedMetadataSchema, data, 'Invalid resolved metadata'),
|
|
114
|
+
} as const;
|
|
115
|
+
|
|
116
|
+
export const safeValidators = {
|
|
117
|
+
renderOptions: (data: unknown): ValidationResult<RenderOptions> => safeValidate(RenderOptionsSchema, data, 'Invalid render options'),
|
|
118
|
+
layoutContext: (data: unknown): ValidationResult<LayoutContext> => safeValidate(LayoutContextSchema, data, 'Invalid layout context'),
|
|
119
|
+
layoutData: (data: unknown): ValidationResult<LayoutData> => safeValidate(LayoutDataSchema, data, 'Invalid layout data'),
|
|
120
|
+
layoutHandler: (data: unknown): ValidationResult<LayoutHandler> => safeValidate(LayoutHandlerSchema, data, 'Invalid layout handler'),
|
|
121
|
+
layoutDiscoveryOptions: (data: unknown): ValidationResult<LayoutDiscoveryOptions> => safeValidate(LayoutDiscoverySchema, data, 'Invalid layout discovery options'),
|
|
122
|
+
layoutConfig: (data: unknown): ValidationResult<LayoutConfig> => safeValidate(LayoutConfigSchema, data, 'Invalid layout config'),
|
|
123
|
+
resolvedLayout: (data: unknown): ValidationResult<ResolvedLayout> => safeValidate(ResolvedLayoutSchema, data, 'Invalid resolved layout'),
|
|
124
|
+
fileSystemRoute: (data: unknown): ValidationResult<FileSystemRoute> => safeValidate(FileSystemRouteSchema, data, 'Invalid file system route'),
|
|
125
|
+
routePageModule: (data: unknown): ValidationResult<RoutePageModule> => safeValidate(RoutePageModuleSchema, data, 'Invalid route page module'),
|
|
126
|
+
routeDiscoveryOptions: (data: unknown): ValidationResult<RouteDiscoveryOptions> => safeValidate(RouteDiscoveryOptionsSchema, data, 'Invalid route discovery options'),
|
|
127
|
+
fileSystemRouterConfig: (data: unknown): ValidationResult<FileSystemRouterConfig> => safeValidate(FileSystemRouterConfigSchema, data, 'Invalid file system router config'),
|
|
128
|
+
metadata: (data: unknown): ValidationResult<Metadata> => safeValidate(MetadataSchema, data, 'Invalid metadata'),
|
|
129
|
+
resolvedMetadata: (data: unknown): ValidationResult<ResolvedMetadata> => safeValidate(ResolvedMetadataSchema, data, 'Invalid resolved metadata'),
|
|
130
|
+
} as const;
|
|
131
|
+
|
|
132
|
+
export const devValidators = {
|
|
133
|
+
renderOptionsSoft: (data: unknown, context = 'unknown'): boolean => {
|
|
134
|
+
const result = safeValidators.renderOptions(data);
|
|
135
|
+
if (!result.success) {
|
|
136
|
+
console.warn(`Render options validation warning in ${context}:`, result.error.getErrorMessage());
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
},
|
|
141
|
+
} as const;
|
|
142
|
+
|
|
143
|
+
export function isValidRenderOptions(data: unknown): data is RenderOptions {
|
|
144
|
+
return safeValidators.renderOptions(data).success;
|
|
145
|
+
}
|
|
146
|
+
export function isValidFileSystemRoute(data: unknown): data is FileSystemRoute {
|
|
147
|
+
return safeValidators.fileSystemRoute(data).success;
|
|
148
|
+
}
|
|
149
|
+
export function isValidRoutePageModule(data: unknown): data is RoutePageModule {
|
|
150
|
+
return safeValidators.routePageModule(data).success;
|
|
151
|
+
}
|
|
152
|
+
export function isValidRouteDiscoveryOptions(data: unknown): data is RouteDiscoveryOptions {
|
|
153
|
+
return safeValidators.routeDiscoveryOptions(data).success;
|
|
154
|
+
}
|
|
155
|
+
export function isValidFileSystemRouterConfig(data: unknown): data is FileSystemRouterConfig {
|
|
156
|
+
return safeValidators.fileSystemRouterConfig(data).success;
|
|
157
|
+
}
|
|
158
|
+
export function isValidMetadata(data: unknown): data is Metadata {
|
|
159
|
+
return safeValidators.metadata(data).success;
|
|
160
|
+
}
|
|
161
|
+
export function isValidResolvedMetadata(data: unknown): data is ResolvedMetadata {
|
|
162
|
+
return safeValidators.resolvedMetadata(data).success;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function validateBatch<T extends Record<string, unknown>>(
|
|
166
|
+
schemas: { [K in keyof T]: z.ZodType<T[K]> },
|
|
167
|
+
data: { [K in keyof T]: unknown }
|
|
168
|
+
): T {
|
|
169
|
+
const result: Partial<T> = {};
|
|
170
|
+
const errors: string[] = [];
|
|
171
|
+
|
|
172
|
+
for (const [key, schema] of Object.entries(schemas) as Array<[keyof T, z.ZodType<T[keyof T]>]>) {
|
|
173
|
+
try {
|
|
174
|
+
result[key] = validate(schema, data[key], `Invalid ${String(key)}`);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (error instanceof ValidationError) {
|
|
177
|
+
errors.push(`${String(key)}: ${error.getErrorMessage()}`);
|
|
178
|
+
} else {
|
|
179
|
+
errors.push(`${String(key)}: Unknown validation error`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (errors.length > 0) {
|
|
185
|
+
throw new Error(`Batch validation failed: ${errors.join('; ')}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return result as T;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function safeValidateBatch<T extends Record<string, unknown>>(
|
|
192
|
+
schemas: { [K in keyof T]: z.ZodType<T[K]> },
|
|
193
|
+
data: { [K in keyof T]: unknown }
|
|
194
|
+
): ValidationResult<T> {
|
|
195
|
+
try {
|
|
196
|
+
const result = validateBatch(schemas, data);
|
|
197
|
+
return { success: true, data: result };
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const validationError =
|
|
200
|
+
error instanceof ValidationError
|
|
201
|
+
? error
|
|
202
|
+
: createValidationError(
|
|
203
|
+
'Batch validation failed',
|
|
204
|
+
new z.ZodError([{ code: 'custom', message: String(error), path: [] }])
|
|
205
|
+
);
|
|
206
|
+
return { success: false, error: validationError };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export type ExtractValidationData<T> = T extends ValidationResult<infer U> ? U : never;
|
|
211
|
+
export type ExtractSchemaInput<T> = T extends z.ZodType<infer U> ? U : never;
|
|
212
|
+
export type ExtractSchemaOutput<T> = T extends z.ZodType<infer U> ? U : never;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ComponentChildren } from 'preact';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Layout Context Schema - Contains request information and state for layout processing
|
|
6
|
+
*/
|
|
7
|
+
export const LayoutContextSchema = z.object({
|
|
8
|
+
request: z.instanceof(Request),
|
|
9
|
+
params: z.record(z.string(), z.string()),
|
|
10
|
+
query: z.instanceof(URLSearchParams),
|
|
11
|
+
state: z.instanceof(Map<string, unknown>),
|
|
12
|
+
middlewareContext: z.any().optional(), // MiddlewareContext type from middleware system
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Layout Data Schema - Flexible data structure for layout loaders
|
|
17
|
+
*/
|
|
18
|
+
export const LayoutDataSchema = z.record(z.string(), z.unknown());
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Layout Route Schema - Represents a discovered layout file with routing information
|
|
22
|
+
*/
|
|
23
|
+
export const LayoutRouteSchema = z.object({
|
|
24
|
+
pattern: z.instanceof(URLPattern),
|
|
25
|
+
layoutPath: z.string().min(1),
|
|
26
|
+
priority: z.number().int().min(0),
|
|
27
|
+
type: z.enum(['root', 'nested']),
|
|
28
|
+
depth: z.number().int().min(0),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Layout Handler Schema - Complete layout information including component and loader
|
|
33
|
+
*/
|
|
34
|
+
export const LayoutHandlerSchema = z.object({
|
|
35
|
+
component: z.any(), // ComponentType<LayoutProps> - can't validate function types with Zod
|
|
36
|
+
loader: z.any().optional(), // LayoutLoader function - can't validate function signature with Zod
|
|
37
|
+
path: z.string().min(1),
|
|
38
|
+
priority: z.number().int().min(0),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Layout Props Schema - Props passed to layout components
|
|
43
|
+
*/
|
|
44
|
+
export const LayoutPropsSchema = z.object({
|
|
45
|
+
children: z.any(), // ComponentChildren - can't validate JSX with Zod
|
|
46
|
+
data: LayoutDataSchema,
|
|
47
|
+
frontmatter: z.record(z.string(), z.any()).optional(), // Frontmatter from MDX files
|
|
48
|
+
route: z.object({
|
|
49
|
+
path: z.string(),
|
|
50
|
+
params: z.record(z.string(), z.string()),
|
|
51
|
+
query: z.instanceof(URLSearchParams),
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Layout Discovery Options Schema
|
|
57
|
+
*/
|
|
58
|
+
export const LayoutDiscoveryOptionsSchema = z.object({
|
|
59
|
+
baseDirectory: z.string().min(1),
|
|
60
|
+
filePattern: z.string().min(1).optional().default('_layout.tsx'),
|
|
61
|
+
excludeDirectories: z.array(z.string()).optional().default([]),
|
|
62
|
+
enableWatching: z.boolean().optional().default(false),
|
|
63
|
+
developmentMode: z.boolean().optional().default(false),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Route Info Schema - Information about the current route for conditional rendering
|
|
68
|
+
*/
|
|
69
|
+
export const RouteInfoSchema = z.object({
|
|
70
|
+
path: z.string(),
|
|
71
|
+
params: z.record(z.string(), z.string()),
|
|
72
|
+
method: z.string(),
|
|
73
|
+
headers: z.instanceof(Headers),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Layout Rule Schema - Rules for conditional layout rendering
|
|
78
|
+
*/
|
|
79
|
+
export const LayoutRuleSchema = z.object({
|
|
80
|
+
matches: z.any(), // (layoutPath: string, route: RouteInfo) => boolean - can't validate function signature with Zod
|
|
81
|
+
apply: z.boolean(),
|
|
82
|
+
priority: z.number().int(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Layout Config Schema - Page-level layout composition control
|
|
87
|
+
*/
|
|
88
|
+
export const LayoutConfigSchema = z.object({
|
|
89
|
+
skipLayouts: z.array(z.string()).optional(),
|
|
90
|
+
replaceLayout: z.boolean().optional(),
|
|
91
|
+
onlyLayouts: z.array(z.string()).optional(),
|
|
92
|
+
customLayout: z.string().optional(),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Island State Schema - State data for persistent islands
|
|
97
|
+
*/
|
|
98
|
+
export const IslandStateSchema = z.record(z.string(), z.unknown());
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Persistent Island Props Schema
|
|
102
|
+
*/
|
|
103
|
+
export const PersistentIslandPropsSchema = z.object({
|
|
104
|
+
persistentId: z.string().min(1),
|
|
105
|
+
children: z.any(), // ComponentChildren
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Persistent Island Context Schema
|
|
110
|
+
*/
|
|
111
|
+
export const PersistentIslandContextSchema = z.object({
|
|
112
|
+
saveState: z.any(), // (state: IslandState) => void - can't validate function signature with Zod
|
|
113
|
+
loadState: z.any(), // () => IslandState | null - can't validate function signature with Zod
|
|
114
|
+
clearState: z.any(), // () => void - can't validate function signature with Zod
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Layout Error Info Schema
|
|
119
|
+
*/
|
|
120
|
+
export const LayoutErrorInfoSchema = z.object({
|
|
121
|
+
layoutPath: z.string(),
|
|
122
|
+
errorType: z.enum(['component', 'loader', 'rendering', 'island']),
|
|
123
|
+
timestamp: z.number().int().positive(),
|
|
124
|
+
componentStack: z.string().optional(),
|
|
125
|
+
errorBoundary: z.string().optional(),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Layout Error Boundary Props Schema
|
|
130
|
+
*/
|
|
131
|
+
export const LayoutErrorBoundaryPropsSchema = z.object({
|
|
132
|
+
children: z.any(), // ComponentChildren
|
|
133
|
+
fallback: z.any(), // (error: Error, retry: () => void) => ComponentChildren - can't validate function signature with Zod
|
|
134
|
+
onError: z.any().optional(), // (error: Error, errorInfo: unknown) => void - can't validate function signature with Zod
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Error Recovery Strategy Schema
|
|
139
|
+
*/
|
|
140
|
+
export const ErrorRecoveryStrategySchema = z.object({
|
|
141
|
+
type: z.enum(['retry', 'fallback', 'skip', 'redirect']),
|
|
142
|
+
maxRetries: z.number().int().positive().optional(),
|
|
143
|
+
fallbackComponent: z.any().optional(), // ComponentType
|
|
144
|
+
redirectUrl: z.url().optional(),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Streaming Layout Props Schema
|
|
149
|
+
*/
|
|
150
|
+
export const StreamingLayoutPropsSchema = z.object({
|
|
151
|
+
children: z.any(), // ComponentChildren
|
|
152
|
+
fallback: z.any().optional(), // ComponentChildren
|
|
153
|
+
priority: z.enum(['high', 'medium', 'low']).default('medium'),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Streaming Component Schema
|
|
158
|
+
*/
|
|
159
|
+
export const StreamingComponentSchema = z.object({
|
|
160
|
+
component: z.any(), // ComponentType
|
|
161
|
+
fallback: z.any(), // ComponentType
|
|
162
|
+
priority: z.number().int().min(0),
|
|
163
|
+
isReady: z.any(), // () => Promise<boolean> - can't validate function signature with Zod
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Resolved Layout Schema - Complete layout resolution result
|
|
168
|
+
*/
|
|
169
|
+
export const ResolvedLayoutSchema = z.object({
|
|
170
|
+
handlers: z.array(LayoutHandlerSchema),
|
|
171
|
+
dataLoaders: z.array(z.any()), // LayoutLoader[] - can't validate function signature with Zod
|
|
172
|
+
errorBoundaries: z.array(z.any()), // LayoutErrorBoundary[]
|
|
173
|
+
streamingComponents: z.array(StreamingComponentSchema),
|
|
174
|
+
metadata: z.object({
|
|
175
|
+
totalLayouts: z.number().int().min(0),
|
|
176
|
+
resolutionTime: z.number().positive(),
|
|
177
|
+
cacheHit: z.boolean(),
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Layout Cache Schema
|
|
183
|
+
*/
|
|
184
|
+
export const LayoutCacheSchema = z.object({
|
|
185
|
+
resolved: z.instanceof(Map), // Map<string, ResolvedLayout>
|
|
186
|
+
handlers: z.instanceof(Map), // Map<string, LayoutHandler>
|
|
187
|
+
data: z.instanceof(Map), // Map<string, LayoutData>
|
|
188
|
+
ttl: z.instanceof(Map), // Map<string, number>
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Enhanced Layout Context Schema - Extended context with layout-specific information
|
|
193
|
+
*/
|
|
194
|
+
export const EnhancedLayoutContextSchema = LayoutContextSchema.extend({
|
|
195
|
+
layouts: z.array(LayoutHandlerSchema),
|
|
196
|
+
parentData: z.array(LayoutDataSchema),
|
|
197
|
+
islandStates: z.instanceof(Map), // Map<string, IslandState>
|
|
198
|
+
streamingEnabled: z.boolean(),
|
|
199
|
+
errorBoundaries: z.array(z.any()), // LayoutErrorBoundary[]
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// === TypeScript Type Definitions ===
|
|
203
|
+
|
|
204
|
+
export type LayoutContext = z.infer<typeof LayoutContextSchema>;
|
|
205
|
+
export type LayoutData = z.infer<typeof LayoutDataSchema>;
|
|
206
|
+
export type LayoutRoute = z.infer<typeof LayoutRouteSchema>;
|
|
207
|
+
export type LayoutHandler = z.infer<typeof LayoutHandlerSchema>;
|
|
208
|
+
export type LayoutProps = z.infer<typeof LayoutPropsSchema>;
|
|
209
|
+
export type LayoutDiscoveryOptions = z.infer<typeof LayoutDiscoveryOptionsSchema>;
|
|
210
|
+
export type RouteInfo = z.infer<typeof RouteInfoSchema>;
|
|
211
|
+
export type LayoutRule = z.infer<typeof LayoutRuleSchema>;
|
|
212
|
+
export type LayoutConfig = z.infer<typeof LayoutConfigSchema>;
|
|
213
|
+
export type IslandState = z.infer<typeof IslandStateSchema>;
|
|
214
|
+
export type PersistentIslandProps = z.infer<typeof PersistentIslandPropsSchema>;
|
|
215
|
+
export type PersistentIslandContext = z.infer<typeof PersistentIslandContextSchema>;
|
|
216
|
+
export type LayoutErrorInfo = z.infer<typeof LayoutErrorInfoSchema>;
|
|
217
|
+
export type LayoutErrorBoundaryProps = z.infer<typeof LayoutErrorBoundaryPropsSchema>;
|
|
218
|
+
export type ErrorRecoveryStrategy = z.infer<typeof ErrorRecoveryStrategySchema>;
|
|
219
|
+
export type StreamingLayoutProps = z.infer<typeof StreamingLayoutPropsSchema>;
|
|
220
|
+
export type StreamingComponent = z.infer<typeof StreamingComponentSchema>;
|
|
221
|
+
export type ResolvedLayout = z.infer<typeof ResolvedLayoutSchema>;
|
|
222
|
+
export type LayoutCache = z.infer<typeof LayoutCacheSchema>;
|
|
223
|
+
export type EnhancedLayoutContext = z.infer<typeof EnhancedLayoutContextSchema>;
|
|
224
|
+
|
|
225
|
+
// === Function Type Definitions ===
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Layout Loader Function Type
|
|
229
|
+
* Loads data for a specific layout component
|
|
230
|
+
*/
|
|
231
|
+
export type LayoutLoader = (ctx: LayoutContext) => Promise<LayoutData>;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Layout Matcher Function Type
|
|
235
|
+
* Determines if a layout should be applied based on route information and optional layout path
|
|
236
|
+
*/
|
|
237
|
+
export type LayoutMatcherFunction = (route: RouteInfo, layoutPath?: string) => boolean;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Layout Error Handler Function Type
|
|
241
|
+
* Handles errors that occur during layout processing
|
|
242
|
+
*/
|
|
243
|
+
export type LayoutErrorHandler = (error: Error, errorInfo: LayoutErrorInfo) => void;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Layout Retry Function Type
|
|
247
|
+
* Function to retry failed layout operations
|
|
248
|
+
*/
|
|
249
|
+
export type LayoutRetryFunction = () => void;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Layout Fallback Renderer Function Type
|
|
253
|
+
* Renders fallback UI when layout errors occur
|
|
254
|
+
*/
|
|
255
|
+
export type LayoutFallbackRenderer = (error: Error, retry: LayoutRetryFunction) => ComponentChildren;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Island State Saver Function Type
|
|
259
|
+
* Saves island state to persistence layer
|
|
260
|
+
*/
|
|
261
|
+
export type IslandStateSaver = (state: IslandState) => void;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Island State Loader Function Type
|
|
265
|
+
* Loads island state from persistence layer
|
|
266
|
+
*/
|
|
267
|
+
export type IslandStateLoader = () => IslandState | null;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Island State Clearer Function Type
|
|
271
|
+
* Clears island state from persistence layer
|
|
272
|
+
*/
|
|
273
|
+
export type IslandStateClearer = () => void;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Streaming Component Ready Check Function Type
|
|
277
|
+
* Checks if a streaming component is ready to render
|
|
278
|
+
*/
|
|
279
|
+
export type StreamingReadyCheck = () => Promise<boolean>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Re-export all routing schemas and types
|
|
2
|
+
export * from '../routing.ts';
|
|
3
|
+
|
|
4
|
+
// Export specific validators for routing
|
|
5
|
+
import {
|
|
6
|
+
FileSystemRouteSchema,
|
|
7
|
+
RoutePageModuleSchema,
|
|
8
|
+
RouteDiscoveryOptionsSchema,
|
|
9
|
+
FileSystemRouterConfigSchema,
|
|
10
|
+
MetadataSchema,
|
|
11
|
+
ResolvedMetadataSchema,
|
|
12
|
+
} from '../routing.ts';
|
|
13
|
+
|
|
14
|
+
import { validate, safeValidate } from '../index.ts';
|
|
15
|
+
|
|
16
|
+
// Routing-specific validators
|
|
17
|
+
export const routingValidators = {
|
|
18
|
+
fileSystemRoute: (data: unknown) => validate(FileSystemRouteSchema, data, 'Invalid file system route'),
|
|
19
|
+
routePageModule: (data: unknown) => validate(RoutePageModuleSchema, data, 'Invalid route page module'),
|
|
20
|
+
routeDiscoveryOptions: (data: unknown) =>
|
|
21
|
+
validate(RouteDiscoveryOptionsSchema, data, 'Invalid route discovery options'),
|
|
22
|
+
fileSystemRouterConfig: (data: unknown) =>
|
|
23
|
+
validate(FileSystemRouterConfigSchema, data, 'Invalid file system router config'),
|
|
24
|
+
metadata: (data: unknown) => validate(MetadataSchema, data, 'Invalid metadata'),
|
|
25
|
+
resolvedMetadata: (data: unknown) => validate(ResolvedMetadataSchema, data, 'Invalid resolved metadata'),
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
// Safe routing validators
|
|
29
|
+
export const safeRoutingValidators = {
|
|
30
|
+
fileSystemRoute: (data: unknown) => safeValidate(FileSystemRouteSchema, data, 'Invalid file system route'),
|
|
31
|
+
routePageModule: (data: unknown) => safeValidate(RoutePageModuleSchema, data, 'Invalid route page module'),
|
|
32
|
+
routeDiscoveryOptions: (data: unknown) =>
|
|
33
|
+
safeValidate(RouteDiscoveryOptionsSchema, data, 'Invalid route discovery options'),
|
|
34
|
+
fileSystemRouterConfig: (data: unknown) =>
|
|
35
|
+
safeValidate(FileSystemRouterConfigSchema, data, 'Invalid file system router config'),
|
|
36
|
+
metadata: (data: unknown) => safeValidate(MetadataSchema, data, 'Invalid metadata'),
|
|
37
|
+
resolvedMetadata: (data: unknown) => safeValidate(ResolvedMetadataSchema, data, 'Invalid resolved metadata'),
|
|
38
|
+
} as const;
|