@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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/dist/actions/index.d.ts +108 -0
  3. package/dist/actions/index.js +3 -0
  4. package/dist/actions/index.js.map +1 -0
  5. package/dist/adapters/index.d.ts +243 -0
  6. package/dist/adapters/index.js +3 -0
  7. package/dist/adapters/index.js.map +1 -0
  8. package/dist/cache/index.d.ts +76 -0
  9. package/dist/cache/index.js +3 -0
  10. package/dist/cache/index.js.map +1 -0
  11. package/dist/chunk-3AIQVGTM.js +120 -0
  12. package/dist/chunk-3AIQVGTM.js.map +1 -0
  13. package/dist/chunk-AFSKXC6V.js +188 -0
  14. package/dist/chunk-AFSKXC6V.js.map +1 -0
  15. package/dist/chunk-AJ3IBYXT.js +47 -0
  16. package/dist/chunk-AJ3IBYXT.js.map +1 -0
  17. package/dist/chunk-GCQZ4FHI.js +245 -0
  18. package/dist/chunk-GCQZ4FHI.js.map +1 -0
  19. package/dist/chunk-I5RHYGX6.js +167 -0
  20. package/dist/chunk-I5RHYGX6.js.map +1 -0
  21. package/dist/chunk-KWFX6WHG.js +311 -0
  22. package/dist/chunk-KWFX6WHG.js.map +1 -0
  23. package/dist/chunk-Q4C5CCHK.js +13 -0
  24. package/dist/chunk-Q4C5CCHK.js.map +1 -0
  25. package/dist/chunk-QEFGUHYD.js +221 -0
  26. package/dist/chunk-QEFGUHYD.js.map +1 -0
  27. package/dist/chunk-TKXN7KGE.js +145 -0
  28. package/dist/chunk-TKXN7KGE.js.map +1 -0
  29. package/dist/chunk-WAGCTWGY.js +93 -0
  30. package/dist/chunk-WAGCTWGY.js.map +1 -0
  31. package/dist/chunk-Y22KEW2F.js +223 -0
  32. package/dist/chunk-Y22KEW2F.js.map +1 -0
  33. package/dist/chunk-ZVC3ZWLM.js +52 -0
  34. package/dist/chunk-ZVC3ZWLM.js.map +1 -0
  35. package/dist/config/index.d.ts +146 -0
  36. package/dist/config/index.js +3 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/file-router/index.d.ts +71 -0
  39. package/dist/file-router/index.js +3 -0
  40. package/dist/file-router/index.js.map +1 -0
  41. package/dist/handlers/index.d.ts +59 -0
  42. package/dist/handlers/index.js +3 -0
  43. package/dist/handlers/index.js.map +1 -0
  44. package/dist/index.d.ts +23 -0
  45. package/dist/index.js +19 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/middleware/index.d.ts +152 -0
  48. package/dist/middleware/index.js +3 -0
  49. package/dist/middleware/index.js.map +1 -0
  50. package/dist/render/index.d.ts +131 -0
  51. package/dist/render/index.js +3 -0
  52. package/dist/render/index.js.map +1 -0
  53. package/dist/router/index.d.ts +65 -0
  54. package/dist/router/index.js +3 -0
  55. package/dist/router/index.js.map +1 -0
  56. package/dist/rsc/index.d.ts +131 -0
  57. package/dist/rsc/index.js +3 -0
  58. package/dist/rsc/index.js.map +1 -0
  59. package/dist/server/index.d.ts +135 -0
  60. package/dist/server/index.js +6 -0
  61. package/dist/server/index.js.map +1 -0
  62. package/dist/streaming/index.d.ts +169 -0
  63. package/dist/streaming/index.js +3 -0
  64. package/dist/streaming/index.js.map +1 -0
  65. package/package.json +100 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Flight Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @flight/core - Server Actions
