@flight-framework/core 0.2.5 → 0.2.6
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 +347 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# @flight-framework/core
|
|
2
|
+
|
|
3
|
+
Core primitives for Flight Framework - the agnostic full-stack framework with maximum flexibility and zero lock-in.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-Render Mode** - SSR, SSG, ISR, and streaming in one unified API
|
|
8
|
+
- **Framework Agnostic** - Works with React, Vue, Svelte, Solid, HTMX, and more
|
|
9
|
+
- **File-Based Routing** - Automatic route discovery from filesystem
|
|
10
|
+
- **Server Actions** - Type-safe server functions with form support
|
|
11
|
+
- **Streaming SSR** - Out-of-order streaming with priority control
|
|
12
|
+
- **Islands Architecture** - Partial hydration with any UI framework
|
|
13
|
+
- **Caching System** - Pluggable cache adapters with deduplication
|
|
14
|
+
- **Error Handling** - Structured errors with type guards and React integration
|
|
15
|
+
- **Zero Lock-in** - Every component is replaceable
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @flight-framework/core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Configuration
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// flight.config.ts
|
|
29
|
+
import { defineConfig } from '@flight-framework/core';
|
|
30
|
+
|
|
31
|
+
export default defineConfig({
|
|
32
|
+
server: {
|
|
33
|
+
port: 3000,
|
|
34
|
+
},
|
|
35
|
+
render: {
|
|
36
|
+
defaultMode: 'ssr',
|
|
37
|
+
streaming: true,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Create a Server
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { createServer } from '@flight-framework/core';
|
|
46
|
+
|
|
47
|
+
const server = createServer({
|
|
48
|
+
port: 3000,
|
|
49
|
+
routes: [
|
|
50
|
+
{ path: '/', handler: homeHandler },
|
|
51
|
+
{ path: '/api/*', handler: apiHandler },
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await server.start();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### File-Based Routing
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { createFileRouter, scanRoutes } from '@flight-framework/core';
|
|
62
|
+
|
|
63
|
+
const routes = await scanRoutes('./src/routes');
|
|
64
|
+
const router = createFileRouter({ routes });
|
|
65
|
+
|
|
66
|
+
// Routes are discovered automatically:
|
|
67
|
+
// src/routes/index.page.tsx -> /
|
|
68
|
+
// src/routes/about.page.tsx -> /about
|
|
69
|
+
// src/routes/blog/[slug].page.tsx -> /blog/:slug
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Modules
|
|
73
|
+
|
|
74
|
+
### Router
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { createRouter } from '@flight-framework/core/router';
|
|
78
|
+
|
|
79
|
+
const router = createRouter();
|
|
80
|
+
router.add('GET', '/users/:id', userHandler);
|
|
81
|
+
|
|
82
|
+
const match = router.match('GET', '/users/123');
|
|
83
|
+
// { params: { id: '123' }, handler: userHandler }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Cache
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { createCache, memory, cached, dedupe } from '@flight-framework/core/cache';
|
|
90
|
+
|
|
91
|
+
// Create a cache with memory adapter
|
|
92
|
+
const cache = createCache({
|
|
93
|
+
adapter: memory(),
|
|
94
|
+
ttl: 60000,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Cache function results
|
|
98
|
+
const getUser = cached(
|
|
99
|
+
async (id: string) => fetchUser(id),
|
|
100
|
+
{ ttl: 5000, key: (id) => `user:${id}` }
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Deduplicate concurrent requests
|
|
104
|
+
const getData = dedupe(fetchData);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Server Actions
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { registerAction, executeAction, cookies } from '@flight-framework/core/actions';
|
|
111
|
+
|
|
112
|
+
// Register a server action
|
|
113
|
+
registerAction('createUser', async (formData: FormData) => {
|
|
114
|
+
const name = formData.get('name');
|
|
115
|
+
const user = await db.users.create({ name });
|
|
116
|
+
|
|
117
|
+
cookies().set('user_id', user.id);
|
|
118
|
+
|
|
119
|
+
return { success: true, user };
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Execute from client
|
|
123
|
+
const result = await executeAction('createUser', formData);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Streaming SSR
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import {
|
|
130
|
+
createStreamingSSR,
|
|
131
|
+
streamWithPriority
|
|
132
|
+
} from '@flight-framework/core/streaming';
|
|
133
|
+
|
|
134
|
+
// Basic streaming
|
|
135
|
+
const stream = await createStreamingSSR({
|
|
136
|
+
component: App,
|
|
137
|
+
props: { data },
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Priority-based streaming (out-of-order)
|
|
141
|
+
const result = await streamWithPriority({
|
|
142
|
+
boundaries: [
|
|
143
|
+
{ id: 'header', priority: 100, render: Header },
|
|
144
|
+
{ id: 'sidebar', priority: 50, render: Sidebar },
|
|
145
|
+
{ id: 'content', priority: 75, render: Content },
|
|
146
|
+
],
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Islands Architecture
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import {
|
|
154
|
+
defineIsland,
|
|
155
|
+
hydrateIslands,
|
|
156
|
+
createReactIslandAdapter
|
|
157
|
+
} from '@flight-framework/core/islands';
|
|
158
|
+
|
|
159
|
+
// Define an island component
|
|
160
|
+
const Counter = defineIsland({
|
|
161
|
+
name: 'counter',
|
|
162
|
+
component: CounterComponent,
|
|
163
|
+
hydrate: 'visible', // 'load' | 'visible' | 'idle' | 'interaction'
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Client-side hydration
|
|
167
|
+
hydrateIslands({
|
|
168
|
+
adapter: createReactIslandAdapter(),
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Middleware
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { createMiddlewareChain } from '@flight-framework/core/middleware';
|
|
176
|
+
|
|
177
|
+
const middleware = createMiddlewareChain([
|
|
178
|
+
async (ctx, next) => {
|
|
179
|
+
const start = Date.now();
|
|
180
|
+
await next();
|
|
181
|
+
console.log(`Request took ${Date.now() - start}ms`);
|
|
182
|
+
},
|
|
183
|
+
authMiddleware,
|
|
184
|
+
loggingMiddleware,
|
|
185
|
+
]);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Error Handling
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import {
|
|
192
|
+
FlightError,
|
|
193
|
+
createError,
|
|
194
|
+
isFlightError,
|
|
195
|
+
createNotFound,
|
|
196
|
+
createForbidden,
|
|
197
|
+
} from '@flight-framework/core/errors';
|
|
198
|
+
|
|
199
|
+
// Create typed errors
|
|
200
|
+
throw createNotFound('Page not found');
|
|
201
|
+
throw createForbidden('Access denied');
|
|
202
|
+
|
|
203
|
+
// Create custom errors
|
|
204
|
+
throw createError({
|
|
205
|
+
statusCode: 422,
|
|
206
|
+
message: 'Validation failed',
|
|
207
|
+
data: { field: 'email', error: 'Invalid format' },
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Type guards
|
|
211
|
+
if (isFlightError(error)) {
|
|
212
|
+
console.log(error.statusCode, error.digest);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### React Integration
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { ErrorProvider, useError, useFlightError } from '@flight-framework/core/react';
|
|
220
|
+
|
|
221
|
+
// Wrap your app
|
|
222
|
+
<ErrorProvider onError={console.error}>
|
|
223
|
+
<App />
|
|
224
|
+
</ErrorProvider>
|
|
225
|
+
|
|
226
|
+
// Use in components
|
|
227
|
+
function MyComponent() {
|
|
228
|
+
const { error, clearError } = useFlightError();
|
|
229
|
+
|
|
230
|
+
if (error) {
|
|
231
|
+
return <ErrorDisplay error={error} onRetry={clearError} />;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return <Content />;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Metadata (SEO)
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { renderMetadataToHead, type Metadata } from '@flight-framework/core';
|
|
242
|
+
|
|
243
|
+
const metadata: Metadata = {
|
|
244
|
+
title: 'My Page',
|
|
245
|
+
description: 'Page description',
|
|
246
|
+
openGraph: {
|
|
247
|
+
title: 'OG Title',
|
|
248
|
+
image: '/og-image.png',
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const headHtml = renderMetadataToHead(metadata);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Route Rules (ISR/SSG)
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { defineConfig } from '@flight-framework/core';
|
|
259
|
+
|
|
260
|
+
export default defineConfig({
|
|
261
|
+
routeRules: {
|
|
262
|
+
'/': { prerender: true },
|
|
263
|
+
'/blog/**': { isr: 3600 },
|
|
264
|
+
'/api/**': { ssr: true },
|
|
265
|
+
'/static/**': { static: true },
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Revalidation
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import {
|
|
274
|
+
revalidatePath,
|
|
275
|
+
revalidateTag,
|
|
276
|
+
createRevalidateHandler
|
|
277
|
+
} from '@flight-framework/core';
|
|
278
|
+
|
|
279
|
+
// On-demand revalidation
|
|
280
|
+
await revalidatePath('/blog/my-post');
|
|
281
|
+
await revalidateTag('blog-posts');
|
|
282
|
+
|
|
283
|
+
// Create revalidation API handler
|
|
284
|
+
const handler = createRevalidateHandler({
|
|
285
|
+
secret: process.env.REVALIDATE_SECRET,
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Environment Utilities
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import {
|
|
293
|
+
isServer,
|
|
294
|
+
isBrowser,
|
|
295
|
+
isProduction,
|
|
296
|
+
isDevelopment
|
|
297
|
+
} from '@flight-framework/core/utils';
|
|
298
|
+
|
|
299
|
+
if (isServer()) {
|
|
300
|
+
// Server-only code
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (isDevelopment()) {
|
|
304
|
+
console.log('Debug info');
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Module Exports
|
|
309
|
+
|
|
310
|
+
| Export | Description |
|
|
311
|
+
|--------|-------------|
|
|
312
|
+
| `@flight-framework/core` | Main entry with all primitives |
|
|
313
|
+
| `@flight-framework/core/router` | Routing utilities |
|
|
314
|
+
| `@flight-framework/core/cache` | Caching system |
|
|
315
|
+
| `@flight-framework/core/server` | HTTP server |
|
|
316
|
+
| `@flight-framework/core/render` | Rendering modes |
|
|
317
|
+
| `@flight-framework/core/middleware` | Middleware chain |
|
|
318
|
+
| `@flight-framework/core/actions` | Server actions |
|
|
319
|
+
| `@flight-framework/core/streaming` | Streaming SSR |
|
|
320
|
+
| `@flight-framework/core/islands` | Islands architecture |
|
|
321
|
+
| `@flight-framework/core/errors` | Error handling |
|
|
322
|
+
| `@flight-framework/core/react` | React integration |
|
|
323
|
+
| `@flight-framework/core/rsc` | React Server Components |
|
|
324
|
+
| `@flight-framework/core/config` | Configuration |
|
|
325
|
+
| `@flight-framework/core/utils` | Environment utilities |
|
|
326
|
+
|
|
327
|
+
## TypeScript
|
|
328
|
+
|
|
329
|
+
Full TypeScript support with exported types for all APIs:
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import type {
|
|
333
|
+
FlightConfig,
|
|
334
|
+
Route,
|
|
335
|
+
RouteMatch,
|
|
336
|
+
Cache,
|
|
337
|
+
CacheAdapter,
|
|
338
|
+
Middleware,
|
|
339
|
+
FlightError,
|
|
340
|
+
Metadata,
|
|
341
|
+
StreamingHints,
|
|
342
|
+
} from '@flight-framework/core';
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT
|