@flight-framework/core 0.0.1
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/LICENSE +21 -0
- package/dist/actions/index.d.ts +108 -0
- package/dist/actions/index.js +3 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/adapters/index.d.ts +243 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/cache/index.d.ts +76 -0
- package/dist/cache/index.js +3 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/chunk-3AIQVGTM.js +120 -0
- package/dist/chunk-3AIQVGTM.js.map +1 -0
- package/dist/chunk-AFSKXC6V.js +188 -0
- package/dist/chunk-AFSKXC6V.js.map +1 -0
- package/dist/chunk-AJ3IBYXT.js +47 -0
- package/dist/chunk-AJ3IBYXT.js.map +1 -0
- package/dist/chunk-GCQZ4FHI.js +245 -0
- package/dist/chunk-GCQZ4FHI.js.map +1 -0
- package/dist/chunk-I5RHYGX6.js +167 -0
- package/dist/chunk-I5RHYGX6.js.map +1 -0
- package/dist/chunk-KWFX6WHG.js +311 -0
- package/dist/chunk-KWFX6WHG.js.map +1 -0
- package/dist/chunk-Q4C5CCHK.js +13 -0
- package/dist/chunk-Q4C5CCHK.js.map +1 -0
- package/dist/chunk-QEFGUHYD.js +221 -0
- package/dist/chunk-QEFGUHYD.js.map +1 -0
- package/dist/chunk-TKXN7KGE.js +145 -0
- package/dist/chunk-TKXN7KGE.js.map +1 -0
- package/dist/chunk-WAGCTWGY.js +93 -0
- package/dist/chunk-WAGCTWGY.js.map +1 -0
- package/dist/chunk-Y22KEW2F.js +223 -0
- package/dist/chunk-Y22KEW2F.js.map +1 -0
- package/dist/chunk-ZVC3ZWLM.js +52 -0
- package/dist/chunk-ZVC3ZWLM.js.map +1 -0
- package/dist/config/index.d.ts +146 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/file-router/index.d.ts +71 -0
- package/dist/file-router/index.js +3 -0
- package/dist/file-router/index.js.map +1 -0
- package/dist/handlers/index.d.ts +59 -0
- package/dist/handlers/index.js +3 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/index.d.ts +152 -0
- package/dist/middleware/index.js +3 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/render/index.d.ts +131 -0
- package/dist/render/index.js +3 -0
- package/dist/render/index.js.map +1 -0
- package/dist/router/index.d.ts +65 -0
- package/dist/router/index.js +3 -0
- package/dist/router/index.js.map +1 -0
- package/dist/rsc/index.d.ts +131 -0
- package/dist/rsc/index.js +3 -0
- package/dist/rsc/index.js.map +1 -0
- package/dist/server/index.d.ts +135 -0
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -0
- package/dist/streaming/index.d.ts +169 -0
- package/dist/streaming/index.js +3 -0
- package/dist/streaming/index.js.map +1 -0
- package/package.json +100 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// src/rsc/index.ts
|
|
2
|
+
function hasUseClientDirective(source) {
|
|
3
|
+
const firstLine = source.trim().split("\n")[0] ?? "";
|
|
4
|
+
return /^['"]use client['"];?/.test(firstLine);
|
|
5
|
+
}
|
|
6
|
+
function hasUseServerDirective(source) {
|
|
7
|
+
const firstLine = source.trim().split("\n")[0] ?? "";
|
|
8
|
+
return /^['"]use server['"];?/.test(firstLine);
|
|
9
|
+
}
|
|
10
|
+
function detectComponentType(source) {
|
|
11
|
+
if (hasUseClientDirective(source)) return "client";
|
|
12
|
+
if (hasUseServerDirective(source)) return "server";
|
|
13
|
+
return "hybrid";
|
|
14
|
+
}
|
|
15
|
+
async function executeServerComponent(component, props, context) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await component(props, context);
|
|
18
|
+
return result;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("[Flight] Server component error:", error);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function createRenderContext(request, params = {}) {
|
|
25
|
+
const url = new URL(request.url);
|
|
26
|
+
const cookies = /* @__PURE__ */ new Map();
|
|
27
|
+
const cookieHeader = request.headers.get("cookie") || "";
|
|
28
|
+
cookieHeader.split(";").forEach((cookie) => {
|
|
29
|
+
const [key, value] = cookie.trim().split("=");
|
|
30
|
+
if (key && value) cookies.set(key, value);
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
request,
|
|
34
|
+
params,
|
|
35
|
+
searchParams: url.searchParams,
|
|
36
|
+
headers: request.headers,
|
|
37
|
+
cookies
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
var fetchCache = /* @__PURE__ */ new Map();
|
|
41
|
+
async function serverFetch(url, options = {}) {
|
|
42
|
+
const { revalidate = 60, tags = [], ...fetchOptions } = options;
|
|
43
|
+
const cacheKey = `${url}:${JSON.stringify(fetchOptions)}`;
|
|
44
|
+
const cached = fetchCache.get(cacheKey);
|
|
45
|
+
if (cached) {
|
|
46
|
+
const age = Date.now() - cached.timestamp;
|
|
47
|
+
if (revalidate === false || age < revalidate * 1e3) {
|
|
48
|
+
return cached.data;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const response = await fetch(url, fetchOptions);
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);
|
|
54
|
+
}
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
if (revalidate !== false) {
|
|
57
|
+
fetchCache.set(cacheKey, {
|
|
58
|
+
data,
|
|
59
|
+
timestamp: Date.now()
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
function revalidateTag(tag) {
|
|
65
|
+
console.log(`[Flight] Revalidating tag: ${tag}`);
|
|
66
|
+
}
|
|
67
|
+
function revalidatePath(path) {
|
|
68
|
+
console.log(`[Flight] Revalidating path: ${path}`);
|
|
69
|
+
}
|
|
70
|
+
function serializeProps(props) {
|
|
71
|
+
function preProcess(value) {
|
|
72
|
+
if (value instanceof Date) {
|
|
73
|
+
return { __type: "Date", value: value.toISOString() };
|
|
74
|
+
}
|
|
75
|
+
if (value instanceof Map) {
|
|
76
|
+
return { __type: "Map", value: Array.from(value.entries()).map(([k, v]) => [preProcess(k), preProcess(v)]) };
|
|
77
|
+
}
|
|
78
|
+
if (value instanceof Set) {
|
|
79
|
+
return { __type: "Set", value: Array.from(value).map(preProcess) };
|
|
80
|
+
}
|
|
81
|
+
if (typeof value === "bigint") {
|
|
82
|
+
return { __type: "BigInt", value: value.toString() };
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === "function") {
|
|
85
|
+
return void 0;
|
|
86
|
+
}
|
|
87
|
+
if (Array.isArray(value)) {
|
|
88
|
+
return value.map(preProcess);
|
|
89
|
+
}
|
|
90
|
+
if (value && typeof value === "object") {
|
|
91
|
+
const result = {};
|
|
92
|
+
for (const [k, v] of Object.entries(value)) {
|
|
93
|
+
result[k] = preProcess(v);
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
return JSON.stringify(preProcess(props));
|
|
100
|
+
}
|
|
101
|
+
function deserializeProps(serialized) {
|
|
102
|
+
return JSON.parse(serialized, (_key, value) => {
|
|
103
|
+
if (value && typeof value === "object" && "__type" in value) {
|
|
104
|
+
switch (value.__type) {
|
|
105
|
+
case "Date":
|
|
106
|
+
return new Date(value.value);
|
|
107
|
+
case "Map":
|
|
108
|
+
return new Map(value.value);
|
|
109
|
+
case "Set":
|
|
110
|
+
return new Set(value.value);
|
|
111
|
+
case "BigInt":
|
|
112
|
+
return BigInt(value.value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function createClientBoundary(componentId, props, fallback) {
|
|
119
|
+
const serializedProps = serializeProps(props);
|
|
120
|
+
return `
|
|
121
|
+
<!--flight-client:${componentId}-->
|
|
122
|
+
<div data-flight-component="${componentId}" data-flight-props='${serializedProps.replace(/'/g, "'")}'>
|
|
123
|
+
${fallback || "<div>Loading...</div>"}
|
|
124
|
+
</div>
|
|
125
|
+
<!--/flight-client-->
|
|
126
|
+
<script type="module">
|
|
127
|
+
(async function() {
|
|
128
|
+
const component = await import('/_flight/components/${componentId}.js');
|
|
129
|
+
const props = JSON.parse('${serializedProps.replace(/'/g, "\\'")}');
|
|
130
|
+
const container = document.querySelector('[data-flight-component="${componentId}"]');
|
|
131
|
+
if (container && component.default) {
|
|
132
|
+
// Hydrate with the framework's hydration method
|
|
133
|
+
if (typeof component.hydrate === 'function') {
|
|
134
|
+
component.hydrate(container, props);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
})();
|
|
138
|
+
</script>`;
|
|
139
|
+
}
|
|
140
|
+
function createAsyncComponent(fetcher, renderer) {
|
|
141
|
+
const component = async (props, context) => {
|
|
142
|
+
const data = await fetcher(props, context);
|
|
143
|
+
return renderer(data, props);
|
|
144
|
+
};
|
|
145
|
+
component.__flight_server = true;
|
|
146
|
+
return component;
|
|
147
|
+
}
|
|
148
|
+
function composeComponents(...components) {
|
|
149
|
+
return async () => {
|
|
150
|
+
const results = await Promise.all(
|
|
151
|
+
components.map(async (comp) => await comp())
|
|
152
|
+
);
|
|
153
|
+
return results.join("");
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function withErrorBoundary(component, errorFallback) {
|
|
157
|
+
return async (props, context) => {
|
|
158
|
+
try {
|
|
159
|
+
return await component(props, context);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error("[Flight] Server component error:", error);
|
|
162
|
+
return errorFallback(error);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function notFound() {
|
|
167
|
+
const error = new Error("Not Found");
|
|
168
|
+
error.__flight_not_found = true;
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
function isNotFoundError(error) {
|
|
172
|
+
return error instanceof Error && error.__flight_not_found === true;
|
|
173
|
+
}
|
|
174
|
+
function redirect(url, type = "replace") {
|
|
175
|
+
const error = new Error(`Redirect: ${url}`);
|
|
176
|
+
error.__flight_redirect = { url, type };
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
function isRedirectError(error) {
|
|
180
|
+
if (error instanceof Error && error.__flight_redirect) {
|
|
181
|
+
return error.__flight_redirect;
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { composeComponents, createAsyncComponent, createClientBoundary, createRenderContext, deserializeProps, detectComponentType, executeServerComponent, hasUseClientDirective, hasUseServerDirective, isNotFoundError, isRedirectError, notFound, redirect, revalidatePath, revalidateTag, serializeProps, serverFetch, withErrorBoundary };
|
|
187
|
+
//# sourceMappingURL=chunk-AFSKXC6V.js.map
|
|
188
|
+
//# sourceMappingURL=chunk-AFSKXC6V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rsc/index.ts"],"names":[],"mappings":"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","file":"chunk-AFSKXC6V.js","sourcesContent":["/**\r\n * @flight/core - React Server Components Support\r\n * \r\n * Framework-agnostic primitives for RSC-like patterns.\r\n * Enables async server components, client/server boundaries, and data fetching.\r\n * \r\n * Best Practices 2025/2026:\r\n * - Async components for server-side data fetching\r\n * - 'use client' / 'use server' directive detection\r\n * - Automatic component serialization\r\n * - Props passing between server and client\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Component rendering context\r\n */\r\nexport interface RenderContext {\r\n /** Current request */\r\n request: Request;\r\n /** Route params */\r\n params: Record<string, string>;\r\n /** Search params */\r\n searchParams: URLSearchParams;\r\n /** Request headers */\r\n headers: Headers;\r\n /** Cookies */\r\n cookies: Map<string, string>;\r\n}\r\n\r\n/**\r\n * Server component definition\r\n */\r\nexport interface ServerComponent<P = unknown> {\r\n (props: P, context: RenderContext): Promise<string> | string;\r\n /** Mark as server component */\r\n __flight_server?: true;\r\n /** Dependencies for hydration */\r\n __flight_deps?: string[];\r\n}\r\n\r\n/**\r\n * Client component definition\r\n */\r\nexport interface ClientComponent<P = unknown> {\r\n (props: P): unknown;\r\n /** Mark as client component */\r\n __flight_client?: true;\r\n /** Client bundle path */\r\n __flight_bundle?: string;\r\n}\r\n\r\n/**\r\n * Component type detection\r\n */\r\nexport type ComponentType = 'server' | 'client' | 'hybrid';\r\n\r\n// ============================================================================\r\n// Directive Detection (Build-time)\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a file has 'use client' directive\r\n */\r\nexport function hasUseClientDirective(source: string): boolean {\r\n const firstLine = source.trim().split('\\n')[0] ?? '';\r\n return /^['\"]use client['\"];?/.test(firstLine);\r\n}\r\n\r\n/**\r\n * Check if a file has 'use server' directive\r\n */\r\nexport function hasUseServerDirective(source: string): boolean {\r\n const firstLine = source.trim().split('\\n')[0] ?? '';\r\n return /^['\"]use server['\"];?/.test(firstLine);\r\n}\r\n\r\n/**\r\n * Detect component type from source\r\n */\r\nexport function detectComponentType(source: string): ComponentType {\r\n if (hasUseClientDirective(source)) return 'client';\r\n if (hasUseServerDirective(source)) return 'server';\r\n return 'hybrid';\r\n}\r\n\r\n// ============================================================================\r\n// Server Component Execution\r\n// ============================================================================\r\n\r\n/**\r\n * Execute an async server component\r\n */\r\nexport async function executeServerComponent<P>(\r\n component: ServerComponent<P>,\r\n props: P,\r\n context: RenderContext\r\n): Promise<string> {\r\n try {\r\n const result = await component(props, context);\r\n return result;\r\n } catch (error) {\r\n console.error('[Flight] Server component error:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Create a render context from a Request\r\n */\r\nexport function createRenderContext(request: Request, params: Record<string, string> = {}): RenderContext {\r\n const url = new URL(request.url);\r\n\r\n // Parse cookies\r\n const cookies = new Map<string, string>();\r\n const cookieHeader = request.headers.get('cookie') || '';\r\n cookieHeader.split(';').forEach(cookie => {\r\n const [key, value] = cookie.trim().split('=');\r\n if (key && value) cookies.set(key, value);\r\n });\r\n\r\n return {\r\n request,\r\n params,\r\n searchParams: url.searchParams,\r\n headers: request.headers,\r\n cookies,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Data Fetching Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Cache for server-side fetch requests\r\n */\r\nconst fetchCache = new Map<string, { data: unknown; timestamp: number }>();\r\n\r\n/**\r\n * Server-side fetch with automatic caching (like Next.js fetch extensions)\r\n */\r\nexport async function serverFetch<T>(\r\n url: string,\r\n options: RequestInit & {\r\n revalidate?: number | false;\r\n tags?: string[];\r\n } = {}\r\n): Promise<T> {\r\n const { revalidate = 60, tags = [], ...fetchOptions } = options;\r\n const cacheKey = `${url}:${JSON.stringify(fetchOptions)}`;\r\n\r\n // Check cache\r\n const cached = fetchCache.get(cacheKey);\r\n if (cached) {\r\n const age = Date.now() - cached.timestamp;\r\n if (revalidate === false || age < (revalidate * 1000)) {\r\n return cached.data as T;\r\n }\r\n }\r\n\r\n // Fetch fresh data\r\n const response = await fetch(url, fetchOptions);\r\n\r\n if (!response.ok) {\r\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n const data = await response.json();\r\n\r\n // Cache the result\r\n if (revalidate !== false) {\r\n fetchCache.set(cacheKey, {\r\n data,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n\r\n return data as T;\r\n}\r\n\r\n/**\r\n * Invalidate cache by tag\r\n */\r\nexport function revalidateTag(tag: string): void {\r\n // In a real implementation, this would invalidate cache entries by tag\r\n console.log(`[Flight] Revalidating tag: ${tag}`);\r\n}\r\n\r\n/**\r\n * Invalidate cache by path\r\n */\r\nexport function revalidatePath(path: string): void {\r\n // In a real implementation, this would invalidate cache entries by path\r\n console.log(`[Flight] Revalidating path: ${path}`);\r\n}\r\n\r\n// ============================================================================\r\n// Component Serialization (for client boundary crossing)\r\n// ============================================================================\r\n\r\n/**\r\n * Serialize props for transmission to client\r\n */\r\nexport function serializeProps(props: unknown): string {\r\n // Pre-process to handle special types before JSON.stringify\r\n function preProcess(value: unknown): unknown {\r\n if (value instanceof Date) {\r\n return { __type: 'Date', value: value.toISOString() };\r\n }\r\n if (value instanceof Map) {\r\n return { __type: 'Map', value: Array.from(value.entries()).map(([k, v]) => [preProcess(k), preProcess(v)]) };\r\n }\r\n if (value instanceof Set) {\r\n return { __type: 'Set', value: Array.from(value).map(preProcess) };\r\n }\r\n if (typeof value === 'bigint') {\r\n return { __type: 'BigInt', value: value.toString() };\r\n }\r\n if (typeof value === 'function') {\r\n return undefined;\r\n }\r\n if (Array.isArray(value)) {\r\n return value.map(preProcess);\r\n }\r\n if (value && typeof value === 'object') {\r\n const result: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(value)) {\r\n result[k] = preProcess(v);\r\n }\r\n return result;\r\n }\r\n return value;\r\n }\r\n\r\n return JSON.stringify(preProcess(props));\r\n}\r\n\r\n/**\r\n * Deserialize props on client\r\n */\r\nexport function deserializeProps<T>(serialized: string): T {\r\n return JSON.parse(serialized, (_key, value) => {\r\n if (value && typeof value === 'object' && '__type' in value) {\r\n switch (value.__type) {\r\n case 'Date':\r\n return new Date(value.value);\r\n case 'Map':\r\n return new Map(value.value);\r\n case 'Set':\r\n return new Set(value.value);\r\n case 'BigInt':\r\n return BigInt(value.value);\r\n }\r\n }\r\n return value;\r\n });\r\n}\r\n\r\n// ============================================================================\r\n// Client Component Boundary\r\n// ============================================================================\r\n\r\n/**\r\n * Create a client boundary placeholder\r\n */\r\nexport function createClientBoundary(\r\n componentId: string,\r\n props: unknown,\r\n fallback?: string\r\n): string {\r\n const serializedProps = serializeProps(props);\r\n\r\n return `\r\n<!--flight-client:${componentId}-->\r\n<div data-flight-component=\"${componentId}\" data-flight-props='${serializedProps.replace(/'/g, \"'\")}'>\r\n ${fallback || '<div>Loading...</div>'}\r\n</div>\r\n<!--/flight-client-->\r\n<script type=\"module\">\r\n(async function() {\r\n const component = await import('/_flight/components/${componentId}.js');\r\n const props = JSON.parse('${serializedProps.replace(/'/g, \"\\\\'\")}');\r\n const container = document.querySelector('[data-flight-component=\"${componentId}\"]');\r\n if (container && component.default) {\r\n // Hydrate with the framework's hydration method\r\n if (typeof component.hydrate === 'function') {\r\n component.hydrate(container, props);\r\n }\r\n }\r\n})();\r\n</script>`;\r\n}\r\n\r\n// ============================================================================\r\n// Async Component Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Helper to create an async server component\r\n */\r\nexport function createAsyncComponent<P, T>(\r\n fetcher: (props: P, context: RenderContext) => Promise<T>,\r\n renderer: (data: T, props: P) => string\r\n): ServerComponent<P> {\r\n const component: ServerComponent<P> = async (props, context) => {\r\n const data = await fetcher(props, context);\r\n return renderer(data, props);\r\n };\r\n component.__flight_server = true;\r\n return component;\r\n}\r\n\r\n/**\r\n * Compose multiple server components\r\n */\r\nexport function composeComponents(\r\n ...components: Array<() => Promise<string> | string>\r\n): () => Promise<string> {\r\n return async () => {\r\n const results = await Promise.all(\r\n components.map(async (comp) => await comp())\r\n );\r\n return results.join('');\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Error Boundary for Server Components\r\n// ============================================================================\r\n\r\n/**\r\n * Wrap a server component with error handling\r\n */\r\nexport function withErrorBoundary<P>(\r\n component: ServerComponent<P>,\r\n errorFallback: (error: Error) => string\r\n): ServerComponent<P> {\r\n return async (props: P, context: RenderContext) => {\r\n try {\r\n return await component(props, context);\r\n } catch (error) {\r\n console.error('[Flight] Server component error:', error);\r\n return errorFallback(error as Error);\r\n }\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Not Found / Redirect Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Throw a not found error (like Next.js notFound())\r\n */\r\nexport function notFound(): never {\r\n const error = new Error('Not Found');\r\n (error as any).__flight_not_found = true;\r\n throw error;\r\n}\r\n\r\n/**\r\n * Check if error is not found\r\n */\r\nexport function isNotFoundError(error: unknown): boolean {\r\n return error instanceof Error && (error as any).__flight_not_found === true;\r\n}\r\n\r\n/**\r\n * Server-side redirect (like Next.js redirect())\r\n */\r\nexport function redirect(url: string, type: 'replace' | 'push' = 'replace'): never {\r\n const error = new Error(`Redirect: ${url}`);\r\n (error as any).__flight_redirect = { url, type };\r\n throw error;\r\n}\r\n\r\n/**\r\n * Check if error is redirect\r\n */\r\nexport function isRedirectError(error: unknown): { url: string; type: string } | null {\r\n if (error instanceof Error && (error as any).__flight_redirect) {\r\n return (error as any).__flight_redirect;\r\n }\r\n return null;\r\n}\r\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/handlers/index.ts
|
|
2
|
+
function createRouteContext(request, params = {}) {
|
|
3
|
+
const url = new URL(request.url);
|
|
4
|
+
return {
|
|
5
|
+
params,
|
|
6
|
+
searchParams: url.searchParams
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function json(data, init) {
|
|
10
|
+
const headers = new Headers(init?.headers);
|
|
11
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
12
|
+
return new Response(JSON.stringify(data), {
|
|
13
|
+
...init,
|
|
14
|
+
headers
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function redirect(url, status = 302) {
|
|
18
|
+
return new Response(null, {
|
|
19
|
+
status,
|
|
20
|
+
headers: { Location: url }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function error(message, status = 500) {
|
|
24
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
25
|
+
status,
|
|
26
|
+
headers: { "Content-Type": "application/json" }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function parseBody(request) {
|
|
30
|
+
const contentType = request.headers.get("content-type") || "";
|
|
31
|
+
if (contentType.includes("application/json")) {
|
|
32
|
+
return await request.json();
|
|
33
|
+
}
|
|
34
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
35
|
+
const formData = await request.formData();
|
|
36
|
+
const obj = {};
|
|
37
|
+
formData.forEach((value, key) => {
|
|
38
|
+
obj[key] = String(value);
|
|
39
|
+
});
|
|
40
|
+
return obj;
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`Unsupported content type: ${contentType}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { createRouteContext, error, json, parseBody, redirect };
|
|
46
|
+
//# sourceMappingURL=chunk-AJ3IBYXT.js.map
|
|
47
|
+
//# sourceMappingURL=chunk-AJ3IBYXT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/handlers/index.ts"],"names":[],"mappings":";AAuDO,SAAS,kBAAA,CACZ,OAAA,EACA,MAAA,GAAiC,EAAC,EACf;AACnB,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,EAAA,OAAO;AAAA,IACH,MAAA;AAAA,IACA,cAAc,GAAA,CAAI;AAAA,GACtB;AACJ;AAKO,SAAS,IAAA,CAAQ,MAAS,IAAA,EAA+B;AAC5D,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AACzC,EAAA,OAAA,CAAQ,GAAA,CAAI,gBAAgB,iCAAiC,CAAA;AAE7D,EAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA,IACtC,GAAG,IAAA;AAAA,IACH;AAAA,GACH,CAAA;AACL;AAKO,SAAS,QAAA,CAAS,GAAA,EAAa,MAAA,GAAsC,GAAA,EAAe;AACvF,EAAA,OAAO,IAAI,SAAS,IAAA,EAAM;AAAA,IACtB,MAAA;AAAA,IACA,OAAA,EAAS,EAAE,QAAA,EAAU,GAAA;AAAI,GAC5B,CAAA;AACL;AAKO,SAAS,KAAA,CAAM,OAAA,EAAiB,MAAA,GAAS,GAAA,EAAe;AAC3D,EAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA,EAAG;AAAA,IACpD,MAAA;AAAA,IACA,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,GACjD,CAAA;AACL;AAKA,eAAsB,UAAa,OAAA,EAA8B;AAC7D,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,EAAA;AAE3D,EAAA,IAAI,WAAA,CAAY,QAAA,CAAS,kBAAkB,CAAA,EAAG;AAC1C,IAAA,OAAO,MAAM,QAAQ,IAAA,EAAK;AAAA,EAC9B;AAEA,EAAA,IAAI,WAAA,CAAY,QAAA,CAAS,mCAAmC,CAAA,EAAG;AAC3D,IAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,QAAA,EAAS;AACxC,IAAA,MAAM,MAA8B,EAAC;AACrC,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,EAAO,GAAA,KAAQ;AAC7B,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,MAAA,CAAO,KAAK,CAAA;AAAA,IAC3B,CAAC,CAAA;AACD,IAAA,OAAO,GAAA;AAAA,EACX;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,WAAW,CAAA,CAAE,CAAA;AAC9D","file":"chunk-AJ3IBYXT.js","sourcesContent":["/**\r\n * @flight/core - Route Handlers\r\n * \r\n * Types and utilities for route handlers.\r\n * Similar to Next.js Route Handlers pattern.\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * HTTP methods supported by route handlers\r\n */\r\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\r\n\r\n/**\r\n * Context passed to route handlers\r\n */\r\nexport interface RouteHandlerContext {\r\n /** Route parameters (e.g., { id: '123' }) */\r\n params: Record<string, string>;\r\n /** Query string parameters */\r\n searchParams: URLSearchParams;\r\n}\r\n\r\n/**\r\n * Route handler function signature\r\n * \r\n * @example\r\n * ```typescript\r\n * // src/routes/api/users/[id].ts\r\n * export const GET: RouteHandler = async (request, context) => {\r\n * const { id } = context.params;\r\n * return Response.json({ userId: id });\r\n * };\r\n * \r\n * export const PUT: RouteHandler = async (request, context) => {\r\n * const body = await request.json();\r\n * return Response.json({ updated: true, data: body });\r\n * };\r\n * ```\r\n */\r\nexport type RouteHandler = (\r\n request: Request,\r\n context: RouteHandlerContext\r\n) => Response | Promise<Response>;\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Create a route handler context from request\r\n */\r\nexport function createRouteContext(\r\n request: Request,\r\n params: Record<string, string> = {}\r\n): RouteHandlerContext {\r\n const url = new URL(request.url);\r\n return {\r\n params,\r\n searchParams: url.searchParams,\r\n };\r\n}\r\n\r\n/**\r\n * Helper to create JSON response\r\n */\r\nexport function json<T>(data: T, init?: ResponseInit): Response {\r\n const headers = new Headers(init?.headers);\r\n headers.set('Content-Type', 'application/json; charset=utf-8');\r\n\r\n return new Response(JSON.stringify(data), {\r\n ...init,\r\n headers,\r\n });\r\n}\r\n\r\n/**\r\n * Helper to create redirect response\r\n */\r\nexport function redirect(url: string, status: 301 | 302 | 303 | 307 | 308 = 302): Response {\r\n return new Response(null, {\r\n status,\r\n headers: { Location: url },\r\n });\r\n}\r\n\r\n/**\r\n * Helper to create error response\r\n */\r\nexport function error(message: string, status = 500): Response {\r\n return new Response(JSON.stringify({ error: message }), {\r\n status,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n}\r\n\r\n/**\r\n * Helper to get request body as typed object\r\n */\r\nexport async function parseBody<T>(request: Request): Promise<T> {\r\n const contentType = request.headers.get('content-type') || '';\r\n\r\n if (contentType.includes('application/json')) {\r\n return await request.json() as T;\r\n }\r\n\r\n if (contentType.includes('application/x-www-form-urlencoded')) {\r\n const formData = await request.formData();\r\n const obj: Record<string, string> = {};\r\n formData.forEach((value, key) => {\r\n obj[key] = String(value);\r\n });\r\n return obj as T;\r\n }\r\n\r\n throw new Error(`Unsupported content type: ${contentType}`);\r\n}\r\n"]}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// ../../node_modules/.pnpm/radix3@1.1.2/node_modules/radix3/dist/index.mjs
|
|
2
|
+
var NODE_TYPES = {
|
|
3
|
+
NORMAL: 0,
|
|
4
|
+
WILDCARD: 1,
|
|
5
|
+
PLACEHOLDER: 2
|
|
6
|
+
};
|
|
7
|
+
function createRouter(options = {}) {
|
|
8
|
+
const ctx = {
|
|
9
|
+
options,
|
|
10
|
+
rootNode: createRadixNode(),
|
|
11
|
+
staticRoutesMap: {}
|
|
12
|
+
};
|
|
13
|
+
const normalizeTrailingSlash = (p) => options.strictTrailingSlash ? p : p.replace(/\/$/, "") || "/";
|
|
14
|
+
if (options.routes) {
|
|
15
|
+
for (const path in options.routes) {
|
|
16
|
+
insert(ctx, normalizeTrailingSlash(path), options.routes[path]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
ctx,
|
|
21
|
+
lookup: (path) => lookup(ctx, normalizeTrailingSlash(path)),
|
|
22
|
+
insert: (path, data) => insert(ctx, normalizeTrailingSlash(path), data),
|
|
23
|
+
remove: (path) => remove(ctx, normalizeTrailingSlash(path))
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function lookup(ctx, path) {
|
|
27
|
+
const staticPathNode = ctx.staticRoutesMap[path];
|
|
28
|
+
if (staticPathNode) {
|
|
29
|
+
return staticPathNode.data;
|
|
30
|
+
}
|
|
31
|
+
const sections = path.split("/");
|
|
32
|
+
const params = {};
|
|
33
|
+
let paramsFound = false;
|
|
34
|
+
let wildcardNode = null;
|
|
35
|
+
let node = ctx.rootNode;
|
|
36
|
+
let wildCardParam = null;
|
|
37
|
+
for (let i = 0; i < sections.length; i++) {
|
|
38
|
+
const section = sections[i];
|
|
39
|
+
if (node.wildcardChildNode !== null) {
|
|
40
|
+
wildcardNode = node.wildcardChildNode;
|
|
41
|
+
wildCardParam = sections.slice(i).join("/");
|
|
42
|
+
}
|
|
43
|
+
const nextNode = node.children.get(section);
|
|
44
|
+
if (nextNode === void 0) {
|
|
45
|
+
if (node && node.placeholderChildren.length > 1) {
|
|
46
|
+
const remaining = sections.length - i;
|
|
47
|
+
node = node.placeholderChildren.find((c) => c.maxDepth === remaining) || null;
|
|
48
|
+
} else {
|
|
49
|
+
node = node.placeholderChildren[0] || null;
|
|
50
|
+
}
|
|
51
|
+
if (!node) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
if (node.paramName) {
|
|
55
|
+
params[node.paramName] = section;
|
|
56
|
+
}
|
|
57
|
+
paramsFound = true;
|
|
58
|
+
} else {
|
|
59
|
+
node = nextNode;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if ((node === null || node.data === null) && wildcardNode !== null) {
|
|
63
|
+
node = wildcardNode;
|
|
64
|
+
params[node.paramName || "_"] = wildCardParam;
|
|
65
|
+
paramsFound = true;
|
|
66
|
+
}
|
|
67
|
+
if (!node) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (paramsFound) {
|
|
71
|
+
return {
|
|
72
|
+
...node.data,
|
|
73
|
+
params: paramsFound ? params : void 0
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return node.data;
|
|
77
|
+
}
|
|
78
|
+
function insert(ctx, path, data) {
|
|
79
|
+
let isStaticRoute = true;
|
|
80
|
+
const sections = path.split("/");
|
|
81
|
+
let node = ctx.rootNode;
|
|
82
|
+
let _unnamedPlaceholderCtr = 0;
|
|
83
|
+
const matchedNodes = [node];
|
|
84
|
+
for (const section of sections) {
|
|
85
|
+
let childNode;
|
|
86
|
+
if (childNode = node.children.get(section)) {
|
|
87
|
+
node = childNode;
|
|
88
|
+
} else {
|
|
89
|
+
const type = getNodeType(section);
|
|
90
|
+
childNode = createRadixNode({ type, parent: node });
|
|
91
|
+
node.children.set(section, childNode);
|
|
92
|
+
if (type === NODE_TYPES.PLACEHOLDER) {
|
|
93
|
+
childNode.paramName = section === "*" ? `_${_unnamedPlaceholderCtr++}` : section.slice(1);
|
|
94
|
+
node.placeholderChildren.push(childNode);
|
|
95
|
+
isStaticRoute = false;
|
|
96
|
+
} else if (type === NODE_TYPES.WILDCARD) {
|
|
97
|
+
node.wildcardChildNode = childNode;
|
|
98
|
+
childNode.paramName = section.slice(
|
|
99
|
+
3
|
|
100
|
+
/* "**:" */
|
|
101
|
+
) || "_";
|
|
102
|
+
isStaticRoute = false;
|
|
103
|
+
}
|
|
104
|
+
matchedNodes.push(childNode);
|
|
105
|
+
node = childNode;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const [depth, node2] of matchedNodes.entries()) {
|
|
109
|
+
node2.maxDepth = Math.max(matchedNodes.length - depth, node2.maxDepth || 0);
|
|
110
|
+
}
|
|
111
|
+
node.data = data;
|
|
112
|
+
if (isStaticRoute === true) {
|
|
113
|
+
ctx.staticRoutesMap[path] = node;
|
|
114
|
+
}
|
|
115
|
+
return node;
|
|
116
|
+
}
|
|
117
|
+
function remove(ctx, path) {
|
|
118
|
+
let success = false;
|
|
119
|
+
const sections = path.split("/");
|
|
120
|
+
let node = ctx.rootNode;
|
|
121
|
+
for (const section of sections) {
|
|
122
|
+
node = node.children.get(section);
|
|
123
|
+
if (!node) {
|
|
124
|
+
return success;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (node.data) {
|
|
128
|
+
const lastSection = sections.at(-1) || "";
|
|
129
|
+
node.data = null;
|
|
130
|
+
if (Object.keys(node.children).length === 0 && node.parent) {
|
|
131
|
+
node.parent.children.delete(lastSection);
|
|
132
|
+
node.parent.wildcardChildNode = null;
|
|
133
|
+
node.parent.placeholderChildren = [];
|
|
134
|
+
}
|
|
135
|
+
success = true;
|
|
136
|
+
}
|
|
137
|
+
return success;
|
|
138
|
+
}
|
|
139
|
+
function createRadixNode(options = {}) {
|
|
140
|
+
return {
|
|
141
|
+
type: options.type || NODE_TYPES.NORMAL,
|
|
142
|
+
maxDepth: 0,
|
|
143
|
+
parent: options.parent || null,
|
|
144
|
+
children: /* @__PURE__ */ new Map(),
|
|
145
|
+
data: options.data || null,
|
|
146
|
+
paramName: options.paramName || null,
|
|
147
|
+
wildcardChildNode: null,
|
|
148
|
+
placeholderChildren: []
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function getNodeType(str) {
|
|
152
|
+
if (str.startsWith("**")) {
|
|
153
|
+
return NODE_TYPES.WILDCARD;
|
|
154
|
+
}
|
|
155
|
+
if (str[0] === ":" || str === "*") {
|
|
156
|
+
return NODE_TYPES.PLACEHOLDER;
|
|
157
|
+
}
|
|
158
|
+
return NODE_TYPES.NORMAL;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/router/index.ts
|
|
162
|
+
function convertPattern(pattern) {
|
|
163
|
+
return pattern.replace(/\[\.\.\.(\w+)\]/g, "**:$1").replace(/\[(\w+)\]/g, ":$1");
|
|
164
|
+
}
|
|
165
|
+
function createRouter2() {
|
|
166
|
+
const radix = createRouter();
|
|
167
|
+
const routeMap = /* @__PURE__ */ new Map();
|
|
168
|
+
return {
|
|
169
|
+
add(route) {
|
|
170
|
+
const radixPath = convertPattern(route.path);
|
|
171
|
+
radix.insert(radixPath, route);
|
|
172
|
+
routeMap.set(route.path, route);
|
|
173
|
+
},
|
|
174
|
+
addAll(routes) {
|
|
175
|
+
for (const route of routes) {
|
|
176
|
+
this.add(route);
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
match(path) {
|
|
180
|
+
const result = radix.lookup(path);
|
|
181
|
+
if (!result) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const params = {};
|
|
185
|
+
if (result.params) {
|
|
186
|
+
for (const [key, value] of Object.entries(result.params)) {
|
|
187
|
+
if (value !== void 0) {
|
|
188
|
+
params[key] = value;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
route: result,
|
|
194
|
+
params,
|
|
195
|
+
path
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
routes() {
|
|
199
|
+
return Array.from(routeMap.values());
|
|
200
|
+
},
|
|
201
|
+
remove(path) {
|
|
202
|
+
if (routeMap.has(path)) {
|
|
203
|
+
const radixPath = convertPattern(path);
|
|
204
|
+
radix.remove(radixPath);
|
|
205
|
+
routeMap.delete(path);
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function filePathToRoutePath(filePath) {
|
|
213
|
+
let routePath = filePath.replace(/\.(tsx?|jsx?|vue|svelte|astro)$/, "").replace(/\/index$/, "").replace(/^index$/, "").replace(/\([^)]+\)\//g, "").replace(/\/\([^)]+\)/g, "");
|
|
214
|
+
if (!routePath.startsWith("/")) {
|
|
215
|
+
routePath = "/" + routePath;
|
|
216
|
+
}
|
|
217
|
+
if (routePath === "/") {
|
|
218
|
+
return "/";
|
|
219
|
+
}
|
|
220
|
+
return routePath.replace(/\/$/, "");
|
|
221
|
+
}
|
|
222
|
+
function sortRoutes(routes) {
|
|
223
|
+
return [...routes].sort((a, b) => {
|
|
224
|
+
const aSegments = a.path.split("/");
|
|
225
|
+
const bSegments = b.path.split("/");
|
|
226
|
+
const aDynamic = aSegments.filter((s) => s.startsWith("[") || s.startsWith(":")).length;
|
|
227
|
+
const bDynamic = bSegments.filter((s) => s.startsWith("[") || s.startsWith(":")).length;
|
|
228
|
+
if (aSegments.length !== bSegments.length) {
|
|
229
|
+
return bSegments.length - aSegments.length;
|
|
230
|
+
}
|
|
231
|
+
if (aDynamic !== bDynamic) {
|
|
232
|
+
return aDynamic - bDynamic;
|
|
233
|
+
}
|
|
234
|
+
const aCatchAll = a.path.includes("[...");
|
|
235
|
+
const bCatchAll = b.path.includes("[...");
|
|
236
|
+
if (aCatchAll !== bCatchAll) {
|
|
237
|
+
return aCatchAll ? 1 : -1;
|
|
238
|
+
}
|
|
239
|
+
return a.path.localeCompare(b.path);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export { createRouter2 as createRouter, filePathToRoutePath, sortRoutes };
|
|
244
|
+
//# sourceMappingURL=chunk-GCQZ4FHI.js.map
|
|
245
|
+
//# sourceMappingURL=chunk-GCQZ4FHI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/radix3@1.1.2/node_modules/radix3/dist/index.mjs","../src/router/index.ts"],"names":["createRouter"],"mappings":"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","file":"chunk-GCQZ4FHI.js","sourcesContent":["const NODE_TYPES = {\n NORMAL: 0,\n WILDCARD: 1,\n PLACEHOLDER: 2\n};\n\nfunction createRouter(options = {}) {\n const ctx = {\n options,\n rootNode: createRadixNode(),\n staticRoutesMap: {}\n };\n const normalizeTrailingSlash = (p) => options.strictTrailingSlash ? p : p.replace(/\\/$/, \"\") || \"/\";\n if (options.routes) {\n for (const path in options.routes) {\n insert(ctx, normalizeTrailingSlash(path), options.routes[path]);\n }\n }\n return {\n ctx,\n lookup: (path) => lookup(ctx, normalizeTrailingSlash(path)),\n insert: (path, data) => insert(ctx, normalizeTrailingSlash(path), data),\n remove: (path) => remove(ctx, normalizeTrailingSlash(path))\n };\n}\nfunction lookup(ctx, path) {\n const staticPathNode = ctx.staticRoutesMap[path];\n if (staticPathNode) {\n return staticPathNode.data;\n }\n const sections = path.split(\"/\");\n const params = {};\n let paramsFound = false;\n let wildcardNode = null;\n let node = ctx.rootNode;\n let wildCardParam = null;\n for (let i = 0; i < sections.length; i++) {\n const section = sections[i];\n if (node.wildcardChildNode !== null) {\n wildcardNode = node.wildcardChildNode;\n wildCardParam = sections.slice(i).join(\"/\");\n }\n const nextNode = node.children.get(section);\n if (nextNode === void 0) {\n if (node && node.placeholderChildren.length > 1) {\n const remaining = sections.length - i;\n node = node.placeholderChildren.find((c) => c.maxDepth === remaining) || null;\n } else {\n node = node.placeholderChildren[0] || null;\n }\n if (!node) {\n break;\n }\n if (node.paramName) {\n params[node.paramName] = section;\n }\n paramsFound = true;\n } else {\n node = nextNode;\n }\n }\n if ((node === null || node.data === null) && wildcardNode !== null) {\n node = wildcardNode;\n params[node.paramName || \"_\"] = wildCardParam;\n paramsFound = true;\n }\n if (!node) {\n return null;\n }\n if (paramsFound) {\n return {\n ...node.data,\n params: paramsFound ? params : void 0\n };\n }\n return node.data;\n}\nfunction insert(ctx, path, data) {\n let isStaticRoute = true;\n const sections = path.split(\"/\");\n let node = ctx.rootNode;\n let _unnamedPlaceholderCtr = 0;\n const matchedNodes = [node];\n for (const section of sections) {\n let childNode;\n if (childNode = node.children.get(section)) {\n node = childNode;\n } else {\n const type = getNodeType(section);\n childNode = createRadixNode({ type, parent: node });\n node.children.set(section, childNode);\n if (type === NODE_TYPES.PLACEHOLDER) {\n childNode.paramName = section === \"*\" ? `_${_unnamedPlaceholderCtr++}` : section.slice(1);\n node.placeholderChildren.push(childNode);\n isStaticRoute = false;\n } else if (type === NODE_TYPES.WILDCARD) {\n node.wildcardChildNode = childNode;\n childNode.paramName = section.slice(\n 3\n /* \"**:\" */\n ) || \"_\";\n isStaticRoute = false;\n }\n matchedNodes.push(childNode);\n node = childNode;\n }\n }\n for (const [depth, node2] of matchedNodes.entries()) {\n node2.maxDepth = Math.max(matchedNodes.length - depth, node2.maxDepth || 0);\n }\n node.data = data;\n if (isStaticRoute === true) {\n ctx.staticRoutesMap[path] = node;\n }\n return node;\n}\nfunction remove(ctx, path) {\n let success = false;\n const sections = path.split(\"/\");\n let node = ctx.rootNode;\n for (const section of sections) {\n node = node.children.get(section);\n if (!node) {\n return success;\n }\n }\n if (node.data) {\n const lastSection = sections.at(-1) || \"\";\n node.data = null;\n if (Object.keys(node.children).length === 0 && node.parent) {\n node.parent.children.delete(lastSection);\n node.parent.wildcardChildNode = null;\n node.parent.placeholderChildren = [];\n }\n success = true;\n }\n return success;\n}\nfunction createRadixNode(options = {}) {\n return {\n type: options.type || NODE_TYPES.NORMAL,\n maxDepth: 0,\n parent: options.parent || null,\n children: /* @__PURE__ */ new Map(),\n data: options.data || null,\n paramName: options.paramName || null,\n wildcardChildNode: null,\n placeholderChildren: []\n };\n}\nfunction getNodeType(str) {\n if (str.startsWith(\"**\")) {\n return NODE_TYPES.WILDCARD;\n }\n if (str[0] === \":\" || str === \"*\") {\n return NODE_TYPES.PLACEHOLDER;\n }\n return NODE_TYPES.NORMAL;\n}\n\nfunction toRouteMatcher(router) {\n const table = _routerNodeToTable(\"\", router.ctx.rootNode);\n return _createMatcher(table, router.ctx.options.strictTrailingSlash);\n}\nfunction _createMatcher(table, strictTrailingSlash) {\n return {\n ctx: { table },\n matchAll: (path) => _matchRoutes(path, table, strictTrailingSlash)\n };\n}\nfunction _createRouteTable() {\n return {\n static: /* @__PURE__ */ new Map(),\n wildcard: /* @__PURE__ */ new Map(),\n dynamic: /* @__PURE__ */ new Map()\n };\n}\nfunction _exportMatcherFromTable(table) {\n const obj = /* @__PURE__ */ Object.create(null);\n for (const property in table) {\n obj[property] = property === \"dynamic\" ? Object.fromEntries(\n [...table[property].entries()].map(([key, value]) => [\n key,\n _exportMatcherFromTable(value)\n ])\n ) : Object.fromEntries(table[property].entries());\n }\n return obj;\n}\nfunction exportMatcher(matcher) {\n return _exportMatcherFromTable(matcher.ctx.table);\n}\nfunction _createTableFromExport(matcherExport) {\n const table = {};\n for (const property in matcherExport) {\n table[property] = property === \"dynamic\" ? new Map(\n Object.entries(matcherExport[property]).map(([key, value]) => [\n key,\n _createTableFromExport(value)\n ])\n ) : new Map(\n Object.entries(matcherExport[property])\n );\n }\n return table;\n}\nfunction createMatcherFromExport(matcherExport) {\n return _createMatcher(_createTableFromExport(matcherExport));\n}\nfunction _matchRoutes(path, table, strictTrailingSlash) {\n if (strictTrailingSlash !== true && path.endsWith(\"/\")) {\n path = path.slice(0, -1) || \"/\";\n }\n const matches = [];\n for (const [key, value] of _sortRoutesMap(table.wildcard)) {\n if (path === key || path.startsWith(key + \"/\")) {\n matches.push(value);\n }\n }\n for (const [key, value] of _sortRoutesMap(table.dynamic)) {\n if (path.startsWith(key + \"/\")) {\n const subPath = \"/\" + path.slice(key.length).split(\"/\").splice(2).join(\"/\");\n matches.push(..._matchRoutes(subPath, value));\n }\n }\n const staticMatch = table.static.get(path);\n if (staticMatch) {\n matches.push(staticMatch);\n }\n return matches.filter(Boolean);\n}\nfunction _sortRoutesMap(m) {\n return [...m.entries()].sort((a, b) => a[0].length - b[0].length);\n}\nfunction _routerNodeToTable(initialPath, initialNode) {\n const table = _createRouteTable();\n function _addNode(path, node) {\n if (path) {\n if (node.type === NODE_TYPES.NORMAL && !(path.includes(\"*\") || path.includes(\":\"))) {\n if (node.data) {\n table.static.set(path, node.data);\n }\n } else if (node.type === NODE_TYPES.WILDCARD) {\n table.wildcard.set(path.replace(\"/**\", \"\"), node.data);\n } else if (node.type === NODE_TYPES.PLACEHOLDER) {\n const subTable = _routerNodeToTable(\"\", node);\n if (node.data) {\n subTable.static.set(\"/\", node.data);\n }\n table.dynamic.set(path.replace(/\\/\\*|\\/:\\w+/, \"\"), subTable);\n return;\n }\n }\n for (const [childPath, child] of node.children.entries()) {\n _addNode(`${path}/${childPath}`.replace(\"//\", \"/\"), child);\n }\n }\n _addNode(initialPath, initialNode);\n return table;\n}\n\nexport { NODE_TYPES, createMatcherFromExport, createRouter, exportMatcher, toRouteMatcher };\n","/**\r\n * Flight Router - File-based routing with dynamic patterns\r\n */\r\n\r\nimport { createRouter as createRadixRouter, type RadixRouter } from 'radix3';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface RouteParams {\r\n [key: string]: string | string[];\r\n}\r\n\r\nexport interface Route<T = unknown> {\r\n /** Route path pattern (e.g., '/blog/[slug]', '/api/[...path]') */\r\n path: string;\r\n /** Handler or component for this route */\r\n handler: T;\r\n /** Rendering mode for this route */\r\n mode?: 'ssr' | 'ssg' | 'csr' | 'isr';\r\n /** Metadata for the route */\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface RouteMatch<T = unknown> {\r\n /** The matched route */\r\n route: Route<T>;\r\n /** Extracted parameters from the URL */\r\n params: RouteParams;\r\n /** The original path that was matched */\r\n path: string;\r\n}\r\n\r\nexport interface Router<T = unknown> {\r\n /** Add a route to the router */\r\n add(route: Route<T>): void;\r\n /** Add multiple routes */\r\n addAll(routes: Route<T>[]): void;\r\n /** Match a path against registered routes */\r\n match(path: string): RouteMatch<T> | null;\r\n /** Get all registered routes */\r\n routes(): Route<T>[];\r\n /** Remove a route by path */\r\n remove(path: string): boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * Convert Flight route pattern to radix3 pattern\r\n * Flight: /blog/[slug] -> radix3: /blog/:slug\r\n * Flight: /api/[...path] -> radix3: /api/**:path\r\n */\r\nfunction convertPattern(pattern: string): string {\r\n return pattern\r\n // Convert catch-all [...param] to **:param\r\n .replace(/\\[\\.\\.\\.(\\w+)\\]/g, '**:$1')\r\n // Convert dynamic [param] to :param\r\n .replace(/\\[(\\w+)\\]/g, ':$1');\r\n}\r\n\r\n/**\r\n * Create a new Flight router instance\r\n */\r\nexport function createRouter<T = unknown>(): Router<T> {\r\n const radix: RadixRouter<Route<T>> = createRadixRouter();\r\n const routeMap = new Map<string, Route<T>>();\r\n\r\n return {\r\n add(route: Route<T>): void {\r\n const radixPath = convertPattern(route.path);\r\n radix.insert(radixPath, route);\r\n routeMap.set(route.path, route);\r\n },\r\n\r\n addAll(routes: Route<T>[]): void {\r\n for (const route of routes) {\r\n this.add(route);\r\n }\r\n },\r\n\r\n match(path: string): RouteMatch<T> | null {\r\n const result = radix.lookup(path);\r\n\r\n if (!result) {\r\n return null;\r\n }\r\n\r\n // Extract params from radix3 result\r\n const params: RouteParams = {};\r\n if (result.params) {\r\n for (const [key, value] of Object.entries(result.params)) {\r\n if (value !== undefined) {\r\n params[key] = value as string | string[];\r\n }\r\n }\r\n }\r\n\r\n return {\r\n route: result,\r\n params,\r\n path,\r\n };\r\n },\r\n\r\n routes(): Route<T>[] {\r\n return Array.from(routeMap.values());\r\n },\r\n\r\n remove(path: string): boolean {\r\n if (routeMap.has(path)) {\r\n const radixPath = convertPattern(path);\r\n radix.remove(radixPath);\r\n routeMap.delete(path);\r\n return true;\r\n }\r\n return false;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// File System Router Utilities\r\n// ============================================================================\r\n\r\nexport interface FileRoute {\r\n /** File path relative to routes directory */\r\n filePath: string;\r\n /** Generated route path */\r\n routePath: string;\r\n}\r\n\r\n/**\r\n * Convert a file path to a route path\r\n * \r\n * Examples:\r\n * - index.tsx -> /\r\n * - about.tsx -> /about\r\n * - blog/index.tsx -> /blog\r\n * - blog/[slug].tsx -> /blog/[slug]\r\n * - api/[...path].ts -> /api/[...path]\r\n * - (group)/settings.tsx -> /settings (groups are ignored)\r\n */\r\nexport function filePathToRoutePath(filePath: string): string {\r\n let routePath = filePath\r\n // Remove file extension\r\n .replace(/\\.(tsx?|jsx?|vue|svelte|astro)$/, '')\r\n // Remove index files\r\n .replace(/\\/index$/, '')\r\n .replace(/^index$/, '')\r\n // Remove route groups (parentheses)\r\n .replace(/\\([^)]+\\)\\//g, '')\r\n .replace(/\\/\\([^)]+\\)/g, '');\r\n\r\n // Ensure path starts with /\r\n if (!routePath.startsWith('/')) {\r\n routePath = '/' + routePath;\r\n }\r\n\r\n // Handle root\r\n if (routePath === '/') {\r\n return '/';\r\n }\r\n\r\n // Remove trailing slash\r\n return routePath.replace(/\\/$/, '');\r\n}\r\n\r\n/**\r\n * Sort routes by specificity (most specific first)\r\n * Static routes come before dynamic routes\r\n */\r\nexport function sortRoutes<T>(routes: Route<T>[]): Route<T>[] {\r\n return [...routes].sort((a, b) => {\r\n const aSegments = a.path.split('/');\r\n const bSegments = b.path.split('/');\r\n\r\n // Count dynamic segments\r\n const aDynamic = aSegments.filter(s => s.startsWith('[') || s.startsWith(':')).length;\r\n const bDynamic = bSegments.filter(s => s.startsWith('[') || s.startsWith(':')).length;\r\n\r\n // More segments = more specific\r\n if (aSegments.length !== bSegments.length) {\r\n return bSegments.length - aSegments.length;\r\n }\r\n\r\n // Fewer dynamic segments = more specific\r\n if (aDynamic !== bDynamic) {\r\n return aDynamic - bDynamic;\r\n }\r\n\r\n // Catch-all routes are less specific\r\n const aCatchAll = a.path.includes('[...');\r\n const bCatchAll = b.path.includes('[...');\r\n if (aCatchAll !== bCatchAll) {\r\n return aCatchAll ? 1 : -1;\r\n }\r\n\r\n // Alphabetical for consistency\r\n return a.path.localeCompare(b.path);\r\n });\r\n}\r\n"]}
|