3
+ *
4
+ * Implementation of React 19 style Server Actions.
5
+ * Functions marked with 'use server' run on the server.
6
+ */
7
+ /**
8
+ * Server action metadata
9
+ */
10
+ interface ServerAction {
11
+ /** Unique action ID */
12
+ id: string;
13
+ /** Original function name */
14
+ name: string;
15
+ /** File path where action is defined */
16
+ filePath: string;
17
+ /** The actual action function */
18
+ fn: (...args: unknown[]) => Promise<unknown>;
19
+ }
20
+ /**
21
+ * Server action result
22
+ */
23
+ interface ActionResult<T = unknown> {
24
+ success: boolean;
25
+ data?: T;
26
+ error?: string;
27
+ }
28
+ /**
29
+ * Form action data
30
+ */
31
+ interface FormActionData {
32
+ actionId: string;
33
+ formData: FormData;
34
+ }
35
+ /**
36
+ * Register a server action
37
+ */
38
+ declare function registerAction(action: ServerAction): void;
39
+ /**
40
+ * Get a registered action by ID
41
+ */
42
+ declare function getAction(id: string): ServerAction | undefined;
43
+ /**
44
+ * Get all registered actions
45
+ */
46
+ declare function getAllActions(): ServerAction[];
47
+ /**
48
+ * Clear all registered actions (useful for testing)
49
+ */
50
+ declare function clearActions(): void;
51
+ /**
52
+ * Execute a server action
53
+ */
54
+ declare function executeAction<T = unknown>(actionId: string, args: unknown[]): Promise<ActionResult<T>>;
55
+ /**
56
+ * Execute a form action
57
+ */
58
+ declare function executeFormAction<T = unknown>(actionId: string, formData: FormData): Promise<ActionResult<T>>;
59
+ /**
60
+ * Generate a unique action ID
61
+ */
62
+ declare function generateActionId(name: string, filePath: string): string;
63
+ /**
64
+ * Get cookies in server action context
65
+ */
66
+ declare function cookies(): {
67
+ get: (name: string) => string | undefined;
68
+ set: (name: string, value: string, options?: CookieOptions) => void;
69
+ delete: (name: string) => void;
70
+ };
71
+ interface CookieOptions {
72
+ maxAge?: number;
73
+ expires?: Date;
74
+ path?: string;
75
+ domain?: string;
76
+ secure?: boolean;
77
+ httpOnly?: boolean;
78
+ sameSite?: 'strict' | 'lax' | 'none';
79
+ }
80
+ /**
81
+ * Redirect in server action context
82
+ */
83
+ declare function redirect(url: string): never;
84
+ /**
85
+ * Special error for redirects
86
+ */
87
+ declare class RedirectError extends Error {
88
+ readonly url: string;
89
+ constructor(url: string);
90
+ }
91
+ /**
92
+ * Check if error is a redirect
93
+ */
94
+ declare function isRedirectError(error: unknown): error is RedirectError;
95
+ /**
96
+ * Parse form data to typed object
97
+ */
98
+ declare function parseFormData<T extends Record<string, string>>(formData: FormData): T;
99
+ /**
100
+ * Create action reference for form action attribute
101
+ */
102
+ declare function createActionReference(actionId: string): string;
103
+ /**
104
+ * Handle action request from client
105
+ */
106
+ declare function handleActionRequest(request: Request): Promise<Response>;
107
+
108
+ export { type ActionResult, type CookieOptions, type FormActionData, RedirectError, type ServerAction, clearActions, cookies, createActionReference, executeAction, executeFormAction, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, redirect, registerAction };
@@ -0,0 +1,3 @@
1
+ export { RedirectError, clearActions, cookies, createActionReference, executeAction, executeFormAction, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, redirect, registerAction } from '../chunk-TKXN7KGE.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Flight Adapters - Universal deployment adapters
3
+ *
4
+ * Adapters transform Flight's output for different deployment targets.
5
+ * The user chooses where to deploy - Flight provides the adapters.
6
+ */
7
+ /** Build manifest containing all generated assets */
8
+ interface BuildManifest {
9
+ /** Entry points by name */
10
+ entries: Record<string, string>;
11
+ /** All generated files */
12
+ files: string[];
13
+ /** Route information */
14
+ routes: RouteManifestEntry[];
15
+ /** Server entry point (if applicable) */
16
+ serverEntry?: string;
17
+ /** Client entry point */
18
+ clientEntry?: string;
19
+ }
20
+ /** Route information in manifest */
21
+ interface RouteManifestEntry {
22
+ /** Route path pattern */
23
+ path: string;
24
+ /** Render mode for this route */
25
+ mode: 'ssr' | 'ssg' | 'csr' | 'isr';
26
+ /** Component/handler file path */
27
+ component: string;
28
+ /** Pre-rendered paths (for SSG/ISR) */
29
+ prerendered?: string[];
30
+ }
31
+ /** Builder utilities passed to adapters */
32
+ interface AdapterBuilder {
33
+ /** Build manifest */
34
+ manifest: BuildManifest;
35
+ /** Project root directory */
36
+ root: string;
37
+ /** Build output directory */
38
+ outDir: string;
39
+ /** Read a file from the build output */
40
+ readFile(path: string): Promise<string>;
41
+ /** Write a file to the adapter output */
42
+ writeFile(path: string, content: string): Promise<void>;
43
+ /** Copy files from build to adapter output */
44
+ copy(from: string, to: string): Promise<void>;
45
+ /** Get all files matching a pattern */
46
+ glob(pattern: string): Promise<string[]>;
47
+ /** Compress files for production */
48
+ compress?(files: string[]): Promise<void>;
49
+ /** Log info message */
50
+ log: {
51
+ info(message: string): void;
52
+ warn(message: string): void;
53
+ error(message: string): void;
54
+ };
55
+ }
56
+ /** Flight adapter interface */
57
+ interface FlightAdapter {
58
+ /** Adapter name */
59
+ name: string;
60
+ /**
61
+ * Transform the build output for the target platform
62
+ * This is called after Flight's build process completes
63
+ */
64
+ adapt(builder: AdapterBuilder): Promise<void>;
65
+ /**
66
+ * Optional: Start listening for requests (for Node.js/Bun adapters)
67
+ */
68
+ listen?(server: unknown, port: number): Promise<void>;
69
+ /**
70
+ * Optional: Emulate the platform during development
71
+ * Useful for testing platform-specific behavior locally
72
+ */
73
+ emulate?(): {
74
+ /** Platform-specific env vars */
75
+ env?: Record<string, string>;
76
+ /** Custom middleware for dev server */
77
+ middleware?: unknown[];
78
+ };
79
+ /**
80
+ * Optional: Declare what this adapter supports
81
+ * Flight uses this to warn about incompatible features
82
+ */
83
+ supports?: {
84
+ /** Can read files at runtime (for dynamic content) */
85
+ read?: () => boolean;
86
+ /** Supports streaming responses */
87
+ streaming?: () => boolean;
88
+ /** Supports WebSockets */
89
+ websockets?: () => boolean;
90
+ /** Supports edge runtime */
91
+ edge?: () => boolean;
92
+ /** Supports Node.js runtime */
93
+ node?: () => boolean;
94
+ };
95
+ }
96
+ interface AdapterOptions {
97
+ name: string;
98
+ adapt: (builder: AdapterBuilder) => Promise<void>;
99
+ emulate?: FlightAdapter['emulate'];
100
+ supports?: FlightAdapter['supports'];
101
+ }
102
+ /**
103
+ * Create a Flight adapter
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * import { createAdapter } from '@flight/core/adapters';
108
+ *
109
+ * export default function myAdapter(options = {}) {
110
+ * return createAdapter({
111
+ * name: 'my-adapter',
112
+ * async adapt(builder) {
113
+ * // Transform build output for your platform
114
+ * },
115
+ * });
116
+ * }
117
+ * ```
118
+ */
119
+ declare function createAdapter(options: AdapterOptions): FlightAdapter;
120
+ /**
121
+ * Storage Adapter Interface
122
+ *
123
+ * Implement this to use any storage provider:
124
+ * S3, Supabase Storage, Cloudflare R2, local filesystem, etc.
125
+ */
126
+ interface StorageAdapter {
127
+ name: string;
128
+ /** Upload a file */
129
+ upload(path: string, data: Buffer | Uint8Array | string, options?: {
130
+ contentType?: string;
131
+ metadata?: Record<string, string>;
132
+ }): Promise<{
133
+ url: string;
134
+ path: string;
135
+ }>;
136
+ /** Download a file */
137
+ download(path: string): Promise<Buffer>;
138
+ /** Delete a file */
139
+ delete(path: string): Promise<void>;
140
+ /** List files with optional prefix */
141
+ list(prefix?: string): Promise<string[]>;
142
+ /** Get a signed URL for direct access */
143
+ getSignedUrl?(path: string, options?: {
144
+ expiresIn?: number;
145
+ operation?: 'read' | 'write';
146
+ }): Promise<string>;
147
+ }
148
+ /**
149
+ * Auth Adapter Interface
150
+ *
151
+ * Implement this to use any auth provider:
152
+ * Better Auth, Supabase Auth, Lucia, Auth.js, etc.
153
+ */
154
+ interface AuthAdapter {
155
+ name: string;
156
+ /** Get the current user from a request */
157
+ getUser(request: Request): Promise<AuthUser | null>;
158
+ /** Verify a session token */
159
+ verifySession(token: string): Promise<AuthSession | null>;
160
+ /** Optional middleware for handling auth-specific routes (e.g., /api/auth/*) */
161
+ middleware?: (req: Request) => Promise<Response | null>;
162
+ }
163
+ interface AuthUser {
164
+ id: string;
165
+ email?: string;
166
+ name?: string;
167
+ avatar?: string;
168
+ metadata?: Record<string, unknown>;
169
+ }
170
+ interface AuthSession {
171
+ user: AuthUser;
172
+ expiresAt: Date;
173
+ token: string;
174
+ }
175
+ /**
176
+ * Email Adapter Interface
177
+ *
178
+ * Implement this to use any email provider:
179
+ * Resend, SendGrid, Postmark, SMTP, etc.
180
+ */
181
+ interface EmailAdapter {
182
+ name: string;
183
+ /** Send an email */
184
+ send(options: {
185
+ to: string | string[];
186
+ subject: string;
187
+ html?: string;
188
+ text?: string;
189
+ from?: string;
190
+ replyTo?: string;
191
+ attachments?: Array<{
192
+ filename: string;
193
+ content: Buffer | string;
194
+ contentType?: string;
195
+ }>;
196
+ }): Promise<{
197
+ id: string;
198
+ success: boolean;
199
+ }>;
200
+ }
201
+ /**
202
+ * Queue/Jobs Adapter Interface
203
+ *
204
+ * Implement this to use any job queue:
205
+ * BullMQ, Quirrel, Inngest, custom, etc.
206
+ */
207
+ interface JobsAdapter {
208
+ name: string;
209
+ /** Add a job to the queue */
210
+ enqueue<T>(jobName: string, data: T, options?: {
211
+ delay?: number;
212
+ priority?: number;
213
+ retries?: number;
214
+ }): Promise<{
215
+ id: string;
216
+ }>;
217
+ /** Schedule a recurring job */
218
+ schedule?(jobName: string, cron: string, data?: unknown): Promise<{
219
+ id: string;
220
+ }>;
221
+ /** Cancel a job */
222
+ cancel?(jobId: string): Promise<void>;
223
+ }
224
+ /**
225
+ * Database Adapter Interface
226
+ *
227
+ * Note: This is intentionally minimal.
228
+ * For databases, use your preferred ORM/query builder directly.
229
+ * This interface is for Flight's internal use (sessions, cache, etc.)
230
+ */
231
+ interface DatabaseAdapter {
232
+ name: string;
233
+ /** Raw query execution */
234
+ query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
235
+ /** Execute a mutation */
236
+ execute(sql: string, params?: unknown[]): Promise<{
237
+ rowsAffected: number;
238
+ }>;
239
+ /** Transaction support */
240
+ transaction?<T>(fn: (tx: DatabaseAdapter) => Promise<T>): Promise<T>;
241
+ }
242
+
243
+ export { type AdapterBuilder, type AdapterOptions, type AuthAdapter, type AuthSession, type AuthUser, type BuildManifest, type DatabaseAdapter, type EmailAdapter, type FlightAdapter, type JobsAdapter, type RouteManifestEntry, type StorageAdapter, createAdapter };
@@ -0,0 +1,3 @@
1
+ export { createAdapter } from '../chunk-Q4C5CCHK.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Flight Cache - Agnostic caching primitives
3
+ *
4
+ * Flight provides the interface, you choose the implementation.
5
+ * Use in-memory, Redis, Cloudflare KV, or anything else.
6
+ */
7
+ interface CacheOptions {
8
+ /** Time-to-live in seconds */
9
+ ttl?: number;
10
+ /** Cache tags for invalidation */
11
+ tags?: string[];
12
+ /** Stale-while-revalidate time in seconds */
13
+ swr?: number;
14
+ }
15
+ interface CacheEntry<T> {
16
+ /** Cached value */
17
+ value: T;
18
+ /** When this entry expires (timestamp) */
19
+ expiresAt?: number;
20
+ /** When this entry becomes stale (timestamp) */
21
+ staleAt?: number;
22
+ /** Cache tags for invalidation */
23
+ tags?: string[];
24
+ /** When this entry was created */
25
+ createdAt: number;
26
+ }
27
+ interface Cache {
28
+ /** Get a value from cache */
29
+ get<T>(key: string): Promise<T | undefined>;
30
+ /** Set a value in cache */
31
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
32
+ /** Delete a value from cache */
33
+ delete(key: string): Promise<boolean>;
34
+ /** Check if a key exists */
35
+ has(key: string): Promise<boolean>;
36
+ /** Clear all cache entries */
37
+ clear(): Promise<void>;
38
+ /** Invalidate entries by tag */
39
+ invalidateTag(tag: string): Promise<void>;
40
+ /** Get or set with a factory function */
41
+ getOrSet<T>(key: string, factory: () => Promise<T>, options?: CacheOptions): Promise<T>;
42
+ }
43
+ /** Adapter interface for external cache providers */
44
+ interface CacheAdapter {
45
+ name: string;
46
+ get<T>(key: string): Promise<CacheEntry<T> | undefined>;
47
+ set<T>(key: string, entry: CacheEntry<T>): Promise<void>;
48
+ delete(key: string): Promise<boolean>;
49
+ has(key: string): Promise<boolean>;
50
+ clear(): Promise<void>;
51
+ keys?(pattern?: string): Promise<string[]>;
52
+ }
53
+ interface CreateCacheOptions {
54
+ /** Custom cache adapter (defaults to in-memory) */
55
+ adapter?: CacheAdapter;
56
+ /** Default TTL for all entries */
57
+ defaultTTL?: number;
58
+ /** Key prefix for namespacing */
59
+ prefix?: string;
60
+ }
61
+ /**
62
+ * Create a new cache instance
63
+ */
64
+ declare function createCache(options?: CreateCacheOptions): Cache;
65
+ /**
66
+ * Create a cache key from multiple parts
67
+ */
68
+ declare function cacheKey(...parts: (string | number | boolean | undefined)[]): string;
69
+ /**
70
+ * Wrap a function with caching
71
+ */
72
+ declare function cached<T extends (...args: unknown[]) => Promise<unknown>>(cache: Cache, fn: T, options?: CacheOptions & {
73
+ keyFn?: (...args: Parameters<T>) => string;
74
+ }): T;
75
+
76
+ export { type Cache, type CacheAdapter, type CacheEntry, type CacheOptions, type CreateCacheOptions, cacheKey, cached, createCache };
@@ -0,0 +1,3 @@
1
+ export { cacheKey, cached, createCache } from '../chunk-3AIQVGTM.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,120 @@
1
+ // src/cache/index.ts
2
+ var MemoryCacheAdapter = class {
3
+ name = "memory";
4
+ store = /* @__PURE__ */ new Map();
5
+ async get(key) {
6
+ const entry = this.store.get(key);
7
+ if (!entry) return void 0;
8
+ if (entry.expiresAt && Date.now() > entry.expiresAt) {
9
+ this.store.delete(key);
10
+ return void 0;
11
+ }
12
+ return entry;
13
+ }
14
+ async set(key, entry) {
15
+ this.store.set(key, entry);
16
+ }
17
+ async delete(key) {
18
+ return this.store.delete(key);
19
+ }
20
+ async has(key) {
21
+ const entry = await this.get(key);
22
+ return entry !== void 0;
23
+ }
24
+ async clear() {
25
+ this.store.clear();
26
+ }
27
+ async keys(pattern) {
28
+ const allKeys = Array.from(this.store.keys());
29
+ if (!pattern) return allKeys;
30
+ const regex = new RegExp(pattern.replace(/\*/g, ".*"));
31
+ return allKeys.filter((key) => regex.test(key));
32
+ }
33
+ };
34
+ function createCache(options = {}) {
35
+ const {
36
+ adapter = new MemoryCacheAdapter(),
37
+ defaultTTL,
38
+ prefix = ""
39
+ } = options;
40
+ const tagIndex = /* @__PURE__ */ new Map();
41
+ function prefixKey(key) {
42
+ return prefix ? `${prefix}:${key}` : key;
43
+ }
44
+ return {
45
+ async get(key) {
46
+ const entry = await adapter.get(prefixKey(key));
47
+ if (!entry) return void 0;
48
+ if (entry.staleAt && Date.now() > entry.staleAt) {
49
+ return entry.value;
50
+ }
51
+ return entry.value;
52
+ },
53
+ async set(key, value, opts) {
54
+ const ttl = opts?.ttl ?? defaultTTL;
55
+ const now = Date.now();
56
+ const entry = {
57
+ value,
58
+ createdAt: now,
59
+ tags: opts?.tags
60
+ };
61
+ if (ttl) {
62
+ entry.expiresAt = now + ttl * 1e3;
63
+ if (opts?.swr) {
64
+ entry.staleAt = now + (ttl - opts.swr) * 1e3;
65
+ }
66
+ }
67
+ const fullKey = prefixKey(key);
68
+ await adapter.set(fullKey, entry);
69
+ if (opts?.tags) {
70
+ for (const tag of opts.tags) {
71
+ if (!tagIndex.has(tag)) {
72
+ tagIndex.set(tag, /* @__PURE__ */ new Set());
73
+ }
74
+ tagIndex.get(tag).add(fullKey);
75
+ }
76
+ }
77
+ },
78
+ async delete(key) {
79
+ return adapter.delete(prefixKey(key));
80
+ },
81
+ async has(key) {
82
+ return adapter.has(prefixKey(key));
83
+ },
84
+ async clear() {
85
+ await adapter.clear();
86
+ tagIndex.clear();
87
+ },
88
+ async invalidateTag(tag) {
89
+ const keys = tagIndex.get(tag);
90
+ if (!keys) return;
91
+ for (const key of keys) {
92
+ await adapter.delete(key);
93
+ }
94
+ tagIndex.delete(tag);
95
+ },
96
+ async getOrSet(key, factory, opts) {
97
+ const cached2 = await this.get(key);
98
+ if (cached2 !== void 0) {
99
+ return cached2;
100
+ }
101
+ const value = await factory();
102
+ await this.set(key, value, opts);
103
+ return value;
104
+ }
105
+ };
106
+ }
107
+ function cacheKey(...parts) {
108
+ return parts.filter((p) => p !== void 0).map((p) => String(p)).join(":");
109
+ }
110
+ function cached(cache, fn, options) {
111
+ const { keyFn = (...args) => JSON.stringify(args), ...cacheOpts } = options ?? {};
112
+ return (async (...args) => {
113
+ const key = keyFn(...args);
114
+ return cache.getOrSet(key, () => fn(...args), cacheOpts);
115
+ });
116
+ }
117
+
118
+ export { cacheKey, cached, createCache };
119
+ //# sourceMappingURL=chunk-3AIQVGTM.js.map
120
+ //# sourceMappingURL=chunk-3AIQVGTM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cache/index.ts"],"names":["cached"],"mappings":";AA2EA,IAAM,qBAAN,MAAiD;AAAA,EAC7C,IAAA,GAAO,QAAA;AAAA,EACC,KAAA,uBAAY,GAAA,EAAiC;AAAA,EAErD,MAAM,IAAO,GAAA,EAAiD;AAC1D,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAGnB,IAAA,IAAI,MAAM,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,SAAA,EAAW;AACjD,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,MAAA;AAAA,IACX;AAEA,IAAA,OAAO,KAAA;AAAA,EACX;AAAA,EAEA,MAAM,GAAA,CAAO,GAAA,EAAa,KAAA,EAAqC;AAC3D,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,KAA4B,CAAA;AAAA,EACpD;AAAA,EAEA,MAAM,OAAO,GAAA,EAA+B;AACxC,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,GAAG,CAAA;AAAA,EAChC;AAAA,EAEA,MAAM,IAAI,GAAA,EAA+B;AACrC,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,OAAO,KAAA,KAAU,MAAA;AAAA,EACrB;AAAA,EAEA,MAAM,KAAA,GAAuB;AACzB,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACrB;AAAA,EAEA,MAAM,KAAK,OAAA,EAAqC;AAC5C,IAAA,MAAM,UAAU,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAC5C,IAAA,IAAI,CAAC,SAAS,OAAO,OAAA;AAErB,IAAA,MAAM,QAAQ,IAAI,MAAA,CAAO,QAAQ,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAC,CAAA;AACrD,IAAA,OAAO,QAAQ,MAAA,CAAO,CAAA,GAAA,KAAO,KAAA,CAAM,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,EAChD;AACJ,CAAA;AAkBO,SAAS,WAAA,CAAY,OAAA,GAA8B,EAAC,EAAU;AACjE,EAAA,MAAM;AAAA,IACF,OAAA,GAAU,IAAI,kBAAA,EAAmB;AAAA,IACjC,UAAA;AAAA,IACA,MAAA,GAAS;AAAA,GACb,GAAI,OAAA;AAEJ,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAyB;AAE9C,EAAA,SAAS,UAAU,GAAA,EAAqB;AACpC,IAAA,OAAO,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAAA,EACzC;AAEA,EAAA,OAAO;AAAA,IACH,MAAM,IAAO,GAAA,EAAqC;AAC9C,MAAA,MAAM,QAAQ,MAAM,OAAA,CAAQ,GAAA,CAAO,SAAA,CAAU,GAAG,CAAC,CAAA;AACjD,MAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAGnB,MAAA,IAAI,MAAM,OAAA,IAAW,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,OAAA,EAAS;AAE7C,QAAA,OAAO,KAAA,CAAM,KAAA;AAAA,MACjB;AAEA,MAAA,OAAO,KAAA,CAAM,KAAA;AAAA,IACjB,CAAA;AAAA,IAEA,MAAM,GAAA,CAAO,GAAA,EAAa,KAAA,EAAU,IAAA,EAAoC;AACpE,MAAA,MAAM,GAAA,GAAM,MAAM,GAAA,IAAO,UAAA;AACzB,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,MAAM,KAAA,GAAuB;AAAA,QACzB,KAAA;AAAA,QACA,SAAA,EAAW,GAAA;AAAA,QACX,MAAM,IAAA,EAAM;AAAA,OAChB;AAEA,MAAA,IAAI,GAAA,EAAK;AACL,QAAA,KAAA,CAAM,SAAA,GAAY,MAAO,GAAA,GAAM,GAAA;AAC/B,QAAA,IAAI,MAAM,GAAA,EAAK;AACX,UAAA,KAAA,CAAM,OAAA,GAAU,GAAA,GAAA,CAAQ,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,GAAA;AAAA,QAC9C;AAAA,MACJ;AAEA,MAAA,MAAM,OAAA,GAAU,UAAU,GAAG,CAAA;AAC7B,MAAA,MAAM,OAAA,CAAQ,GAAA,CAAI,OAAA,EAAS,KAAK,CAAA;AAGhC,MAAA,IAAI,MAAM,IAAA,EAAM;AACZ,QAAA,KAAA,MAAW,GAAA,IAAO,KAAK,IAAA,EAAM;AACzB,UAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,EAAG;AACpB,YAAA,QAAA,CAAS,GAAA,CAAI,GAAA,kBAAK,IAAI,GAAA,EAAK,CAAA;AAAA,UAC/B;AACA,UAAA,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,CAAG,GAAA,CAAI,OAAO,CAAA;AAAA,QAClC;AAAA,MACJ;AAAA,IACJ,CAAA;AAAA,IAEA,MAAM,OAAO,GAAA,EAA+B;AACxC,MAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,IACxC,CAAA;AAAA,IAEA,MAAM,IAAI,GAAA,EAA+B;AACrC,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,IACrC,CAAA;AAAA,IAEA,MAAM,KAAA,GAAuB;AACzB,MAAA,MAAM,QAAQ,KAAA,EAAM;AACpB,MAAA,QAAA,CAAS,KAAA,EAAM;AAAA,IACnB,CAAA;AAAA,IAEA,MAAM,cAAc,GAAA,EAA4B;AAC5C,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AAC7B,MAAA,IAAI,CAAC,IAAA,EAAM;AAEX,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACpB,QAAA,MAAM,OAAA,CAAQ,OAAO,GAAG,CAAA;AAAA,MAC5B;AACA,MAAA,QAAA,CAAS,OAAO,GAAG,CAAA;AAAA,IACvB,CAAA;AAAA,IAEA,MAAM,QAAA,CACF,GAAA,EACA,OAAA,EACA,IAAA,EACU;AACV,MAAA,MAAMA,OAAAA,GAAS,MAAM,IAAA,CAAK,GAAA,CAAO,GAAG,CAAA;AACpC,MAAA,IAAIA,YAAW,MAAA,EAAW;AACtB,QAAA,OAAOA,OAAAA;AAAA,MACX;AAEA,MAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,EAAQ;AAC5B,MAAA,MAAM,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,KAAA,EAAO,IAAI,CAAA;AAC/B,MAAA,OAAO,KAAA;AAAA,IACX;AAAA,GACJ;AACJ;AASO,SAAS,YAAY,KAAA,EAA0D;AAClF,EAAA,OAAO,KAAA,CACF,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,KAAM,MAAS,CAAA,CAC3B,GAAA,CAAI,CAAA,CAAA,KAAK,MAAA,CAAO,CAAC,CAAC,CAAA,CAClB,KAAK,GAAG,CAAA;AACjB;AAKO,SAAS,MAAA,CACZ,KAAA,EACA,EAAA,EACA,OAAA,EACC;AACD,EAAA,MAAM,EAAE,KAAA,GAAQ,CAAA,GAAI,IAAA,KAAoB,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG,GAAG,SAAA,EAAU,GAAI,OAAA,IAAW,EAAC;AAE3F,EAAA,QAAQ,UAAU,IAAA,KAAwB;AACtC,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,GAAG,IAAI,CAAA;AACzB,IAAA,OAAO,KAAA,CAAM,SAAS,GAAA,EAAK,MAAM,GAAG,GAAG,IAAI,GAAuB,SAAS,CAAA;AAAA,EAC/E,CAAA;AACJ","file":"chunk-3AIQVGTM.js","sourcesContent":["/**\r\n * Flight Cache - Agnostic caching primitives\r\n * \r\n * Flight provides the interface, you choose the implementation.\r\n * Use in-memory, Redis, Cloudflare KV, or anything else.\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface CacheOptions {\r\n /** Time-to-live in seconds */\r\n ttl?: number;\r\n /** Cache tags for invalidation */\r\n tags?: string[];\r\n /** Stale-while-revalidate time in seconds */\r\n swr?: number;\r\n}\r\n\r\nexport interface CacheEntry<T> {\r\n /** Cached value */\r\n value: T;\r\n /** When this entry expires (timestamp) */\r\n expiresAt?: number;\r\n /** When this entry becomes stale (timestamp) */\r\n staleAt?: number;\r\n /** Cache tags for invalidation */\r\n tags?: string[];\r\n /** When this entry was created */\r\n createdAt: number;\r\n}\r\n\r\nexport interface Cache {\r\n /** Get a value from cache */\r\n get<T>(key: string): Promise<T | undefined>;\r\n\r\n /** Set a value in cache */\r\n set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;\r\n\r\n /** Delete a value from cache */\r\n delete(key: string): Promise<boolean>;\r\n\r\n /** Check if a key exists */\r\n has(key: string): Promise<boolean>;\r\n\r\n /** Clear all cache entries */\r\n clear(): Promise<void>;\r\n\r\n /** Invalidate entries by tag */\r\n invalidateTag(tag: string): Promise<void>;\r\n\r\n /** Get or set with a factory function */\r\n getOrSet<T>(\r\n key: string,\r\n factory: () => Promise<T>,\r\n options?: CacheOptions\r\n ): Promise<T>;\r\n}\r\n\r\n/** Adapter interface for external cache providers */\r\nexport interface CacheAdapter {\r\n name: string;\r\n get<T>(key: string): Promise<CacheEntry<T> | undefined>;\r\n set<T>(key: string, entry: CacheEntry<T>): Promise<void>;\r\n delete(key: string): Promise<boolean>;\r\n has(key: string): Promise<boolean>;\r\n clear(): Promise<void>;\r\n keys?(pattern?: string): Promise<string[]>;\r\n}\r\n\r\n// ============================================================================\r\n// In-Memory Cache Implementation (Default)\r\n// ============================================================================\r\n\r\nclass MemoryCacheAdapter implements CacheAdapter {\r\n name = 'memory';\r\n private store = new Map<string, CacheEntry<unknown>>();\r\n\r\n async get<T>(key: string): Promise<CacheEntry<T> | undefined> {\r\n const entry = this.store.get(key) as CacheEntry<T> | undefined;\r\n if (!entry) return undefined;\r\n\r\n // Check if expired\r\n if (entry.expiresAt && Date.now() > entry.expiresAt) {\r\n this.store.delete(key);\r\n return undefined;\r\n }\r\n\r\n return entry;\r\n }\r\n\r\n async set<T>(key: string, entry: CacheEntry<T>): Promise<void> {\r\n this.store.set(key, entry as CacheEntry<unknown>);\r\n }\r\n\r\n async delete(key: string): Promise<boolean> {\r\n return this.store.delete(key);\r\n }\r\n\r\n async has(key: string): Promise<boolean> {\r\n const entry = await this.get(key);\r\n return entry !== undefined;\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n\r\n async keys(pattern?: string): Promise<string[]> {\r\n const allKeys = Array.from(this.store.keys());\r\n if (!pattern) return allKeys;\r\n\r\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'));\r\n return allKeys.filter(key => regex.test(key));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Cache Factory\r\n// ============================================================================\r\n\r\nexport interface CreateCacheOptions {\r\n /** Custom cache adapter (defaults to in-memory) */\r\n adapter?: CacheAdapter;\r\n /** Default TTL for all entries */\r\n defaultTTL?: number;\r\n /** Key prefix for namespacing */\r\n prefix?: string;\r\n}\r\n\r\n/**\r\n * Create a new cache instance\r\n */\r\nexport function createCache(options: CreateCacheOptions = {}): Cache {\r\n const {\r\n adapter = new MemoryCacheAdapter(),\r\n defaultTTL,\r\n prefix = ''\r\n } = options;\r\n\r\n const tagIndex = new Map<string, Set<string>>();\r\n\r\n function prefixKey(key: string): string {\r\n return prefix ? `${prefix}:${key}` : key;\r\n }\r\n\r\n return {\r\n async get<T>(key: string): Promise<T | undefined> {\r\n const entry = await adapter.get<T>(prefixKey(key));\r\n if (!entry) return undefined;\r\n\r\n // Check stale-while-revalidate\r\n if (entry.staleAt && Date.now() > entry.staleAt) {\r\n // Return stale value (caller should revalidate)\r\n return entry.value;\r\n }\r\n\r\n return entry.value;\r\n },\r\n\r\n async set<T>(key: string, value: T, opts?: CacheOptions): Promise<void> {\r\n const ttl = opts?.ttl ?? defaultTTL;\r\n const now = Date.now();\r\n\r\n const entry: CacheEntry<T> = {\r\n value,\r\n createdAt: now,\r\n tags: opts?.tags,\r\n };\r\n\r\n if (ttl) {\r\n entry.expiresAt = now + (ttl * 1000);\r\n if (opts?.swr) {\r\n entry.staleAt = now + ((ttl - opts.swr) * 1000);\r\n }\r\n }\r\n\r\n const fullKey = prefixKey(key);\r\n await adapter.set(fullKey, entry);\r\n\r\n // Update tag index\r\n if (opts?.tags) {\r\n for (const tag of opts.tags) {\r\n if (!tagIndex.has(tag)) {\r\n tagIndex.set(tag, new Set());\r\n }\r\n tagIndex.get(tag)!.add(fullKey);\r\n }\r\n }\r\n },\r\n\r\n async delete(key: string): Promise<boolean> {\r\n return adapter.delete(prefixKey(key));\r\n },\r\n\r\n async has(key: string): Promise<boolean> {\r\n return adapter.has(prefixKey(key));\r\n },\r\n\r\n async clear(): Promise<void> {\r\n await adapter.clear();\r\n tagIndex.clear();\r\n },\r\n\r\n async invalidateTag(tag: string): Promise<void> {\r\n const keys = tagIndex.get(tag);\r\n if (!keys) return;\r\n\r\n for (const key of keys) {\r\n await adapter.delete(key);\r\n }\r\n tagIndex.delete(tag);\r\n },\r\n\r\n async getOrSet<T>(\r\n key: string,\r\n factory: () => Promise<T>,\r\n opts?: CacheOptions\r\n ): Promise<T> {\r\n const cached = await this.get<T>(key);\r\n if (cached !== undefined) {\r\n return cached;\r\n }\r\n\r\n const value = await factory();\r\n await this.set(key, value, opts);\r\n return value;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Cache Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Create a cache key from multiple parts\r\n */\r\nexport function cacheKey(...parts: (string | number | boolean | undefined)[]): string {\r\n return parts\r\n .filter(p => p !== undefined)\r\n .map(p => String(p))\r\n .join(':');\r\n}\r\n\r\n/**\r\n * Wrap a function with caching\r\n */\r\nexport function cached<T extends (...args: unknown[]) => Promise<unknown>>(\r\n cache: Cache,\r\n fn: T,\r\n options?: CacheOptions & { keyFn?: (...args: Parameters<T>) => string }\r\n): T {\r\n const { keyFn = (...args: unknown[]) => JSON.stringify(args), ...cacheOpts } = options ?? {};\r\n\r\n return (async (...args: Parameters<T>) => {\r\n const key = keyFn(...args);\r\n return cache.getOrSet(key, () => fn(...args) as Promise<unknown>, cacheOpts);\r\n }) as T;\r\n}\r\n"]}