@flight-framework/core 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/index.d.ts +58 -1
- package/dist/actions/index.js +1 -1
- package/dist/{chunk-56ZZNOJD.js → chunk-NU3HX5T7.js} +23 -36
- package/dist/chunk-NU3HX5T7.js.map +1 -0
- package/dist/{chunk-3QP3E7HS.js → chunk-XGP3C2ZE.js} +112 -4
- package/dist/chunk-XGP3C2ZE.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/plugins/index.js +2 -2
- package/dist/plugins/server-boundary-plugin.d.ts +11 -27
- package/dist/plugins/server-boundary-plugin.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3QP3E7HS.js.map +0 -1
- package/dist/chunk-56ZZNOJD.js.map +0 -1
package/dist/actions/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @flight-framework/core - Action Middleware
|
|
3
5
|
*
|
|
@@ -633,6 +635,61 @@ declare function createQueueManager(options: {
|
|
|
633
635
|
retryFailed: () => Promise<void>;
|
|
634
636
|
};
|
|
635
637
|
|
|
638
|
+
/**
|
|
639
|
+
* @flight-framework/core - Server Actions Vite Plugin
|
|
640
|
+
*
|
|
641
|
+
* Transforms files with 'use server' directive.
|
|
642
|
+
* Similar to React 19 / Next.js server actions compilation.
|
|
643
|
+
*/
|
|
644
|
+
|
|
645
|
+
interface ServerActionsPluginOptions {
|
|
646
|
+
/** Include patterns */
|
|
647
|
+
include?: string[];
|
|
648
|
+
/** Exclude patterns */
|
|
649
|
+
exclude?: string[];
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Vite plugin for server actions transformation
|
|
653
|
+
*
|
|
654
|
+
* @example
|
|
655
|
+
* ```typescript
|
|
656
|
+
* // vite.config.ts
|
|
657
|
+
* import { serverActionsPlugin } from '@flight-framework/core/actions';
|
|
658
|
+
*
|
|
659
|
+
* export default {
|
|
660
|
+
* plugins: [serverActionsPlugin()],
|
|
661
|
+
* };
|
|
662
|
+
* ```
|
|
663
|
+
*/
|
|
664
|
+
declare function serverActionsPlugin(options?: ServerActionsPluginOptions): Plugin;
|
|
665
|
+
/**
|
|
666
|
+
* Create a client-side action caller
|
|
667
|
+
*
|
|
668
|
+
* @example
|
|
669
|
+
* ```typescript
|
|
670
|
+
* // In client component
|
|
671
|
+
* import { createActionCaller } from '@flight-framework/core/actions';
|
|
672
|
+
*
|
|
673
|
+
* const submitForm = createActionCaller('action_abc123');
|
|
674
|
+
*
|
|
675
|
+
* // Usage
|
|
676
|
+
* const result = await submitForm({ name: 'John' });
|
|
677
|
+
* ```
|
|
678
|
+
*/
|
|
679
|
+
declare function createActionCaller<TArgs extends unknown[], TResult>(actionId: string): (...args: TArgs) => Promise<TResult>;
|
|
680
|
+
/**
|
|
681
|
+
* Create a form action for HTML forms
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```tsx
|
|
685
|
+
* <form action={formAction('action_abc123')}>
|
|
686
|
+
* <input name="email" />
|
|
687
|
+
* <button type="submit">Submit</button>
|
|
688
|
+
* </form>
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
declare function formAction(actionId: string): string;
|
|
692
|
+
|
|
636
693
|
/**
|
|
637
694
|
* @flight-framework/core - Server Actions
|
|
638
695
|
*
|
|
@@ -740,4 +797,4 @@ declare function createActionReference(actionId: string): string;
|
|
|
740
797
|
*/
|
|
741
798
|
declare function handleActionRequest(request: Request): Promise<Response>;
|
|
742
799
|
|
|
743
|
-
export { type Action, type ActionContext, type ActionMiddleware, type ActionMiddlewareHandler, type ActionNext, type ActionResult, type CookieOptions, type CreateMiddlewareOptions, type FormActionData, type QueueStatus, type QueueStorageAdapter, type QueuedAction, type QueuedActionEntry, type QueuedActionOptions, type QueuedActionResult, RedirectError, type RetryStrategy, type ServerAction, type StreamController, type StreamItem, type StreamProgress, type StreamResult, type StreamableAction, type StreamableActionOptions, type StreamableGenerator, clearActions, collectStream, cookies, createActionContext, createActionMiddleware, createActionReference, createLoggingMiddleware, createMemoryAdapter, createProgressReporter, createQueueManager, createQueuedAction, createRetryMiddleware, createStreamableAction, createTimingMiddleware, defaultRetryStrategy, executeAction, executeFormAction, executeWithMiddleware, exponentialBackoff, fixedDelay, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, pipeline, redirect, registerAction, responseToStream, streamToResponse };
|
|
800
|
+
export { type Action, type ActionContext, type ActionMiddleware, type ActionMiddlewareHandler, type ActionNext, type ActionResult, type CookieOptions, type CreateMiddlewareOptions, type FormActionData, type QueueStatus, type QueueStorageAdapter, type QueuedAction, type QueuedActionEntry, type QueuedActionOptions, type QueuedActionResult, RedirectError, type RetryStrategy, type ServerAction, type ServerActionsPluginOptions, type StreamController, type StreamItem, type StreamProgress, type StreamResult, type StreamableAction, type StreamableActionOptions, type StreamableGenerator, clearActions, collectStream, cookies, createActionCaller, createActionContext, createActionMiddleware, createActionReference, createLoggingMiddleware, createMemoryAdapter, createProgressReporter, createQueueManager, createQueuedAction, createRetryMiddleware, createStreamableAction, createTimingMiddleware, defaultRetryStrategy, executeAction, executeFormAction, executeWithMiddleware, exponentialBackoff, fixedDelay, formAction, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, pipeline, redirect, registerAction, responseToStream, serverActionsPlugin, streamToResponse };
|
package/dist/actions/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { RedirectError, clearActions, collectStream, cookies, createActionContext, createActionMiddleware, createActionReference, createLoggingMiddleware, createMemoryAdapter, createProgressReporter, createQueueManager, createQueuedAction, createRetryMiddleware, createStreamableAction, createTimingMiddleware, defaultRetryStrategy, executeAction, executeFormAction, executeWithMiddleware, exponentialBackoff, fixedDelay, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, pipeline, redirect, registerAction, responseToStream, streamToResponse } from '../chunk-
|
|
1
|
+
export { RedirectError, clearActions, collectStream, cookies, createActionCaller, createActionContext, createActionMiddleware, createActionReference, createLoggingMiddleware, createMemoryAdapter, createProgressReporter, createQueueManager, createQueuedAction, createRetryMiddleware, createStreamableAction, createTimingMiddleware, defaultRetryStrategy, executeAction, executeFormAction, executeWithMiddleware, exponentialBackoff, fixedDelay, formAction, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, pipeline, redirect, registerAction, responseToStream, serverActionsPlugin, streamToResponse } from '../chunk-XGP3C2ZE.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
function serverBoundaryPlugin(options = {}) {
|
|
3
3
|
const {
|
|
4
4
|
serverFilePatterns = [".server.ts", ".server.tsx", ".server.js", ".server.jsx"],
|
|
5
|
-
serverDirPatterns = ["/server/"
|
|
6
|
-
violationBehavior = "
|
|
5
|
+
serverDirPatterns = ["/server/"],
|
|
6
|
+
violationBehavior = "warn",
|
|
7
7
|
customErrorMessage,
|
|
8
|
-
exclude = [
|
|
8
|
+
exclude = [],
|
|
9
|
+
skipServerActions = true
|
|
9
10
|
} = options;
|
|
10
11
|
const filePatterns = serverFilePatterns.map(
|
|
11
12
|
(p) => new RegExp(p.replace(/\./g, "\\.") + "$", "i")
|
|
@@ -13,6 +14,7 @@ function serverBoundaryPlugin(options = {}) {
|
|
|
13
14
|
const dirPatterns = serverDirPatterns.map(
|
|
14
15
|
(p) => new RegExp(p.replace(/\//g, "[\\\\/]"), "i")
|
|
15
16
|
);
|
|
17
|
+
const serverActionFiles = /* @__PURE__ */ new Set();
|
|
16
18
|
function isServerOnlyModule(id) {
|
|
17
19
|
for (const pattern of filePatterns) {
|
|
18
20
|
if (pattern.test(id)) return true;
|
|
@@ -23,6 +25,7 @@ function serverBoundaryPlugin(options = {}) {
|
|
|
23
25
|
return false;
|
|
24
26
|
}
|
|
25
27
|
function isExcluded(id) {
|
|
28
|
+
if (id.includes("node_modules")) return true;
|
|
26
29
|
for (const pattern of exclude) {
|
|
27
30
|
const regex = new RegExp(
|
|
28
31
|
pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/\\\\]*").replace(/\./g, "\\.")
|
|
@@ -35,52 +38,36 @@ function serverBoundaryPlugin(options = {}) {
|
|
|
35
38
|
if (customErrorMessage) {
|
|
36
39
|
return customErrorMessage(module, importer);
|
|
37
40
|
}
|
|
38
|
-
return `[Flight]
|
|
39
|
-
|
|
41
|
+
return `[Flight] Server-only module imported in client code.
|
|
40
42
|
Module: ${module}
|
|
41
43
|
Imported by: ${importer}
|
|
42
|
-
|
|
43
|
-
Solutions:
|
|
44
|
-
1. Move the import to a 'use server' file
|
|
45
|
-
2. Use an API route instead
|
|
46
|
-
3. Use dynamic import with typeof window check
|
|
47
|
-
4. Rename the importing file to *.server.ts
|
|
48
|
-
|
|
49
|
-
Learn more: https://flight-framework.dev/docs/server-client-boundaries`;
|
|
44
|
+
Solutions: Rename to *.server.ts, add 'use server', or use dynamic import.`;
|
|
50
45
|
}
|
|
51
46
|
return {
|
|
52
47
|
name: "flight:server-boundary",
|
|
53
|
-
enforce: "
|
|
48
|
+
enforce: "post",
|
|
49
|
+
transform(code, id, options2) {
|
|
50
|
+
if (options2?.ssr) return null;
|
|
51
|
+
if (skipServerActions) {
|
|
52
|
+
const trimmed = code.trim();
|
|
53
|
+
if (trimmed.startsWith("'use server'") || trimmed.startsWith('"use server"')) {
|
|
54
|
+
serverActionFiles.add(id);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
},
|
|
54
59
|
resolveId(source, importer, options2) {
|
|
55
60
|
if (options2?.ssr) return null;
|
|
56
61
|
if (!importer) return null;
|
|
57
62
|
if (isExcluded(importer)) return null;
|
|
63
|
+
if (skipServerActions && serverActionFiles.has(importer)) return null;
|
|
58
64
|
if (isServerOnlyModule(importer)) return null;
|
|
59
65
|
if (isServerOnlyModule(source)) {
|
|
60
66
|
const message = createErrorMessage(source, importer);
|
|
61
67
|
if (violationBehavior === "error") {
|
|
62
68
|
this.error(message);
|
|
63
69
|
} else {
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
68
|
-
},
|
|
69
|
-
transform(code, id, options2) {
|
|
70
|
-
if (options2?.ssr) return null;
|
|
71
|
-
if (isExcluded(id)) return null;
|
|
72
|
-
if (isServerOnlyModule(id)) return null;
|
|
73
|
-
const trimmed = code.trim();
|
|
74
|
-
if (trimmed.startsWith("'use server'") || trimmed.startsWith('"use server"')) {
|
|
75
|
-
const message = `[Flight] 'use server' file imported in client bundle.
|
|
76
|
-
|
|
77
|
-
File: ${id}
|
|
78
|
-
|
|
79
|
-
This file should only run on the server. Check your import graph to find where this is imported.`;
|
|
80
|
-
if (violationBehavior === "error") {
|
|
81
|
-
this.error(message);
|
|
82
|
-
} else {
|
|
83
|
-
this.warn(message);
|
|
70
|
+
console.warn(message);
|
|
84
71
|
}
|
|
85
72
|
}
|
|
86
73
|
return null;
|
|
@@ -89,5 +76,5 @@ This file should only run on the server. Check your import graph to find where t
|
|
|
89
76
|
}
|
|
90
77
|
|
|
91
78
|
export { serverBoundaryPlugin };
|
|
92
|
-
//# sourceMappingURL=chunk-
|
|
93
|
-
//# sourceMappingURL=chunk-
|
|
79
|
+
//# sourceMappingURL=chunk-NU3HX5T7.js.map
|
|
80
|
+
//# sourceMappingURL=chunk-NU3HX5T7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/server-boundary-plugin.ts"],"names":["options"],"mappings":"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","file":"chunk-NU3HX5T7.js","sourcesContent":["/**\r\n * @flight-framework/core - Server Boundary Plugin\r\n * \r\n * Vite plugin to detect server-only code imported in client bundles.\r\n * OPTIONAL - use if you want build-time protection.\r\n * \r\n * NOTE: This plugin is designed to work WITH serverActionsPlugin.\r\n * It will NOT flag 'use server' files because those are handled\r\n * by the Server Actions transformation.\r\n */\r\n\r\nimport type { Plugin } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface ServerBoundaryPluginOptions {\r\n /**\r\n * File patterns that are server-only.\r\n * @default ['.server.ts', '.server.tsx', '.server.js', '.server.jsx']\r\n */\r\n serverFilePatterns?: string[];\r\n\r\n /**\r\n * Directory patterns that are server-only.\r\n * @default ['/server/']\r\n */\r\n serverDirPatterns?: string[];\r\n\r\n /**\r\n * How to handle violations.\r\n * - 'error': Build error (recommended for production)\r\n * - 'warn': Warning only (for migration)\r\n * @default 'warn'\r\n */\r\n violationBehavior?: 'error' | 'warn';\r\n\r\n /**\r\n * Custom error message template.\r\n */\r\n customErrorMessage?: (module: string, importer: string) => string;\r\n\r\n /**\r\n * Files to exclude from checking.\r\n */\r\n exclude?: string[];\r\n\r\n /**\r\n * Skip checking 'use server' files. These are handled by serverActionsPlugin.\r\n * @default true\r\n */\r\n skipServerActions?: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin to detect server-only imports in client code.\r\n */\r\nexport function serverBoundaryPlugin(\r\n options: ServerBoundaryPluginOptions = {}\r\n): Plugin {\r\n const {\r\n serverFilePatterns = ['.server.ts', '.server.tsx', '.server.js', '.server.jsx'],\r\n serverDirPatterns = ['/server/'],\r\n violationBehavior = 'warn',\r\n customErrorMessage,\r\n exclude = [],\r\n skipServerActions = true,\r\n } = options;\r\n\r\n // Build regex patterns\r\n const filePatterns = serverFilePatterns.map(p =>\r\n new RegExp(p.replace(/\\./g, '\\\\.') + '$', 'i')\r\n );\r\n const dirPatterns = serverDirPatterns.map(p =>\r\n new RegExp(p.replace(/\\//g, '[\\\\\\\\/]'), 'i')\r\n );\r\n\r\n // Track files with 'use server' to skip them\r\n const serverActionFiles = new Set<string>();\r\n\r\n function isServerOnlyModule(id: string): boolean {\r\n for (const pattern of filePatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n for (const pattern of dirPatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n return false;\r\n }\r\n\r\n function isExcluded(id: string): boolean {\r\n if (id.includes('node_modules')) return true;\r\n for (const pattern of exclude) {\r\n const regex = new RegExp(\r\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/\\\\\\\\]*').replace(/\\./g, '\\\\.')\r\n );\r\n if (regex.test(id)) return true;\r\n }\r\n return false;\r\n }\r\n\r\n function createErrorMessage(module: string, importer: string): string {\r\n if (customErrorMessage) {\r\n return customErrorMessage(module, importer);\r\n }\r\n return (\r\n `[Flight] Server-only module imported in client code.\\n` +\r\n ` Module: ${module}\\n` +\r\n ` Imported by: ${importer}\\n` +\r\n `Solutions: Rename to *.server.ts, add 'use server', or use dynamic import.`\r\n );\r\n }\r\n\r\n return {\r\n name: 'flight:server-boundary',\r\n enforce: 'post',\r\n\r\n transform(code, id, options) {\r\n if (options?.ssr) return null;\r\n\r\n // Track 'use server' files\r\n if (skipServerActions) {\r\n const trimmed = code.trim();\r\n if (trimmed.startsWith(\"'use server'\") || trimmed.startsWith('\"use server\"')) {\r\n serverActionFiles.add(id);\r\n }\r\n }\r\n return null;\r\n },\r\n\r\n resolveId(source, importer, options) {\r\n if (options?.ssr) return null;\r\n if (!importer) return null;\r\n if (isExcluded(importer)) return null;\r\n if (skipServerActions && serverActionFiles.has(importer)) return null;\r\n if (isServerOnlyModule(importer)) return null;\r\n\r\n if (isServerOnlyModule(source)) {\r\n const message = createErrorMessage(source, importer);\r\n if (violationBehavior === 'error') {\r\n this.error(message);\r\n } else {\r\n console.warn(message);\r\n }\r\n }\r\n return null;\r\n },\r\n };\r\n}\r\n"]}
|
|
@@ -520,9 +520,117 @@ function createQueueManager(options) {
|
|
|
520
520
|
};
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
// src/actions/plugin.ts
|
|
524
|
+
function serverActionsPlugin(options = {}) {
|
|
525
|
+
const {
|
|
526
|
+
include = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"],
|
|
527
|
+
exclude = ["**/node_modules/**"]
|
|
528
|
+
} = options;
|
|
529
|
+
return {
|
|
530
|
+
name: "flight:server-actions",
|
|
531
|
+
async transform(code, id) {
|
|
532
|
+
if (exclude.some((pattern) => id.includes(pattern.replace("**/", "")))) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
if (!hasUseServerDirective(code)) {
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
const transformed = transformServerActions(code, id);
|
|
539
|
+
return {
|
|
540
|
+
code: transformed,
|
|
541
|
+
map: null
|
|
542
|
+
// TODO: Generate source map
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
var USE_SERVER_REGEX = /^(['"])use server\1;?\s*$/m;
|
|
548
|
+
var FUNCTION_REGEX = /^(export\s+)?(async\s+)?function\s+(\w+)/gm;
|
|
549
|
+
var ARROW_FUNCTION_REGEX = /^(export\s+)?(const|let)\s+(\w+)\s*=\s*(async\s+)?\(/gm;
|
|
550
|
+
function hasUseServerDirective(code) {
|
|
551
|
+
return USE_SERVER_REGEX.test(code);
|
|
552
|
+
}
|
|
553
|
+
function transformServerActions(code, filePath) {
|
|
554
|
+
const isFileLevel = code.trim().startsWith("'use server'") || code.trim().startsWith('"use server"');
|
|
555
|
+
if (isFileLevel) {
|
|
556
|
+
return transformFileLevelActions(code, filePath);
|
|
557
|
+
}
|
|
558
|
+
return transformInlineActions(code, filePath);
|
|
559
|
+
}
|
|
560
|
+
function transformFileLevelActions(code, filePath) {
|
|
561
|
+
const transformed = code.replace(USE_SERVER_REGEX, "");
|
|
562
|
+
const functions = [];
|
|
563
|
+
let match;
|
|
564
|
+
FUNCTION_REGEX.lastIndex = 0;
|
|
565
|
+
while ((match = FUNCTION_REGEX.exec(code)) !== null) {
|
|
566
|
+
functions.push({
|
|
567
|
+
name: match[3],
|
|
568
|
+
isExported: !!match[1],
|
|
569
|
+
isAsync: !!match[2]
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
ARROW_FUNCTION_REGEX.lastIndex = 0;
|
|
573
|
+
while ((match = ARROW_FUNCTION_REGEX.exec(code)) !== null) {
|
|
574
|
+
functions.push({
|
|
575
|
+
name: match[3],
|
|
576
|
+
isExported: !!match[1],
|
|
577
|
+
isAsync: !!match[4]
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
const registrations = functions.filter((fn) => fn.isExported).map((fn) => {
|
|
581
|
+
const actionId = generateActionId(fn.name, filePath);
|
|
582
|
+
return `__flight_registerAction({ id: "${actionId}", name: "${fn.name}", filePath: "${filePath}", fn: ${fn.name} });`;
|
|
583
|
+
}).join("\n");
|
|
584
|
+
const imports = `import { registerAction as __flight_registerAction } from '@flight-framework/core/actions';
|
|
585
|
+
`;
|
|
586
|
+
return imports + transformed + "\n\n// Server action registrations\n" + registrations;
|
|
587
|
+
}
|
|
588
|
+
function transformInlineActions(code, filePath) {
|
|
589
|
+
const inlineServerRegex = /((async\s+)?function\s+(\w+)\s*\([^)]*\)\s*\{)\s*(['"])use server\4;?/g;
|
|
590
|
+
let transformed = code;
|
|
591
|
+
let match;
|
|
592
|
+
const actionsToRegister = [];
|
|
593
|
+
while ((match = inlineServerRegex.exec(code)) !== null) {
|
|
594
|
+
const functionName = match[3];
|
|
595
|
+
const actionId = generateActionId(functionName, filePath);
|
|
596
|
+
transformed = transformed.replace(match[0], match[1]);
|
|
597
|
+
actionsToRegister.push(
|
|
598
|
+
`__flight_registerAction({ id: "${actionId}", name: "${functionName}", filePath: "${filePath}", fn: ${functionName} });`
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
if (actionsToRegister.length > 0) {
|
|
602
|
+
const imports = `import { registerAction as __flight_registerAction } from '@flight-framework/core/actions';
|
|
603
|
+
`;
|
|
604
|
+
return imports + transformed + "\n\n// Server action registrations\n" + actionsToRegister.join("\n");
|
|
605
|
+
}
|
|
606
|
+
return transformed;
|
|
607
|
+
}
|
|
608
|
+
function createActionCaller(actionId) {
|
|
609
|
+
return async (...args) => {
|
|
610
|
+
const response = await fetch(`/__flight_action/${actionId}`, {
|
|
611
|
+
method: "POST",
|
|
612
|
+
headers: {
|
|
613
|
+
"Content-Type": "application/json"
|
|
614
|
+
},
|
|
615
|
+
body: JSON.stringify(args)
|
|
616
|
+
});
|
|
617
|
+
if (!response.ok) {
|
|
618
|
+
throw new Error(`Action failed: ${response.statusText}`);
|
|
619
|
+
}
|
|
620
|
+
const result = await response.json();
|
|
621
|
+
if (!result.success) {
|
|
622
|
+
throw new Error(result.error || "Action failed");
|
|
623
|
+
}
|
|
624
|
+
return result.data;
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
function formAction(actionId) {
|
|
628
|
+
return `/__flight_action/${actionId}`;
|
|
629
|
+
}
|
|
630
|
+
|
|
523
631
|
// src/actions/index.ts
|
|
524
632
|
var actionRegistry = /* @__PURE__ */ new Map();
|
|
525
|
-
function
|
|
633
|
+
function registerAction2(action) {
|
|
526
634
|
actionRegistry.set(action.id, action);
|
|
527
635
|
}
|
|
528
636
|
function getAction(id) {
|
|
@@ -662,6 +770,6 @@ async function handleActionRequest(request) {
|
|
|
662
770
|
}
|
|
663
771
|
}
|
|
664
772
|
|
|
665
|
-
export { RedirectError, clearActions, collectStream, cookies, createActionContext, createActionMiddleware, createActionReference, createLoggingMiddleware, createMemoryAdapter, createProgressReporter, createQueueManager, createQueuedAction, createRetryMiddleware, createStreamableAction, createTimingMiddleware, defaultRetryStrategy, executeAction, executeFormAction, executeWithMiddleware, exponentialBackoff, fixedDelay, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, pipeline, redirect, registerAction, responseToStream, streamToResponse };
|
|
666
|
-
//# sourceMappingURL=chunk-
|
|
667
|
-
//# sourceMappingURL=chunk-
|
|
773
|
+
export { RedirectError, clearActions, collectStream, cookies, createActionCaller, createActionContext, createActionMiddleware, createActionReference, createLoggingMiddleware, createMemoryAdapter, createProgressReporter, createQueueManager, createQueuedAction, createRetryMiddleware, createStreamableAction, createTimingMiddleware, defaultRetryStrategy, executeAction, executeFormAction, executeWithMiddleware, exponentialBackoff, fixedDelay, formAction, generateActionId, getAction, getAllActions, handleActionRequest, isRedirectError, parseFormData, pipeline, redirect, registerAction2 as registerAction, responseToStream, serverActionsPlugin, streamToResponse };
|
|
774
|
+
//# sourceMappingURL=chunk-XGP3C2ZE.js.map
|
|
775
|
+
//# sourceMappingURL=chunk-XGP3C2ZE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/actions/middleware.ts","../src/actions/streaming.ts","../src/actions/queue.ts","../src/actions/plugin.ts","../src/actions/index.ts"],"names":["registerAction"],"mappings":"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","file":"chunk-XGP3C2ZE.js","sourcesContent":["/**\r\n * @flight-framework/core - Action Middleware\r\n * \r\n * Agnostic middleware system for Server Actions.\r\n * Flight provides the PRIMITIVES, you build YOUR solution.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Create your own auth middleware (Flight doesn't impose any auth provider)\r\n * const withAuth = createActionMiddleware(async (ctx, next) => {\r\n * const session = await yourAuthProvider.getSession(ctx.headers);\r\n * if (!session) {\r\n * return { success: false, error: 'UNAUTHORIZED' };\r\n * }\r\n * ctx.set('session', session);\r\n * return next();\r\n * });\r\n * \r\n * // Create your own rate limiter (Flight doesn't impose any rate limit provider)\r\n * const withRateLimit = createActionMiddleware(async (ctx, next) => {\r\n * const allowed = await yourRateLimiter.check(ctx.get('session').userId);\r\n * if (!allowed) {\r\n * return { success: false, error: 'RATE_LIMITED' };\r\n * }\r\n * return next();\r\n * });\r\n * \r\n * // Compose them\r\n * const protectedAction = pipeline(withAuth, withRateLimit)(myAction);\r\n * ```\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Action context - holds request data and middleware-set values\r\n */\r\nexport interface ActionContext {\r\n /** Original request (if available) */\r\n readonly request?: Request;\r\n /** Request headers */\r\n readonly headers: Headers;\r\n /** Action ID being executed */\r\n readonly actionId: string;\r\n /** Action arguments */\r\n readonly args: unknown[];\r\n /** Abort signal for cancellation */\r\n readonly signal?: AbortSignal;\r\n\r\n /** Get a value set by previous middleware */\r\n get<T = unknown>(key: string): T | undefined;\r\n /** Set a value for subsequent middleware/action */\r\n set<T = unknown>(key: string, value: T): void;\r\n}\r\n\r\n/**\r\n * Action result following Flight conventions\r\n */\r\nexport interface ActionResult<T = unknown> {\r\n success: boolean;\r\n data?: T;\r\n error?: string;\r\n code?: string;\r\n}\r\n\r\n/**\r\n * Next function to call the next middleware or action\r\n */\r\nexport type ActionNext<T = unknown> = () => Promise<ActionResult<T>>;\r\n\r\n/**\r\n * Middleware handler function\r\n */\r\nexport type ActionMiddlewareHandler<TContext extends ActionContext = ActionContext> = (\r\n ctx: TContext,\r\n next: ActionNext\r\n) => Promise<ActionResult> | ActionResult;\r\n\r\n/**\r\n * A middleware instance\r\n */\r\nexport interface ActionMiddleware {\r\n /** Unique name for debugging */\r\n readonly name: string;\r\n /** The handler function */\r\n readonly handler: ActionMiddlewareHandler;\r\n}\r\n\r\n/**\r\n * An action function\r\n */\r\nexport type Action<TInput = unknown, TOutput = unknown> = (\r\n ...args: TInput extends unknown[] ? TInput : [TInput]\r\n) => Promise<ActionResult<TOutput>>;\r\n\r\n/**\r\n * Options for creating middleware\r\n */\r\nexport interface CreateMiddlewareOptions {\r\n /** Name for debugging/logging */\r\n name?: string;\r\n}\r\n\r\n// ============================================================================\r\n// Action Context Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * Create an action context from request or minimal data\r\n */\r\nexport function createActionContext(options: {\r\n request?: Request;\r\n headers?: Headers;\r\n actionId: string;\r\n args: unknown[];\r\n signal?: AbortSignal;\r\n}): ActionContext {\r\n const store = new Map<string, unknown>();\r\n\r\n return {\r\n request: options.request,\r\n headers: options.headers ?? options.request?.headers ?? new Headers(),\r\n actionId: options.actionId,\r\n args: options.args,\r\n signal: options.signal,\r\n\r\n get<T = unknown>(key: string): T | undefined {\r\n return store.get(key) as T | undefined;\r\n },\r\n\r\n set<T = unknown>(key: string, value: T): void {\r\n store.set(key, value);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Middleware Creation\r\n// ============================================================================\r\n\r\nlet middlewareCounter = 0;\r\n\r\n/**\r\n * Create a reusable action middleware.\r\n * \r\n * Flight provides this PRIMITIVE - you define WHAT the middleware does.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Authentication middleware (you choose the auth provider)\r\n * const withAuth = createActionMiddleware(async (ctx, next) => {\r\n * const token = ctx.headers.get('Authorization');\r\n * const user = await myAuthLib.verify(token); // YOUR auth library\r\n * \r\n * if (!user) {\r\n * return { success: false, error: 'Unauthorized', code: 'AUTH_ERROR' };\r\n * }\r\n * \r\n * ctx.set('user', user);\r\n * return next();\r\n * });\r\n * \r\n * // Validation middleware (you choose the validator)\r\n * const withValidation = (schema: ZodSchema) => createActionMiddleware(\r\n * async (ctx, next) => {\r\n * const result = schema.safeParse(ctx.args[0]);\r\n * if (!result.success) {\r\n * return { success: false, error: 'Validation failed', code: 'VALIDATION_ERROR' };\r\n * }\r\n * return next();\r\n * },\r\n * { name: 'validation' }\r\n * );\r\n * ```\r\n */\r\nexport function createActionMiddleware(\r\n handler: ActionMiddlewareHandler,\r\n options: CreateMiddlewareOptions = {}\r\n): ActionMiddleware {\r\n const name = options.name ?? `middleware_${++middlewareCounter}`;\r\n\r\n return {\r\n name,\r\n handler,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Pipeline Composition\r\n// ============================================================================\r\n\r\n/**\r\n * Compose multiple middleware into a pipeline that wraps an action.\r\n * \r\n * Middleware executes in order: first middleware runs first.\r\n * Each middleware can:\r\n * - Short-circuit by returning a result without calling next()\r\n * - Transform context for subsequent middleware\r\n * - Wrap the next() call for timing/logging\r\n * \r\n * @example\r\n * ```typescript\r\n * const protectedAction = pipeline(\r\n * withAuth,\r\n * withRateLimit,\r\n * withValidation(UserSchema),\r\n * )(createUserAction);\r\n * \r\n * // Now protectedAction has auth, rate-limit, and validation\r\n * const result = await protectedAction(userData);\r\n * ```\r\n */\r\nexport function pipeline<TInput, TOutput>(\r\n ...middlewares: ActionMiddleware[]\r\n): (action: Action<TInput, TOutput>) => Action<TInput, TOutput> {\r\n return (action: Action<TInput, TOutput>): Action<TInput, TOutput> => {\r\n return async (...args: TInput extends unknown[] ? TInput : [TInput]): Promise<ActionResult<TOutput>> => {\r\n // Create context for this execution\r\n const ctx = createActionContext({\r\n actionId: action.name || 'anonymous',\r\n args: args as unknown[],\r\n });\r\n\r\n // Build the middleware chain\r\n let index = -1;\r\n\r\n const dispatch = async (i: number): Promise<ActionResult<TOutput>> => {\r\n if (i <= index) {\r\n throw new Error('next() called multiple times');\r\n }\r\n index = i;\r\n\r\n if (i < middlewares.length) {\r\n // Execute middleware\r\n const middleware = middlewares[i]!;\r\n return middleware.handler(ctx, () => dispatch(i + 1)) as Promise<ActionResult<TOutput>>;\r\n } else {\r\n // Execute the actual action\r\n return action(...args);\r\n }\r\n };\r\n\r\n return dispatch(0);\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Execute an action with middleware, providing custom context.\r\n * \r\n * Use this when you need to provide request context (headers, etc.)\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await executeWithMiddleware(\r\n * myAction,\r\n * [arg1, arg2],\r\n * [withAuth, withRateLimit],\r\n * { request: incomingRequest }\r\n * );\r\n * ```\r\n */\r\nexport async function executeWithMiddleware<TInput extends unknown[], TOutput>(\r\n action: (...args: TInput) => Promise<ActionResult<TOutput>>,\r\n args: TInput,\r\n middlewares: ActionMiddleware[],\r\n options: {\r\n request?: Request;\r\n headers?: Headers;\r\n signal?: AbortSignal;\r\n } = {}\r\n): Promise<ActionResult<TOutput>> {\r\n // Create context with request info\r\n const ctx = createActionContext({\r\n request: options.request,\r\n headers: options.headers,\r\n actionId: action.name || 'anonymous',\r\n args: args as unknown[],\r\n signal: options.signal,\r\n });\r\n\r\n // Build the middleware chain\r\n let index = -1;\r\n\r\n const dispatch = async (i: number): Promise<ActionResult<TOutput>> => {\r\n // Check for abort\r\n if (options.signal?.aborted) {\r\n return { success: false, error: 'Aborted', code: 'ABORTED' };\r\n }\r\n\r\n if (i <= index) {\r\n throw new Error('next() called multiple times');\r\n }\r\n index = i;\r\n\r\n if (i < middlewares.length) {\r\n const middleware = middlewares[i]!;\r\n return middleware.handler(ctx, () => dispatch(i + 1)) as Promise<ActionResult<TOutput>>;\r\n } else {\r\n return action(...args);\r\n }\r\n };\r\n\r\n return dispatch(0);\r\n}\r\n\r\n// ============================================================================\r\n// Utility Middleware Factories\r\n// ============================================================================\r\n\r\n/**\r\n * Create a timing middleware for observability.\r\n * \r\n * You provide the reporter - Flight doesn't impose any observability provider.\r\n * \r\n * @example\r\n * ```typescript\r\n * const withTiming = createTimingMiddleware((actionId, durationMs) => {\r\n * myMetricsService.histogram('action.duration', durationMs, { actionId });\r\n * });\r\n * ```\r\n */\r\nexport function createTimingMiddleware(\r\n reporter: (actionId: string, durationMs: number, result: ActionResult) => void\r\n): ActionMiddleware {\r\n return createActionMiddleware(\r\n async (ctx, next) => {\r\n const start = performance.now();\r\n const result = await next();\r\n const duration = performance.now() - start;\r\n reporter(ctx.actionId, duration, result);\r\n return result;\r\n },\r\n { name: 'timing' }\r\n );\r\n}\r\n\r\n/**\r\n * Create a logging middleware.\r\n * \r\n * You provide the logger - Flight doesn't impose any logging library.\r\n * \r\n * @example\r\n * ```typescript\r\n * const withLogging = createLoggingMiddleware({\r\n * onStart: (ctx) => console.log(`[${ctx.actionId}] Starting...`),\r\n * onComplete: (ctx, result, ms) => console.log(`[${ctx.actionId}] ${result.success ? 'OK' : 'FAIL'} in ${ms}ms`),\r\n * });\r\n * ```\r\n */\r\nexport function createLoggingMiddleware(options: {\r\n onStart?: (ctx: ActionContext) => void;\r\n onComplete?: (ctx: ActionContext, result: ActionResult, durationMs: number) => void;\r\n onError?: (ctx: ActionContext, error: Error) => void;\r\n}): ActionMiddleware {\r\n return createActionMiddleware(\r\n async (ctx, next) => {\r\n options.onStart?.(ctx);\r\n const start = performance.now();\r\n\r\n try {\r\n const result = await next();\r\n const duration = performance.now() - start;\r\n options.onComplete?.(ctx, result, duration);\r\n return result;\r\n } catch (error) {\r\n options.onError?.(ctx, error as Error);\r\n throw error;\r\n }\r\n },\r\n { name: 'logging' }\r\n );\r\n}\r\n\r\n/**\r\n * Create a retry middleware.\r\n * \r\n * @example\r\n * ```typescript\r\n * const withRetry = createRetryMiddleware({\r\n * maxAttempts: 3,\r\n * delay: (attempt) => Math.pow(2, attempt) * 100, // Exponential backoff\r\n * shouldRetry: (result) => result.code === 'TEMPORARY_ERROR',\r\n * });\r\n * ```\r\n */\r\nexport function createRetryMiddleware(options: {\r\n maxAttempts: number;\r\n delay?: (attempt: number) => number;\r\n shouldRetry?: (result: ActionResult) => boolean;\r\n}): ActionMiddleware {\r\n const {\r\n maxAttempts,\r\n delay = () => 0,\r\n shouldRetry = (result) => !result.success,\r\n } = options;\r\n\r\n return createActionMiddleware(\r\n async (ctx, next) => {\r\n let lastResult: ActionResult = { success: false, error: 'No attempts made' };\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (attempt > 0) {\r\n const delayMs = delay(attempt);\r\n if (delayMs > 0) {\r\n await new Promise(resolve => setTimeout(resolve, delayMs));\r\n }\r\n }\r\n\r\n lastResult = await next();\r\n\r\n if (!shouldRetry(lastResult)) {\r\n return lastResult;\r\n }\r\n }\r\n\r\n return lastResult;\r\n },\r\n { name: 'retry' }\r\n );\r\n}\r\n","/**\r\n * @flight-framework/core - Action Streaming\r\n * \r\n * Streamable actions using async generators.\r\n * Flight provides the PRIMITIVES, you choose the transport.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Create a streamable action for long-running operations\r\n * const generateReport = createStreamableAction(async function* (params: ReportParams) {\r\n * yield { type: 'progress', message: 'Fetching data...', progress: 0 };\r\n * const data = await fetchData(params);\r\n * \r\n * yield { type: 'progress', message: 'Processing...', progress: 33 };\r\n * const processed = await processData(data);\r\n * \r\n * yield { type: 'progress', message: 'Generating PDF...', progress: 66 };\r\n * const pdf = await generatePDF(processed);\r\n * \r\n * yield { type: 'progress', message: 'Complete!', progress: 100 };\r\n * return { success: true, data: pdf };\r\n * });\r\n * \r\n * // Client consumption\r\n * for await (const update of generateReport(params)) {\r\n * if (update.type === 'progress') {\r\n * setProgress(update.progress);\r\n * } else if (update.type === 'result') {\r\n * handleResult(update.data);\r\n * }\r\n * }\r\n * ```\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Progress update yielded during streaming\r\n */\r\nexport interface StreamProgress<TYield = unknown> {\r\n type: 'progress';\r\n data: TYield;\r\n}\r\n\r\n/**\r\n * Final result of a streaming action\r\n */\r\nexport interface StreamResult<TReturn = unknown> {\r\n type: 'result';\r\n success: boolean;\r\n data?: TReturn;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Union type for stream items\r\n */\r\nexport type StreamItem<TYield, TReturn> = StreamProgress<TYield> | StreamResult<TReturn>;\r\n\r\n/**\r\n * Streamable action generator function\r\n */\r\nexport type StreamableGenerator<TInput, TYield, TReturn> = (\r\n input: TInput,\r\n signal?: AbortSignal\r\n) => AsyncGenerator<TYield, TReturn>;\r\n\r\n/**\r\n * Options for creating a streamable action\r\n */\r\nexport interface StreamableActionOptions {\r\n /** Name for debugging */\r\n name?: string;\r\n /** Timeout in milliseconds */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Controller for a running stream\r\n */\r\nexport interface StreamController<TYield, TReturn> {\r\n /** Async iterator for consuming the stream */\r\n [Symbol.asyncIterator](): AsyncIterator<StreamItem<TYield, TReturn>>;\r\n /** Abort the stream */\r\n abort(): void;\r\n /** Promise that resolves when stream completes */\r\n done: Promise<StreamResult<TReturn>>;\r\n}\r\n\r\n/**\r\n * A streamable action function\r\n */\r\nexport type StreamableAction<TInput, TYield, TReturn> = (\r\n input: TInput\r\n) => StreamController<TYield, TReturn>;\r\n\r\n// ============================================================================\r\n// Streamable Action Creation\r\n// ============================================================================\r\n\r\n/**\r\n * Create a streamable action from an async generator.\r\n * \r\n * Flight provides this PRIMITIVE - you define the generator logic\r\n * and choose how to transport the stream (HTTP, WebSocket, etc.)\r\n * \r\n * @example\r\n * ```typescript\r\n * // AI streaming response\r\n * const streamChat = createStreamableAction(async function* (message: string) {\r\n * const stream = await openai.chat.completions.create({\r\n * model: 'gpt-4',\r\n * messages: [{ role: 'user', content: message }],\r\n * stream: true,\r\n * });\r\n * \r\n * let fullResponse = '';\r\n * for await (const chunk of stream) {\r\n * const text = chunk.choices[0]?.delta?.content || '';\r\n * fullResponse += text;\r\n * yield { text, partial: true };\r\n * }\r\n * \r\n * return { text: fullResponse, partial: false };\r\n * });\r\n * ```\r\n */\r\nexport function createStreamableAction<TInput, TYield, TReturn>(\r\n generator: StreamableGenerator<TInput, TYield, TReturn>,\r\n options: StreamableActionOptions = {}\r\n): StreamableAction<TInput, TYield, TReturn> {\r\n const actionName = options.name ?? generator.name ?? 'streamable_action';\r\n\r\n return (input: TInput): StreamController<TYield, TReturn> => {\r\n const abortController = new AbortController();\r\n let completed = false;\r\n let finalResult: StreamResult<TReturn> | null = null;\r\n\r\n // Create done promise\r\n let resolveDone: (result: StreamResult<TReturn>) => void;\r\n const done = new Promise<StreamResult<TReturn>>((resolve) => {\r\n resolveDone = resolve;\r\n });\r\n\r\n // Setup timeout if specified\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\r\n if (options.timeout) {\r\n timeoutId = setTimeout(() => {\r\n abortController.abort();\r\n }, options.timeout);\r\n }\r\n\r\n // Create the async iterator\r\n async function* iterate(): AsyncGenerator<StreamItem<TYield, TReturn>> {\r\n try {\r\n const gen = generator(input, abortController.signal);\r\n\r\n while (true) {\r\n if (abortController.signal.aborted) {\r\n const abortResult: StreamResult<TReturn> = {\r\n type: 'result',\r\n success: false,\r\n error: 'Stream aborted',\r\n };\r\n finalResult = abortResult;\r\n resolveDone!(abortResult);\r\n yield abortResult;\r\n return;\r\n }\r\n\r\n const next = await gen.next();\r\n\r\n if (next.done) {\r\n // Generator returned - this is the final value\r\n const successResult: StreamResult<TReturn> = {\r\n type: 'result',\r\n success: true,\r\n data: next.value,\r\n };\r\n finalResult = successResult;\r\n completed = true;\r\n resolveDone!(successResult);\r\n yield successResult;\r\n return;\r\n } else {\r\n // Generator yielded - this is a progress update\r\n yield {\r\n type: 'progress',\r\n data: next.value,\r\n };\r\n }\r\n }\r\n } catch (error) {\r\n const errorResult: StreamResult<TReturn> = {\r\n type: 'result',\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n finalResult = errorResult;\r\n resolveDone!(errorResult);\r\n yield errorResult;\r\n } finally {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n }\r\n }\r\n\r\n const iterator = iterate();\r\n\r\n return {\r\n [Symbol.asyncIterator]() {\r\n return iterator;\r\n },\r\n abort() {\r\n abortController.abort();\r\n },\r\n done,\r\n };\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// HTTP Transport Adapter\r\n// ============================================================================\r\n\r\n/**\r\n * Convert a streamable action result to an HTTP streaming response.\r\n * \r\n * This is ONE transport option - you can create others (WebSocket, SSE, etc.)\r\n * \r\n * @example\r\n * ```typescript\r\n * // In your API route\r\n * export async function POST(request: Request) {\r\n * const body = await request.json();\r\n * const stream = generateReport(body);\r\n * return streamToResponse(stream);\r\n * }\r\n * ```\r\n */\r\nexport function streamToResponse<TYield, TReturn>(\r\n controller: StreamController<TYield, TReturn>,\r\n options: {\r\n headers?: Record<string, string>;\r\n } = {}\r\n): Response {\r\n const encoder = new TextEncoder();\r\n\r\n const stream = new ReadableStream({\r\n async start(streamController) {\r\n try {\r\n for await (const item of controller) {\r\n const chunk = JSON.stringify(item) + '\\n';\r\n streamController.enqueue(encoder.encode(chunk));\r\n\r\n if (item.type === 'result') {\r\n break;\r\n }\r\n }\r\n } catch (error) {\r\n const errorChunk = JSON.stringify({\r\n type: 'result',\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Stream error',\r\n }) + '\\n';\r\n streamController.enqueue(encoder.encode(errorChunk));\r\n } finally {\r\n streamController.close();\r\n }\r\n },\r\n cancel() {\r\n controller.abort();\r\n },\r\n });\r\n\r\n return new Response(stream, {\r\n status: 200,\r\n headers: {\r\n 'Content-Type': 'application/x-ndjson',\r\n 'Transfer-Encoding': 'chunked',\r\n 'Cache-Control': 'no-cache',\r\n 'Connection': 'keep-alive',\r\n ...options.headers,\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Parse an HTTP streaming response back to a stream controller (client-side).\r\n * \r\n * @example\r\n * ```typescript\r\n * // Client-side consumption\r\n * const response = await fetch('/api/generate-report', {\r\n * method: 'POST',\r\n * body: JSON.stringify(params),\r\n * });\r\n * \r\n * const stream = responseToStream<Progress, Report>(response);\r\n * \r\n * for await (const item of stream) {\r\n * if (item.type === 'progress') {\r\n * setProgress(item.data);\r\n * } else {\r\n * setReport(item.data);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function responseToStream<TYield, TReturn>(\r\n response: Response\r\n): AsyncGenerator<StreamItem<TYield, TReturn>> {\r\n const reader = response.body?.getReader();\r\n const decoder = new TextDecoder();\r\n\r\n if (!reader) {\r\n throw new Error('Response body is not readable');\r\n }\r\n\r\n return (async function* () {\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n\r\n if (done) {\r\n break;\r\n }\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // Process complete lines\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() || ''; // Keep incomplete line in buffer\r\n\r\n for (const line of lines) {\r\n if (line.trim()) {\r\n try {\r\n const item = JSON.parse(line) as StreamItem<TYield, TReturn>;\r\n yield item;\r\n } catch {\r\n // Skip malformed JSON\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Process remaining buffer\r\n if (buffer.trim()) {\r\n try {\r\n const item = JSON.parse(buffer) as StreamItem<TYield, TReturn>;\r\n yield item;\r\n } catch {\r\n // Skip malformed JSON\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n })();\r\n}\r\n\r\n// ============================================================================\r\n// Utility Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Collect all items from a stream into an array.\r\n * \r\n * Useful for testing or when you want to wait for completion.\r\n */\r\nexport async function collectStream<TYield, TReturn>(\r\n controller: StreamController<TYield, TReturn>\r\n): Promise<{ items: StreamItem<TYield, TReturn>[]; result: StreamResult<TReturn> }> {\r\n const items: StreamItem<TYield, TReturn>[] = [];\r\n let result: StreamResult<TReturn> | null = null;\r\n\r\n for await (const item of controller) {\r\n items.push(item);\r\n if (item.type === 'result') {\r\n result = item;\r\n }\r\n }\r\n\r\n if (!result) {\r\n result = { type: 'result', success: false, error: 'No result received' };\r\n }\r\n\r\n return { items, result };\r\n}\r\n\r\n/**\r\n * Create a simple progress reporter for streams.\r\n * \r\n * @example\r\n * ```typescript\r\n * const onProgress = createProgressReporter<MyProgress>((data) => {\r\n * console.log(`Progress: ${data.percent}%`);\r\n * });\r\n * \r\n * for await (const item of myStream) {\r\n * onProgress(item);\r\n * }\r\n * ```\r\n */\r\nexport function createProgressReporter<TYield, TReturn = unknown>(\r\n onProgress: (data: TYield) => void,\r\n onComplete?: (result: StreamResult<TReturn>) => void\r\n): (item: StreamItem<TYield, TReturn>) => void {\r\n return (item: StreamItem<TYield, TReturn>) => {\r\n if (item.type === 'progress') {\r\n onProgress(item.data);\r\n } else {\r\n onComplete?.(item);\r\n }\r\n };\r\n}\r\n","/**\r\n * @flight-framework/core - Action Queue\r\n * \r\n * Offline-first action queuing with pluggable storage.\r\n * Flight provides the PRIMITIVES and INTERFACE, you choose the storage.\r\n * \r\n * @example\r\n * ```typescript\r\n * // 1. Use a storage adapter (install separately or create your own)\r\n * import { indexedDBAdapter } from '@flight-framework/queue-indexeddb';\r\n * // OR create your own:\r\n * const myAdapter: QueueStorageAdapter = { ... };\r\n * \r\n * // 2. Create a queued action\r\n * const saveNote = createQueuedAction(\r\n * async (note: Note) => {\r\n * await api.saveNote(note);\r\n * return { success: true };\r\n * },\r\n * {\r\n * storage: indexedDBAdapter({ dbName: 'myapp' }),\r\n * retryStrategy: exponentialBackoff({ maxAttempts: 5 }),\r\n * onStatusChange: (status) => console.log('Queue status:', status),\r\n * }\r\n * );\r\n * \r\n * // 3. Use it - works offline!\r\n * await saveNote({ title: 'My Note', content: '...' });\r\n * // If offline: queued and synced later\r\n * // If online: executed immediately\r\n * ```\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * A queued action entry\r\n */\r\nexport interface QueuedActionEntry<TInput = unknown> {\r\n /** Unique ID for this entry */\r\n id: string;\r\n /** Action identifier */\r\n actionId: string;\r\n /** Action arguments */\r\n input: TInput;\r\n /** When the action was queued */\r\n queuedAt: number;\r\n /** Number of execution attempts */\r\n attempts: number;\r\n /** Last error message if failed */\r\n lastError?: string;\r\n /** Status */\r\n status: 'pending' | 'processing' | 'failed';\r\n /** Optional metadata */\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Queue storage adapter interface.\r\n * \r\n * Flight does NOT provide storage implementations - you choose:\r\n * - @flight-framework/queue-indexeddb (browser)\r\n * - @flight-framework/queue-sqlite (mobile/desktop)\r\n * - @flight-framework/queue-memory (testing)\r\n * - Your own implementation\r\n */\r\nexport interface QueueStorageAdapter {\r\n /** Add an action to the queue */\r\n enqueue<TInput>(entry: QueuedActionEntry<TInput>): Promise<void>;\r\n\r\n /** Get and remove the next pending action */\r\n dequeue(): Promise<QueuedActionEntry | null>;\r\n\r\n /** Get all pending actions without removing */\r\n peek(): Promise<QueuedActionEntry[]>;\r\n\r\n /** Update an existing entry */\r\n update(id: string, updates: Partial<QueuedActionEntry>): Promise<void>;\r\n\r\n /** Remove an entry by ID */\r\n remove(id: string): Promise<void>;\r\n\r\n /** Clear all entries */\r\n clear(): Promise<void>;\r\n\r\n /** Get queue length */\r\n length(): Promise<number>;\r\n}\r\n\r\n/**\r\n * Retry strategy function\r\n */\r\nexport type RetryStrategy = (\r\n entry: QueuedActionEntry,\r\n error: Error\r\n) => { shouldRetry: boolean; delayMs: number };\r\n\r\n/**\r\n * Queue status for observability\r\n */\r\nexport interface QueueStatus {\r\n /** Whether the queue processor is running */\r\n isProcessing: boolean;\r\n /** Number of pending actions */\r\n pendingCount: number;\r\n /** Number of failed actions */\r\n failedCount: number;\r\n /** Whether online */\r\n isOnline: boolean;\r\n}\r\n\r\n/**\r\n * Options for creating a queued action\r\n */\r\nexport interface QueuedActionOptions {\r\n /** Storage adapter (required - Flight doesn't provide default) */\r\n storage: QueueStorageAdapter;\r\n /** Custom action ID */\r\n actionId?: string;\r\n /** Retry strategy */\r\n retryStrategy?: RetryStrategy;\r\n /** Check if online (default: navigator.onLine on browser) */\r\n isOnline?: () => boolean | Promise<boolean>;\r\n /** Called when queue status changes */\r\n onStatusChange?: (status: QueueStatus) => void;\r\n /** Called when an action is successfully processed */\r\n onSuccess?: (entry: QueuedActionEntry, result: unknown) => void;\r\n /** Called when an action fails permanently */\r\n onFailure?: (entry: QueuedActionEntry, error: Error) => void;\r\n}\r\n\r\n/**\r\n * Action result for queued actions\r\n */\r\nexport interface QueuedActionResult<TOutput = unknown> {\r\n /** Whether immediately executed or queued */\r\n queued: boolean;\r\n /** Queue entry ID if queued */\r\n entryId?: string;\r\n /** Result if immediately executed */\r\n result?: { success: boolean; data?: TOutput; error?: string };\r\n}\r\n\r\n/**\r\n * A queued action function\r\n */\r\nexport type QueuedAction<TInput, TOutput> = (\r\n input: TInput\r\n) => Promise<QueuedActionResult<TOutput>>;\r\n\r\n// ============================================================================\r\n// Queue Creation\r\n// ============================================================================\r\n\r\nlet entryCounter = 0;\r\n\r\nfunction generateEntryId(): string {\r\n return `${Date.now()}_${++entryCounter}_${Math.random().toString(36).substring(2, 9)}`;\r\n}\r\n\r\n/**\r\n * Create an offline-capable queued action.\r\n * \r\n * Flight provides this PRIMITIVE - you provide the storage adapter.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Create with your storage adapter\r\n * const syncData = createQueuedAction(\r\n * async (data: MyData) => {\r\n * await api.sync(data);\r\n * return { success: true };\r\n * },\r\n * {\r\n * storage: myStorageAdapter,\r\n * retryStrategy: exponentialBackoff(),\r\n * }\r\n * );\r\n * \r\n * // Use it - works offline automatically\r\n * const result = await syncData({ items: [...] });\r\n * \r\n * if (result.queued) {\r\n * console.log('Queued for later sync:', result.entryId);\r\n * } else {\r\n * console.log('Synced immediately:', result.result);\r\n * }\r\n * ```\r\n */\r\nexport function createQueuedAction<TInput, TOutput>(\r\n action: (input: TInput) => Promise<{ success: boolean; data?: TOutput; error?: string }>,\r\n options: QueuedActionOptions\r\n): QueuedAction<TInput, TOutput> {\r\n const {\r\n storage,\r\n actionId = action.name || `action_${Date.now()}`,\r\n retryStrategy = defaultRetryStrategy,\r\n isOnline = defaultIsOnline,\r\n onStatusChange,\r\n onSuccess,\r\n onFailure,\r\n } = options;\r\n\r\n // Queue processor state\r\n let isProcessing = false;\r\n let processorRunning = false;\r\n\r\n // Start background processor\r\n startProcessor();\r\n\r\n async function startProcessor() {\r\n if (processorRunning) return;\r\n processorRunning = true;\r\n\r\n // Process queue periodically\r\n while (processorRunning) {\r\n await processQueue();\r\n await sleep(1000); // Check every second\r\n }\r\n }\r\n\r\n async function processQueue() {\r\n // Check if online\r\n const online = await isOnline();\r\n if (!online) {\r\n return;\r\n }\r\n\r\n // Get next entry\r\n const entry = await storage.dequeue();\r\n if (!entry) {\r\n if (isProcessing) {\r\n isProcessing = false;\r\n await notifyStatus();\r\n }\r\n return;\r\n }\r\n\r\n isProcessing = true;\r\n await notifyStatus();\r\n\r\n // Update status to processing\r\n await storage.update(entry.id, { status: 'processing' });\r\n\r\n try {\r\n // Execute the action\r\n const result = await action(entry.input as TInput);\r\n\r\n // Success - remove from queue\r\n await storage.remove(entry.id);\r\n onSuccess?.(entry, result);\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Check retry strategy\r\n const { shouldRetry, delayMs } = retryStrategy(entry, err);\r\n\r\n if (shouldRetry) {\r\n // Re-queue with updated attempts\r\n await storage.update(entry.id, {\r\n status: 'pending',\r\n attempts: entry.attempts + 1,\r\n lastError: err.message,\r\n });\r\n\r\n // Wait before next attempt\r\n if (delayMs > 0) {\r\n await sleep(delayMs);\r\n }\r\n } else {\r\n // Mark as failed\r\n await storage.update(entry.id, {\r\n status: 'failed',\r\n lastError: err.message,\r\n });\r\n onFailure?.(entry, err);\r\n }\r\n }\r\n }\r\n\r\n async function notifyStatus() {\r\n if (!onStatusChange) return;\r\n\r\n const entries = await storage.peek();\r\n const status: QueueStatus = {\r\n isProcessing,\r\n pendingCount: entries.filter(e => e.status === 'pending').length,\r\n failedCount: entries.filter(e => e.status === 'failed').length,\r\n isOnline: await isOnline(),\r\n };\r\n onStatusChange(status);\r\n }\r\n\r\n // Return the queued action function\r\n return async (input: TInput): Promise<QueuedActionResult<TOutput>> => {\r\n const online = await isOnline();\r\n\r\n if (online) {\r\n // Try to execute immediately\r\n try {\r\n const result = await action(input);\r\n return { queued: false, result };\r\n } catch {\r\n // Fall through to queue\r\n }\r\n }\r\n\r\n // Queue for later\r\n const entry: QueuedActionEntry<TInput> = {\r\n id: generateEntryId(),\r\n actionId,\r\n input,\r\n queuedAt: Date.now(),\r\n attempts: 0,\r\n status: 'pending',\r\n };\r\n\r\n await storage.enqueue(entry);\r\n await notifyStatus();\r\n\r\n return { queued: true, entryId: entry.id };\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Built-in Retry Strategies\r\n// ============================================================================\r\n\r\n/**\r\n * Default retry strategy: 3 attempts with 1 second delay\r\n */\r\nexport const defaultRetryStrategy: RetryStrategy = (entry) => ({\r\n shouldRetry: entry.attempts < 3,\r\n delayMs: 1000,\r\n});\r\n\r\n/**\r\n * Create an exponential backoff retry strategy.\r\n * \r\n * @example\r\n * ```typescript\r\n * const retry = exponentialBackoff({\r\n * maxAttempts: 5,\r\n * baseDelayMs: 1000,\r\n * maxDelayMs: 30000,\r\n * });\r\n * ```\r\n */\r\nexport function exponentialBackoff(options: {\r\n maxAttempts?: number;\r\n baseDelayMs?: number;\r\n maxDelayMs?: number;\r\n} = {}): RetryStrategy {\r\n const {\r\n maxAttempts = 5,\r\n baseDelayMs = 1000,\r\n maxDelayMs = 30000,\r\n } = options;\r\n\r\n return (entry) => {\r\n const shouldRetry = entry.attempts < maxAttempts;\r\n const delayMs = Math.min(\r\n baseDelayMs * Math.pow(2, entry.attempts),\r\n maxDelayMs\r\n );\r\n\r\n return { shouldRetry, delayMs };\r\n };\r\n}\r\n\r\n/**\r\n * Create a fixed delay retry strategy.\r\n */\r\nexport function fixedDelay(options: {\r\n maxAttempts?: number;\r\n delayMs?: number;\r\n} = {}): RetryStrategy {\r\n const { maxAttempts = 3, delayMs = 1000 } = options;\r\n\r\n return (entry) => ({\r\n shouldRetry: entry.attempts < maxAttempts,\r\n delayMs,\r\n });\r\n}\r\n\r\n// ============================================================================\r\n// In-Memory Storage Adapter (for testing only)\r\n// ============================================================================\r\n\r\n/**\r\n * In-memory queue storage adapter.\r\n * \r\n * ⚠️ FOR TESTING ONLY - data is lost on page refresh.\r\n * \r\n * For production, use:\r\n * - @flight-framework/queue-indexeddb (browser)\r\n * - @flight-framework/queue-sqlite (native apps)\r\n * - Your own implementation\r\n */\r\nexport function createMemoryAdapter(): QueueStorageAdapter {\r\n const store = new Map<string, QueuedActionEntry>();\r\n\r\n return {\r\n async enqueue(entry) {\r\n store.set(entry.id, entry);\r\n },\r\n\r\n async dequeue() {\r\n for (const [id, entry] of store.entries()) {\r\n if (entry.status === 'pending') {\r\n store.delete(id);\r\n return entry;\r\n }\r\n }\r\n return null;\r\n },\r\n\r\n async peek() {\r\n return Array.from(store.values());\r\n },\r\n\r\n async update(id, updates) {\r\n const entry = store.get(id);\r\n if (entry) {\r\n store.set(id, { ...entry, ...updates });\r\n }\r\n },\r\n\r\n async remove(id) {\r\n store.delete(id);\r\n },\r\n\r\n async clear() {\r\n store.clear();\r\n },\r\n\r\n async length() {\r\n return store.size;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Utility Functions\r\n// ============================================================================\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\nfunction defaultIsOnline(): boolean {\r\n if (typeof navigator !== 'undefined' && 'onLine' in navigator) {\r\n return navigator.onLine;\r\n }\r\n // Assume online in non-browser environments\r\n return true;\r\n}\r\n\r\n/**\r\n * Create a queue manager to control multiple queued actions.\r\n * \r\n * @example\r\n * ```typescript\r\n * const queueManager = createQueueManager({\r\n * storage: myStorageAdapter,\r\n * });\r\n * \r\n * // Pause all processing\r\n * queueManager.pause();\r\n * \r\n * // Resume\r\n * queueManager.resume();\r\n * \r\n * // Get status\r\n * const status = await queueManager.getStatus();\r\n * ```\r\n */\r\nexport function createQueueManager(options: {\r\n storage: QueueStorageAdapter;\r\n}): {\r\n pause: () => void;\r\n resume: () => void;\r\n getStatus: () => Promise<QueueStatus>;\r\n clearFailed: () => Promise<void>;\r\n retryFailed: () => Promise<void>;\r\n} {\r\n let paused = false;\r\n\r\n return {\r\n pause() {\r\n paused = true;\r\n },\r\n\r\n resume() {\r\n paused = false;\r\n },\r\n\r\n async getStatus() {\r\n const entries = await options.storage.peek();\r\n return {\r\n isProcessing: !paused,\r\n pendingCount: entries.filter(e => e.status === 'pending').length,\r\n failedCount: entries.filter(e => e.status === 'failed').length,\r\n isOnline: defaultIsOnline(),\r\n };\r\n },\r\n\r\n async clearFailed() {\r\n const entries = await options.storage.peek();\r\n for (const entry of entries) {\r\n if (entry.status === 'failed') {\r\n await options.storage.remove(entry.id);\r\n }\r\n }\r\n },\r\n\r\n async retryFailed() {\r\n const entries = await options.storage.peek();\r\n for (const entry of entries) {\r\n if (entry.status === 'failed') {\r\n await options.storage.update(entry.id, {\r\n status: 'pending',\r\n attempts: 0,\r\n lastError: undefined,\r\n });\r\n }\r\n }\r\n },\r\n };\r\n}\r\n","/**\r\n * @flight-framework/core - Server Actions Vite Plugin\r\n * \r\n * Transforms files with 'use server' directive.\r\n * Similar to React 19 / Next.js server actions compilation.\r\n */\r\n\r\nimport type { Plugin } from 'vite';\r\nimport { generateActionId, registerAction } from './index.js';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface ServerActionsPluginOptions {\r\n /** Include patterns */\r\n include?: string[];\r\n /** Exclude patterns */\r\n exclude?: string[];\r\n}\r\n\r\n// ============================================================================\r\n// Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin for server actions transformation\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { serverActionsPlugin } from '@flight-framework/core/actions';\r\n * \r\n * export default {\r\n * plugins: [serverActionsPlugin()],\r\n * };\r\n * ```\r\n */\r\nexport function serverActionsPlugin(options: ServerActionsPluginOptions = {}): Plugin {\r\n const {\r\n include = ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],\r\n exclude = ['**/node_modules/**'],\r\n } = options;\r\n\r\n return {\r\n name: 'flight:server-actions',\r\n\r\n async transform(code, id) {\r\n // Skip excluded files\r\n if (exclude.some(pattern => id.includes(pattern.replace('**/', '')))) {\r\n return null;\r\n }\r\n\r\n // Check for 'use server' directive\r\n if (!hasUseServerDirective(code)) {\r\n return null;\r\n }\r\n\r\n // Transform the file\r\n const transformed = transformServerActions(code, id);\r\n\r\n return {\r\n code: transformed,\r\n map: null, // TODO: Generate source map\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Transformation\r\n// ============================================================================\r\n\r\nconst USE_SERVER_REGEX = /^(['\"])use server\\1;?\\s*$/m;\r\nconst FUNCTION_REGEX = /^(export\\s+)?(async\\s+)?function\\s+(\\w+)/gm;\r\nconst ARROW_FUNCTION_REGEX = /^(export\\s+)?(const|let)\\s+(\\w+)\\s*=\\s*(async\\s+)?\\(/gm;\r\n\r\n/**\r\n * Check if file has 'use server' directive\r\n */\r\nfunction hasUseServerDirective(code: string): boolean {\r\n return USE_SERVER_REGEX.test(code);\r\n}\r\n\r\n/**\r\n * Transform server actions in a file\r\n */\r\nfunction transformServerActions(code: string, filePath: string): string {\r\n // Check if directive is at file level (whole file is server actions)\r\n const isFileLevel = code.trim().startsWith(\"'use server'\") ||\r\n code.trim().startsWith('\"use server\"');\r\n\r\n if (isFileLevel) {\r\n return transformFileLevelActions(code, filePath);\r\n }\r\n\r\n // Otherwise, look for inline 'use server' in functions\r\n return transformInlineActions(code, filePath);\r\n}\r\n\r\n/**\r\n * Transform file where all functions are server actions\r\n */\r\nfunction transformFileLevelActions(code: string, filePath: string): string {\r\n // Remove the 'use server' directive\r\n const transformed = code.replace(USE_SERVER_REGEX, '');\r\n\r\n // Find all exported functions\r\n const functions: Array<{ name: string; isAsync: boolean; isExported: boolean }> = [];\r\n\r\n // Regular functions\r\n let match;\r\n FUNCTION_REGEX.lastIndex = 0;\r\n while ((match = FUNCTION_REGEX.exec(code)) !== null) {\r\n functions.push({\r\n name: match[3],\r\n isExported: !!match[1],\r\n isAsync: !!match[2],\r\n });\r\n }\r\n\r\n // Arrow functions\r\n ARROW_FUNCTION_REGEX.lastIndex = 0;\r\n while ((match = ARROW_FUNCTION_REGEX.exec(code)) !== null) {\r\n functions.push({\r\n name: match[3],\r\n isExported: !!match[1],\r\n isAsync: !!match[4],\r\n });\r\n }\r\n\r\n // Generate registration code\r\n const registrations = functions\r\n .filter(fn => fn.isExported)\r\n .map(fn => {\r\n const actionId = generateActionId(fn.name, filePath);\r\n return `__flight_registerAction({ id: \"${actionId}\", name: \"${fn.name}\", filePath: \"${filePath}\", fn: ${fn.name} });`;\r\n })\r\n .join('\\n');\r\n\r\n // Add imports and registrations\r\n const imports = `import { registerAction as __flight_registerAction } from '@flight-framework/core/actions';\\n`;\r\n\r\n return imports + transformed + '\\n\\n// Server action registrations\\n' + registrations;\r\n}\r\n\r\n/**\r\n * Transform inline 'use server' in functions\r\n */\r\nfunction transformInlineActions(code: string, filePath: string): string {\r\n // This is a simplified version - a full implementation would use a proper AST parser\r\n // For now, we detect functions with 'use server' at the start of their body\r\n\r\n const inlineServerRegex = /((async\\s+)?function\\s+(\\w+)\\s*\\([^)]*\\)\\s*\\{)\\s*(['\"])use server\\4;?/g;\r\n\r\n let transformed = code;\r\n let match;\r\n const actionsToRegister: string[] = [];\r\n\r\n while ((match = inlineServerRegex.exec(code)) !== null) {\r\n const functionName = match[3];\r\n const actionId = generateActionId(functionName, filePath);\r\n\r\n // Remove 'use server' from function body\r\n transformed = transformed.replace(match[0], match[1]);\r\n\r\n actionsToRegister.push(\r\n `__flight_registerAction({ id: \"${actionId}\", name: \"${functionName}\", filePath: \"${filePath}\", fn: ${functionName} });`\r\n );\r\n }\r\n\r\n if (actionsToRegister.length > 0) {\r\n const imports = `import { registerAction as __flight_registerAction } from '@flight-framework/core/actions';\\n`;\r\n return imports + transformed + '\\n\\n// Server action registrations\\n' + actionsToRegister.join('\\n');\r\n }\r\n\r\n return transformed;\r\n}\r\n\r\n// ============================================================================\r\n// Client Helper\r\n// ============================================================================\r\n\r\n/**\r\n * Create a client-side action caller\r\n * \r\n * @example\r\n * ```typescript\r\n * // In client component\r\n * import { createActionCaller } from '@flight-framework/core/actions';\r\n * \r\n * const submitForm = createActionCaller('action_abc123');\r\n * \r\n * // Usage\r\n * const result = await submitForm({ name: 'John' });\r\n * ```\r\n */\r\nexport function createActionCaller<TArgs extends unknown[], TResult>(\r\n actionId: string\r\n): (...args: TArgs) => Promise<TResult> {\r\n return async (...args: TArgs): Promise<TResult> => {\r\n const response = await fetch(`/__flight_action/${actionId}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(args),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Action failed: ${response.statusText}`);\r\n }\r\n\r\n const result = await response.json();\r\n\r\n if (!result.success) {\r\n throw new Error(result.error || 'Action failed');\r\n }\r\n\r\n return result.data;\r\n };\r\n}\r\n\r\n/**\r\n * Create a form action for HTML forms\r\n * \r\n * @example\r\n * ```tsx\r\n * <form action={formAction('action_abc123')}>\r\n * <input name=\"email\" />\r\n * <button type=\"submit\">Submit</button>\r\n * </form>\r\n * ```\r\n */\r\nexport function formAction(actionId: string): string {\r\n return `/__flight_action/${actionId}`;\r\n}\r\n","/**\r\n * @flight-framework/core - Server Actions\r\n * \r\n * Implementation of React 19 style Server Actions.\r\n * Functions marked with 'use server' run on the server.\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Server action metadata\r\n */\r\nexport interface ServerAction {\r\n /** Unique action ID */\r\n id: string;\r\n /** Original function name */\r\n name: string;\r\n /** File path where action is defined */\r\n filePath: string;\r\n /** The actual action function */\r\n fn: (...args: unknown[]) => Promise<unknown>;\r\n}\r\n\r\n/**\r\n * Server action result\r\n */\r\nexport interface ActionResult<T = unknown> {\r\n success: boolean;\r\n data?: T;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Form action data\r\n */\r\nexport interface FormActionData {\r\n actionId: string;\r\n formData: FormData;\r\n}\r\n\r\n// ============================================================================\r\n// Action Registry\r\n// ============================================================================\r\n\r\nconst actionRegistry = new Map<string, ServerAction>();\r\n\r\n/**\r\n * Register a server action\r\n */\r\nexport function registerAction(action: ServerAction): void {\r\n actionRegistry.set(action.id, action);\r\n}\r\n\r\n/**\r\n * Get a registered action by ID\r\n */\r\nexport function getAction(id: string): ServerAction | undefined {\r\n return actionRegistry.get(id);\r\n}\r\n\r\n/**\r\n * Get all registered actions\r\n */\r\nexport function getAllActions(): ServerAction[] {\r\n return Array.from(actionRegistry.values());\r\n}\r\n\r\n/**\r\n * Clear all registered actions (useful for testing)\r\n */\r\nexport function clearActions(): void {\r\n actionRegistry.clear();\r\n}\r\n\r\n// ============================================================================\r\n// Action Execution\r\n// ============================================================================\r\n\r\n/**\r\n * Execute a server action\r\n */\r\nexport async function executeAction<T = unknown>(\r\n actionId: string,\r\n args: unknown[]\r\n): Promise<ActionResult<T>> {\r\n const action = getAction(actionId);\r\n\r\n if (!action) {\r\n return {\r\n success: false,\r\n error: `Action not found: ${actionId}`,\r\n };\r\n }\r\n\r\n try {\r\n const result = await action.fn(...args);\r\n return {\r\n success: true,\r\n data: result as T,\r\n };\r\n } catch (error) {\r\n // Re-throw RedirectError so handleActionRequest can return 303\r\n if (isRedirectError(error)) {\r\n throw error;\r\n }\r\n console.error(`[Flight] Action error (${actionId}):`, error);\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Execute a form action\r\n */\r\nexport async function executeFormAction<T = unknown>(\r\n actionId: string,\r\n formData: FormData\r\n): Promise<ActionResult<T>> {\r\n return executeAction<T>(actionId, [formData]);\r\n}\r\n\r\n// ============================================================================\r\n// Action ID Generation\r\n// ============================================================================\r\n\r\nlet actionCounter = 0;\r\n\r\n/**\r\n * Generate a unique action ID\r\n */\r\nexport function generateActionId(name: string, filePath: string): string {\r\n const hash = simpleHash(`${filePath}:${name}`);\r\n return `action_${hash}_${actionCounter++}`;\r\n}\r\n\r\n/**\r\n * Simple hash function for action IDs\r\n */\r\nfunction simpleHash(str: string): string {\r\n let hash = 0;\r\n for (let i = 0; i < str.length; i++) {\r\n const char = str.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash; // Convert to 32bit integer\r\n }\r\n return Math.abs(hash).toString(36);\r\n}\r\n\r\n// ============================================================================\r\n// Action Helpers (for use inside actions)\r\n// ============================================================================\r\n\r\n/**\r\n * Get cookies in server action context\r\n */\r\nexport function cookies(): {\r\n get: (name: string) => string | undefined;\r\n set: (name: string, value: string, options?: CookieOptions) => void;\r\n delete: (name: string) => void;\r\n} {\r\n // This will be populated by the runtime\r\n const cookieStore = (globalThis as any).__flightCookies;\r\n\r\n if (!cookieStore) {\r\n console.warn('[Flight] Cookies not available outside of action context');\r\n return {\r\n get: () => undefined,\r\n set: () => { },\r\n delete: () => { },\r\n };\r\n }\r\n\r\n return cookieStore;\r\n}\r\n\r\nexport interface CookieOptions {\r\n maxAge?: number;\r\n expires?: Date;\r\n path?: string;\r\n domain?: string;\r\n secure?: boolean;\r\n httpOnly?: boolean;\r\n sameSite?: 'strict' | 'lax' | 'none';\r\n}\r\n\r\n/**\r\n * Redirect in server action context\r\n */\r\nexport function redirect(url: string): never {\r\n throw new RedirectError(url);\r\n}\r\n\r\n/**\r\n * Special error for redirects\r\n */\r\nexport class RedirectError extends Error {\r\n public readonly url: string;\r\n\r\n constructor(url: string) {\r\n super(`Redirect to ${url}`);\r\n this.name = 'RedirectError';\r\n this.url = url;\r\n }\r\n}\r\n\r\n/**\r\n * Check if error is a redirect\r\n */\r\nexport function isRedirectError(error: unknown): error is RedirectError {\r\n return error instanceof RedirectError;\r\n}\r\n\r\n// ============================================================================\r\n// Form Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Parse form data to typed object\r\n */\r\nexport function parseFormData<T extends Record<string, string>>(\r\n formData: FormData\r\n): T {\r\n const result: Record<string, string> = {};\r\n\r\n formData.forEach((value, key) => {\r\n result[key] = String(value);\r\n });\r\n\r\n return result as T;\r\n}\r\n\r\n/**\r\n * Create action reference for form action attribute\r\n */\r\nexport function createActionReference(actionId: string): string {\r\n return `/__flight_action/${actionId}`;\r\n}\r\n\r\n// ============================================================================\r\n// Action Handler (for HTTP endpoint)\r\n// ============================================================================\r\n\r\n/**\r\n * Handle action request from client\r\n */\r\nexport async function handleActionRequest(\r\n request: Request\r\n): Promise<Response> {\r\n const url = new URL(request.url);\r\n const actionPath = url.pathname;\r\n\r\n // Extract action ID from path: /__flight_action/{actionId}\r\n const match = actionPath.match(/^\\/__flight_action\\/(.+)$/);\r\n\r\n if (!match) {\r\n return new Response(JSON.stringify({ error: 'Invalid action path' }), {\r\n status: 400,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n }\r\n\r\n const actionId = match[1];\r\n\r\n if (!actionId) {\r\n return new Response(JSON.stringify({ error: 'Missing action ID' }), {\r\n status: 400,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n }\r\n\r\n try {\r\n let result: ActionResult;\r\n\r\n // Check content type for form vs JSON\r\n const contentType = request.headers.get('content-type') || '';\r\n\r\n if (contentType.includes('application/x-www-form-urlencoded') ||\r\n contentType.includes('multipart/form-data')) {\r\n const formData = await request.formData();\r\n result = await executeFormAction(actionId, formData);\r\n } else {\r\n const args = await request.json();\r\n result = await executeAction(actionId, Array.isArray(args) ? args : [args]);\r\n }\r\n\r\n return new Response(JSON.stringify(result), {\r\n status: result.success ? 200 : 400,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n } catch (error) {\r\n if (isRedirectError(error)) {\r\n return new Response(null, {\r\n status: 303,\r\n headers: { Location: error.url },\r\n });\r\n }\r\n\r\n return new Response(JSON.stringify({\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n }), {\r\n status: 500,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Re-export New Modules\r\n// ============================================================================\r\n\r\n// Action Middleware - composable middleware for actions\r\nexport * from './middleware.js';\r\n\r\n// Action Streaming - async generator-based streaming actions\r\nexport * from './streaming.js';\r\n\r\n// Action Queue - offline-first action queuing\r\nexport * from './queue.js';\r\n\r\n// Vite Plugin - transforms 'use server' files\r\nexport {\r\n serverActionsPlugin,\r\n createActionCaller,\r\n formAction,\r\n type ServerActionsPluginOptions,\r\n} from './plugin.js';\r\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { ClientComponent, ComponentType as RSCComponentType, RenderContext as RS
|
|
|
22
22
|
export { BadRequestError, ErrorBoundaryOptions, FlightError, FlightErrorOptions, FlightErrorProps, ForbiddenError, InternalError, NotFoundError, ResetDetails, UnauthorizedError, clearError, createError, createErrorResponse, forbidden as createForbidden, notFound as createNotFound, unauthorized as createUnauthorized, getError, getErrorStatusCode, isFlightError, isForbiddenError as isForbidden, isNotFoundError as isNotFound, isUnauthorizedError as isUnauthorized, showError, wrapWithDigest } from './errors/index.js';
|
|
23
23
|
export { g as getEnvironment, d as isBrowser, a as isDevelopment, i as isProduction, c as isServer, b as isTest } from './env-9do2c6yn.js';
|
|
24
24
|
export { assertClient, assertServer, getEnv, requireEnv } from './utils/index.js';
|
|
25
|
+
import 'vite';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* @flight-framework/core - Route Rules Configuration
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ export { detectBoundaryType, hasUseClientDirective, hasUseServerDirective } from
|
|
|
18
18
|
import './chunk-77MJZCYD.js';
|
|
19
19
|
export { createServer } from './chunk-EGB7C73X.js';
|
|
20
20
|
export { createFileRouter, loadRoutes, scanRoutes } from './chunk-3KRBRSRJ.js';
|
|
21
|
-
export { RedirectError, redirect as actionRedirect, cookies, executeAction, executeFormAction, getAction, handleActionRequest, isRedirectError, parseFormData, registerAction } from './chunk-
|
|
21
|
+
export { RedirectError, redirect as actionRedirect, cookies, executeAction, executeFormAction, getAction, handleActionRequest, isRedirectError, parseFormData, registerAction } from './chunk-XGP3C2ZE.js';
|
|
22
22
|
export { createRouteContext, error, json, parseBody, redirect } from './chunk-W6D62JCI.js';
|
|
23
23
|
export { createLazyContent, createStreamingResponse, createStreamingSSR, renderWithStreaming, streamParallel, streamSequential } from './chunk-RSVA2EYO.js';
|
|
24
24
|
export { DEFAULT_BOT_PATTERNS, addStreamingHeaders, createConditionalStreamer, createStreamingResponse as createConditionalStreamingResponse, createStaticResponse, isBot, isSlowConnection, prefersNoStream, streamIf, supportsStreaming } from './chunk-XOIYNY4I.js';
|
package/dist/plugins/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { serverBoundaryPlugin } from '../chunk-
|
|
2
|
-
export { serverBoundaryPlugin } from '../chunk-
|
|
1
|
+
import { serverBoundaryPlugin } from '../chunk-NU3HX5T7.js';
|
|
2
|
+
export { serverBoundaryPlugin } from '../chunk-NU3HX5T7.js';
|
|
3
3
|
import { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
|
|
4
4
|
export { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
|
|
5
5
|
|
|
@@ -6,21 +6,9 @@ import { Plugin } from 'vite';
|
|
|
6
6
|
* Vite plugin to detect server-only code imported in client bundles.
|
|
7
7
|
* OPTIONAL - use if you want build-time protection.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - Configurable behavior (warn, error)
|
|
13
|
-
* - Clear error messages with solutions
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* // vite.config.ts
|
|
18
|
-
* import { serverBoundaryPlugin } from '@flight-framework/core/plugins';
|
|
19
|
-
*
|
|
20
|
-
* export default {
|
|
21
|
-
* plugins: [serverBoundaryPlugin()],
|
|
22
|
-
* };
|
|
23
|
-
* ```
|
|
9
|
+
* NOTE: This plugin is designed to work WITH serverActionsPlugin.
|
|
10
|
+
* It will NOT flag 'use server' files because those are handled
|
|
11
|
+
* by the Server Actions transformation.
|
|
24
12
|
*/
|
|
25
13
|
|
|
26
14
|
interface ServerBoundaryPluginOptions {
|
|
@@ -31,14 +19,14 @@ interface ServerBoundaryPluginOptions {
|
|
|
31
19
|
serverFilePatterns?: string[];
|
|
32
20
|
/**
|
|
33
21
|
* Directory patterns that are server-only.
|
|
34
|
-
* @default ['/server/'
|
|
22
|
+
* @default ['/server/']
|
|
35
23
|
*/
|
|
36
24
|
serverDirPatterns?: string[];
|
|
37
25
|
/**
|
|
38
26
|
* How to handle violations.
|
|
39
27
|
* - 'error': Build error (recommended for production)
|
|
40
28
|
* - 'warn': Warning only (for migration)
|
|
41
|
-
* @default '
|
|
29
|
+
* @default 'warn'
|
|
42
30
|
*/
|
|
43
31
|
violationBehavior?: 'error' | 'warn';
|
|
44
32
|
/**
|
|
@@ -46,21 +34,17 @@ interface ServerBoundaryPluginOptions {
|
|
|
46
34
|
*/
|
|
47
35
|
customErrorMessage?: (module: string, importer: string) => string;
|
|
48
36
|
/**
|
|
49
|
-
* Files to exclude from checking
|
|
50
|
-
* @default ['**\/*.test.*', '**\/*.spec.*']
|
|
37
|
+
* Files to exclude from checking.
|
|
51
38
|
*/
|
|
52
39
|
exclude?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Skip checking 'use server' files. These are handled by serverActionsPlugin.
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
skipServerActions?: boolean;
|
|
53
45
|
}
|
|
54
46
|
/**
|
|
55
47
|
* Vite plugin to detect server-only imports in client code.
|
|
56
|
-
*
|
|
57
|
-
* This plugin is OPTIONAL. Use it if you want build-time
|
|
58
|
-
* detection of server code leaking to the client.
|
|
59
|
-
*
|
|
60
|
-
* By default, it will:
|
|
61
|
-
* - Block imports of *.server.ts files in client code
|
|
62
|
-
* - Block imports from /server/ and /api/ directories
|
|
63
|
-
* - Throw build errors with clear solutions
|
|
64
48
|
*/
|
|
65
49
|
declare function serverBoundaryPlugin(options?: ServerBoundaryPluginOptions): Plugin;
|
|
66
50
|
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/actions/middleware.ts","../src/actions/streaming.ts","../src/actions/queue.ts","../src/actions/index.ts"],"names":[],"mappings":"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","file":"chunk-3QP3E7HS.js","sourcesContent":["/**\r\n * @flight-framework/core - Action Middleware\r\n * \r\n * Agnostic middleware system for Server Actions.\r\n * Flight provides the PRIMITIVES, you build YOUR solution.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Create your own auth middleware (Flight doesn't impose any auth provider)\r\n * const withAuth = createActionMiddleware(async (ctx, next) => {\r\n * const session = await yourAuthProvider.getSession(ctx.headers);\r\n * if (!session) {\r\n * return { success: false, error: 'UNAUTHORIZED' };\r\n * }\r\n * ctx.set('session', session);\r\n * return next();\r\n * });\r\n * \r\n * // Create your own rate limiter (Flight doesn't impose any rate limit provider)\r\n * const withRateLimit = createActionMiddleware(async (ctx, next) => {\r\n * const allowed = await yourRateLimiter.check(ctx.get('session').userId);\r\n * if (!allowed) {\r\n * return { success: false, error: 'RATE_LIMITED' };\r\n * }\r\n * return next();\r\n * });\r\n * \r\n * // Compose them\r\n * const protectedAction = pipeline(withAuth, withRateLimit)(myAction);\r\n * ```\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Action context - holds request data and middleware-set values\r\n */\r\nexport interface ActionContext {\r\n /** Original request (if available) */\r\n readonly request?: Request;\r\n /** Request headers */\r\n readonly headers: Headers;\r\n /** Action ID being executed */\r\n readonly actionId: string;\r\n /** Action arguments */\r\n readonly args: unknown[];\r\n /** Abort signal for cancellation */\r\n readonly signal?: AbortSignal;\r\n\r\n /** Get a value set by previous middleware */\r\n get<T = unknown>(key: string): T | undefined;\r\n /** Set a value for subsequent middleware/action */\r\n set<T = unknown>(key: string, value: T): void;\r\n}\r\n\r\n/**\r\n * Action result following Flight conventions\r\n */\r\nexport interface ActionResult<T = unknown> {\r\n success: boolean;\r\n data?: T;\r\n error?: string;\r\n code?: string;\r\n}\r\n\r\n/**\r\n * Next function to call the next middleware or action\r\n */\r\nexport type ActionNext<T = unknown> = () => Promise<ActionResult<T>>;\r\n\r\n/**\r\n * Middleware handler function\r\n */\r\nexport type ActionMiddlewareHandler<TContext extends ActionContext = ActionContext> = (\r\n ctx: TContext,\r\n next: ActionNext\r\n) => Promise<ActionResult> | ActionResult;\r\n\r\n/**\r\n * A middleware instance\r\n */\r\nexport interface ActionMiddleware {\r\n /** Unique name for debugging */\r\n readonly name: string;\r\n /** The handler function */\r\n readonly handler: ActionMiddlewareHandler;\r\n}\r\n\r\n/**\r\n * An action function\r\n */\r\nexport type Action<TInput = unknown, TOutput = unknown> = (\r\n ...args: TInput extends unknown[] ? TInput : [TInput]\r\n) => Promise<ActionResult<TOutput>>;\r\n\r\n/**\r\n * Options for creating middleware\r\n */\r\nexport interface CreateMiddlewareOptions {\r\n /** Name for debugging/logging */\r\n name?: string;\r\n}\r\n\r\n// ============================================================================\r\n// Action Context Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * Create an action context from request or minimal data\r\n */\r\nexport function createActionContext(options: {\r\n request?: Request;\r\n headers?: Headers;\r\n actionId: string;\r\n args: unknown[];\r\n signal?: AbortSignal;\r\n}): ActionContext {\r\n const store = new Map<string, unknown>();\r\n\r\n return {\r\n request: options.request,\r\n headers: options.headers ?? options.request?.headers ?? new Headers(),\r\n actionId: options.actionId,\r\n args: options.args,\r\n signal: options.signal,\r\n\r\n get<T = unknown>(key: string): T | undefined {\r\n return store.get(key) as T | undefined;\r\n },\r\n\r\n set<T = unknown>(key: string, value: T): void {\r\n store.set(key, value);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Middleware Creation\r\n// ============================================================================\r\n\r\nlet middlewareCounter = 0;\r\n\r\n/**\r\n * Create a reusable action middleware.\r\n * \r\n * Flight provides this PRIMITIVE - you define WHAT the middleware does.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Authentication middleware (you choose the auth provider)\r\n * const withAuth = createActionMiddleware(async (ctx, next) => {\r\n * const token = ctx.headers.get('Authorization');\r\n * const user = await myAuthLib.verify(token); // YOUR auth library\r\n * \r\n * if (!user) {\r\n * return { success: false, error: 'Unauthorized', code: 'AUTH_ERROR' };\r\n * }\r\n * \r\n * ctx.set('user', user);\r\n * return next();\r\n * });\r\n * \r\n * // Validation middleware (you choose the validator)\r\n * const withValidation = (schema: ZodSchema) => createActionMiddleware(\r\n * async (ctx, next) => {\r\n * const result = schema.safeParse(ctx.args[0]);\r\n * if (!result.success) {\r\n * return { success: false, error: 'Validation failed', code: 'VALIDATION_ERROR' };\r\n * }\r\n * return next();\r\n * },\r\n * { name: 'validation' }\r\n * );\r\n * ```\r\n */\r\nexport function createActionMiddleware(\r\n handler: ActionMiddlewareHandler,\r\n options: CreateMiddlewareOptions = {}\r\n): ActionMiddleware {\r\n const name = options.name ?? `middleware_${++middlewareCounter}`;\r\n\r\n return {\r\n name,\r\n handler,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Pipeline Composition\r\n// ============================================================================\r\n\r\n/**\r\n * Compose multiple middleware into a pipeline that wraps an action.\r\n * \r\n * Middleware executes in order: first middleware runs first.\r\n * Each middleware can:\r\n * - Short-circuit by returning a result without calling next()\r\n * - Transform context for subsequent middleware\r\n * - Wrap the next() call for timing/logging\r\n * \r\n * @example\r\n * ```typescript\r\n * const protectedAction = pipeline(\r\n * withAuth,\r\n * withRateLimit,\r\n * withValidation(UserSchema),\r\n * )(createUserAction);\r\n * \r\n * // Now protectedAction has auth, rate-limit, and validation\r\n * const result = await protectedAction(userData);\r\n * ```\r\n */\r\nexport function pipeline<TInput, TOutput>(\r\n ...middlewares: ActionMiddleware[]\r\n): (action: Action<TInput, TOutput>) => Action<TInput, TOutput> {\r\n return (action: Action<TInput, TOutput>): Action<TInput, TOutput> => {\r\n return async (...args: TInput extends unknown[] ? TInput : [TInput]): Promise<ActionResult<TOutput>> => {\r\n // Create context for this execution\r\n const ctx = createActionContext({\r\n actionId: action.name || 'anonymous',\r\n args: args as unknown[],\r\n });\r\n\r\n // Build the middleware chain\r\n let index = -1;\r\n\r\n const dispatch = async (i: number): Promise<ActionResult<TOutput>> => {\r\n if (i <= index) {\r\n throw new Error('next() called multiple times');\r\n }\r\n index = i;\r\n\r\n if (i < middlewares.length) {\r\n // Execute middleware\r\n const middleware = middlewares[i]!;\r\n return middleware.handler(ctx, () => dispatch(i + 1)) as Promise<ActionResult<TOutput>>;\r\n } else {\r\n // Execute the actual action\r\n return action(...args);\r\n }\r\n };\r\n\r\n return dispatch(0);\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Execute an action with middleware, providing custom context.\r\n * \r\n * Use this when you need to provide request context (headers, etc.)\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await executeWithMiddleware(\r\n * myAction,\r\n * [arg1, arg2],\r\n * [withAuth, withRateLimit],\r\n * { request: incomingRequest }\r\n * );\r\n * ```\r\n */\r\nexport async function executeWithMiddleware<TInput extends unknown[], TOutput>(\r\n action: (...args: TInput) => Promise<ActionResult<TOutput>>,\r\n args: TInput,\r\n middlewares: ActionMiddleware[],\r\n options: {\r\n request?: Request;\r\n headers?: Headers;\r\n signal?: AbortSignal;\r\n } = {}\r\n): Promise<ActionResult<TOutput>> {\r\n // Create context with request info\r\n const ctx = createActionContext({\r\n request: options.request,\r\n headers: options.headers,\r\n actionId: action.name || 'anonymous',\r\n args: args as unknown[],\r\n signal: options.signal,\r\n });\r\n\r\n // Build the middleware chain\r\n let index = -1;\r\n\r\n const dispatch = async (i: number): Promise<ActionResult<TOutput>> => {\r\n // Check for abort\r\n if (options.signal?.aborted) {\r\n return { success: false, error: 'Aborted', code: 'ABORTED' };\r\n }\r\n\r\n if (i <= index) {\r\n throw new Error('next() called multiple times');\r\n }\r\n index = i;\r\n\r\n if (i < middlewares.length) {\r\n const middleware = middlewares[i]!;\r\n return middleware.handler(ctx, () => dispatch(i + 1)) as Promise<ActionResult<TOutput>>;\r\n } else {\r\n return action(...args);\r\n }\r\n };\r\n\r\n return dispatch(0);\r\n}\r\n\r\n// ============================================================================\r\n// Utility Middleware Factories\r\n// ============================================================================\r\n\r\n/**\r\n * Create a timing middleware for observability.\r\n * \r\n * You provide the reporter - Flight doesn't impose any observability provider.\r\n * \r\n * @example\r\n * ```typescript\r\n * const withTiming = createTimingMiddleware((actionId, durationMs) => {\r\n * myMetricsService.histogram('action.duration', durationMs, { actionId });\r\n * });\r\n * ```\r\n */\r\nexport function createTimingMiddleware(\r\n reporter: (actionId: string, durationMs: number, result: ActionResult) => void\r\n): ActionMiddleware {\r\n return createActionMiddleware(\r\n async (ctx, next) => {\r\n const start = performance.now();\r\n const result = await next();\r\n const duration = performance.now() - start;\r\n reporter(ctx.actionId, duration, result);\r\n return result;\r\n },\r\n { name: 'timing' }\r\n );\r\n}\r\n\r\n/**\r\n * Create a logging middleware.\r\n * \r\n * You provide the logger - Flight doesn't impose any logging library.\r\n * \r\n * @example\r\n * ```typescript\r\n * const withLogging = createLoggingMiddleware({\r\n * onStart: (ctx) => console.log(`[${ctx.actionId}] Starting...`),\r\n * onComplete: (ctx, result, ms) => console.log(`[${ctx.actionId}] ${result.success ? 'OK' : 'FAIL'} in ${ms}ms`),\r\n * });\r\n * ```\r\n */\r\nexport function createLoggingMiddleware(options: {\r\n onStart?: (ctx: ActionContext) => void;\r\n onComplete?: (ctx: ActionContext, result: ActionResult, durationMs: number) => void;\r\n onError?: (ctx: ActionContext, error: Error) => void;\r\n}): ActionMiddleware {\r\n return createActionMiddleware(\r\n async (ctx, next) => {\r\n options.onStart?.(ctx);\r\n const start = performance.now();\r\n\r\n try {\r\n const result = await next();\r\n const duration = performance.now() - start;\r\n options.onComplete?.(ctx, result, duration);\r\n return result;\r\n } catch (error) {\r\n options.onError?.(ctx, error as Error);\r\n throw error;\r\n }\r\n },\r\n { name: 'logging' }\r\n );\r\n}\r\n\r\n/**\r\n * Create a retry middleware.\r\n * \r\n * @example\r\n * ```typescript\r\n * const withRetry = createRetryMiddleware({\r\n * maxAttempts: 3,\r\n * delay: (attempt) => Math.pow(2, attempt) * 100, // Exponential backoff\r\n * shouldRetry: (result) => result.code === 'TEMPORARY_ERROR',\r\n * });\r\n * ```\r\n */\r\nexport function createRetryMiddleware(options: {\r\n maxAttempts: number;\r\n delay?: (attempt: number) => number;\r\n shouldRetry?: (result: ActionResult) => boolean;\r\n}): ActionMiddleware {\r\n const {\r\n maxAttempts,\r\n delay = () => 0,\r\n shouldRetry = (result) => !result.success,\r\n } = options;\r\n\r\n return createActionMiddleware(\r\n async (ctx, next) => {\r\n let lastResult: ActionResult = { success: false, error: 'No attempts made' };\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (attempt > 0) {\r\n const delayMs = delay(attempt);\r\n if (delayMs > 0) {\r\n await new Promise(resolve => setTimeout(resolve, delayMs));\r\n }\r\n }\r\n\r\n lastResult = await next();\r\n\r\n if (!shouldRetry(lastResult)) {\r\n return lastResult;\r\n }\r\n }\r\n\r\n return lastResult;\r\n },\r\n { name: 'retry' }\r\n );\r\n}\r\n","/**\r\n * @flight-framework/core - Action Streaming\r\n * \r\n * Streamable actions using async generators.\r\n * Flight provides the PRIMITIVES, you choose the transport.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Create a streamable action for long-running operations\r\n * const generateReport = createStreamableAction(async function* (params: ReportParams) {\r\n * yield { type: 'progress', message: 'Fetching data...', progress: 0 };\r\n * const data = await fetchData(params);\r\n * \r\n * yield { type: 'progress', message: 'Processing...', progress: 33 };\r\n * const processed = await processData(data);\r\n * \r\n * yield { type: 'progress', message: 'Generating PDF...', progress: 66 };\r\n * const pdf = await generatePDF(processed);\r\n * \r\n * yield { type: 'progress', message: 'Complete!', progress: 100 };\r\n * return { success: true, data: pdf };\r\n * });\r\n * \r\n * // Client consumption\r\n * for await (const update of generateReport(params)) {\r\n * if (update.type === 'progress') {\r\n * setProgress(update.progress);\r\n * } else if (update.type === 'result') {\r\n * handleResult(update.data);\r\n * }\r\n * }\r\n * ```\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Progress update yielded during streaming\r\n */\r\nexport interface StreamProgress<TYield = unknown> {\r\n type: 'progress';\r\n data: TYield;\r\n}\r\n\r\n/**\r\n * Final result of a streaming action\r\n */\r\nexport interface StreamResult<TReturn = unknown> {\r\n type: 'result';\r\n success: boolean;\r\n data?: TReturn;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Union type for stream items\r\n */\r\nexport type StreamItem<TYield, TReturn> = StreamProgress<TYield> | StreamResult<TReturn>;\r\n\r\n/**\r\n * Streamable action generator function\r\n */\r\nexport type StreamableGenerator<TInput, TYield, TReturn> = (\r\n input: TInput,\r\n signal?: AbortSignal\r\n) => AsyncGenerator<TYield, TReturn>;\r\n\r\n/**\r\n * Options for creating a streamable action\r\n */\r\nexport interface StreamableActionOptions {\r\n /** Name for debugging */\r\n name?: string;\r\n /** Timeout in milliseconds */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Controller for a running stream\r\n */\r\nexport interface StreamController<TYield, TReturn> {\r\n /** Async iterator for consuming the stream */\r\n [Symbol.asyncIterator](): AsyncIterator<StreamItem<TYield, TReturn>>;\r\n /** Abort the stream */\r\n abort(): void;\r\n /** Promise that resolves when stream completes */\r\n done: Promise<StreamResult<TReturn>>;\r\n}\r\n\r\n/**\r\n * A streamable action function\r\n */\r\nexport type StreamableAction<TInput, TYield, TReturn> = (\r\n input: TInput\r\n) => StreamController<TYield, TReturn>;\r\n\r\n// ============================================================================\r\n// Streamable Action Creation\r\n// ============================================================================\r\n\r\n/**\r\n * Create a streamable action from an async generator.\r\n * \r\n * Flight provides this PRIMITIVE - you define the generator logic\r\n * and choose how to transport the stream (HTTP, WebSocket, etc.)\r\n * \r\n * @example\r\n * ```typescript\r\n * // AI streaming response\r\n * const streamChat = createStreamableAction(async function* (message: string) {\r\n * const stream = await openai.chat.completions.create({\r\n * model: 'gpt-4',\r\n * messages: [{ role: 'user', content: message }],\r\n * stream: true,\r\n * });\r\n * \r\n * let fullResponse = '';\r\n * for await (const chunk of stream) {\r\n * const text = chunk.choices[0]?.delta?.content || '';\r\n * fullResponse += text;\r\n * yield { text, partial: true };\r\n * }\r\n * \r\n * return { text: fullResponse, partial: false };\r\n * });\r\n * ```\r\n */\r\nexport function createStreamableAction<TInput, TYield, TReturn>(\r\n generator: StreamableGenerator<TInput, TYield, TReturn>,\r\n options: StreamableActionOptions = {}\r\n): StreamableAction<TInput, TYield, TReturn> {\r\n const actionName = options.name ?? generator.name ?? 'streamable_action';\r\n\r\n return (input: TInput): StreamController<TYield, TReturn> => {\r\n const abortController = new AbortController();\r\n let completed = false;\r\n let finalResult: StreamResult<TReturn> | null = null;\r\n\r\n // Create done promise\r\n let resolveDone: (result: StreamResult<TReturn>) => void;\r\n const done = new Promise<StreamResult<TReturn>>((resolve) => {\r\n resolveDone = resolve;\r\n });\r\n\r\n // Setup timeout if specified\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\r\n if (options.timeout) {\r\n timeoutId = setTimeout(() => {\r\n abortController.abort();\r\n }, options.timeout);\r\n }\r\n\r\n // Create the async iterator\r\n async function* iterate(): AsyncGenerator<StreamItem<TYield, TReturn>> {\r\n try {\r\n const gen = generator(input, abortController.signal);\r\n\r\n while (true) {\r\n if (abortController.signal.aborted) {\r\n const abortResult: StreamResult<TReturn> = {\r\n type: 'result',\r\n success: false,\r\n error: 'Stream aborted',\r\n };\r\n finalResult = abortResult;\r\n resolveDone!(abortResult);\r\n yield abortResult;\r\n return;\r\n }\r\n\r\n const next = await gen.next();\r\n\r\n if (next.done) {\r\n // Generator returned - this is the final value\r\n const successResult: StreamResult<TReturn> = {\r\n type: 'result',\r\n success: true,\r\n data: next.value,\r\n };\r\n finalResult = successResult;\r\n completed = true;\r\n resolveDone!(successResult);\r\n yield successResult;\r\n return;\r\n } else {\r\n // Generator yielded - this is a progress update\r\n yield {\r\n type: 'progress',\r\n data: next.value,\r\n };\r\n }\r\n }\r\n } catch (error) {\r\n const errorResult: StreamResult<TReturn> = {\r\n type: 'result',\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n finalResult = errorResult;\r\n resolveDone!(errorResult);\r\n yield errorResult;\r\n } finally {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n }\r\n }\r\n\r\n const iterator = iterate();\r\n\r\n return {\r\n [Symbol.asyncIterator]() {\r\n return iterator;\r\n },\r\n abort() {\r\n abortController.abort();\r\n },\r\n done,\r\n };\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// HTTP Transport Adapter\r\n// ============================================================================\r\n\r\n/**\r\n * Convert a streamable action result to an HTTP streaming response.\r\n * \r\n * This is ONE transport option - you can create others (WebSocket, SSE, etc.)\r\n * \r\n * @example\r\n * ```typescript\r\n * // In your API route\r\n * export async function POST(request: Request) {\r\n * const body = await request.json();\r\n * const stream = generateReport(body);\r\n * return streamToResponse(stream);\r\n * }\r\n * ```\r\n */\r\nexport function streamToResponse<TYield, TReturn>(\r\n controller: StreamController<TYield, TReturn>,\r\n options: {\r\n headers?: Record<string, string>;\r\n } = {}\r\n): Response {\r\n const encoder = new TextEncoder();\r\n\r\n const stream = new ReadableStream({\r\n async start(streamController) {\r\n try {\r\n for await (const item of controller) {\r\n const chunk = JSON.stringify(item) + '\\n';\r\n streamController.enqueue(encoder.encode(chunk));\r\n\r\n if (item.type === 'result') {\r\n break;\r\n }\r\n }\r\n } catch (error) {\r\n const errorChunk = JSON.stringify({\r\n type: 'result',\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Stream error',\r\n }) + '\\n';\r\n streamController.enqueue(encoder.encode(errorChunk));\r\n } finally {\r\n streamController.close();\r\n }\r\n },\r\n cancel() {\r\n controller.abort();\r\n },\r\n });\r\n\r\n return new Response(stream, {\r\n status: 200,\r\n headers: {\r\n 'Content-Type': 'application/x-ndjson',\r\n 'Transfer-Encoding': 'chunked',\r\n 'Cache-Control': 'no-cache',\r\n 'Connection': 'keep-alive',\r\n ...options.headers,\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Parse an HTTP streaming response back to a stream controller (client-side).\r\n * \r\n * @example\r\n * ```typescript\r\n * // Client-side consumption\r\n * const response = await fetch('/api/generate-report', {\r\n * method: 'POST',\r\n * body: JSON.stringify(params),\r\n * });\r\n * \r\n * const stream = responseToStream<Progress, Report>(response);\r\n * \r\n * for await (const item of stream) {\r\n * if (item.type === 'progress') {\r\n * setProgress(item.data);\r\n * } else {\r\n * setReport(item.data);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function responseToStream<TYield, TReturn>(\r\n response: Response\r\n): AsyncGenerator<StreamItem<TYield, TReturn>> {\r\n const reader = response.body?.getReader();\r\n const decoder = new TextDecoder();\r\n\r\n if (!reader) {\r\n throw new Error('Response body is not readable');\r\n }\r\n\r\n return (async function* () {\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n\r\n if (done) {\r\n break;\r\n }\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // Process complete lines\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() || ''; // Keep incomplete line in buffer\r\n\r\n for (const line of lines) {\r\n if (line.trim()) {\r\n try {\r\n const item = JSON.parse(line) as StreamItem<TYield, TReturn>;\r\n yield item;\r\n } catch {\r\n // Skip malformed JSON\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Process remaining buffer\r\n if (buffer.trim()) {\r\n try {\r\n const item = JSON.parse(buffer) as StreamItem<TYield, TReturn>;\r\n yield item;\r\n } catch {\r\n // Skip malformed JSON\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n })();\r\n}\r\n\r\n// ============================================================================\r\n// Utility Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Collect all items from a stream into an array.\r\n * \r\n * Useful for testing or when you want to wait for completion.\r\n */\r\nexport async function collectStream<TYield, TReturn>(\r\n controller: StreamController<TYield, TReturn>\r\n): Promise<{ items: StreamItem<TYield, TReturn>[]; result: StreamResult<TReturn> }> {\r\n const items: StreamItem<TYield, TReturn>[] = [];\r\n let result: StreamResult<TReturn> | null = null;\r\n\r\n for await (const item of controller) {\r\n items.push(item);\r\n if (item.type === 'result') {\r\n result = item;\r\n }\r\n }\r\n\r\n if (!result) {\r\n result = { type: 'result', success: false, error: 'No result received' };\r\n }\r\n\r\n return { items, result };\r\n}\r\n\r\n/**\r\n * Create a simple progress reporter for streams.\r\n * \r\n * @example\r\n * ```typescript\r\n * const onProgress = createProgressReporter<MyProgress>((data) => {\r\n * console.log(`Progress: ${data.percent}%`);\r\n * });\r\n * \r\n * for await (const item of myStream) {\r\n * onProgress(item);\r\n * }\r\n * ```\r\n */\r\nexport function createProgressReporter<TYield, TReturn = unknown>(\r\n onProgress: (data: TYield) => void,\r\n onComplete?: (result: StreamResult<TReturn>) => void\r\n): (item: StreamItem<TYield, TReturn>) => void {\r\n return (item: StreamItem<TYield, TReturn>) => {\r\n if (item.type === 'progress') {\r\n onProgress(item.data);\r\n } else {\r\n onComplete?.(item);\r\n }\r\n };\r\n}\r\n","/**\r\n * @flight-framework/core - Action Queue\r\n * \r\n * Offline-first action queuing with pluggable storage.\r\n * Flight provides the PRIMITIVES and INTERFACE, you choose the storage.\r\n * \r\n * @example\r\n * ```typescript\r\n * // 1. Use a storage adapter (install separately or create your own)\r\n * import { indexedDBAdapter } from '@flight-framework/queue-indexeddb';\r\n * // OR create your own:\r\n * const myAdapter: QueueStorageAdapter = { ... };\r\n * \r\n * // 2. Create a queued action\r\n * const saveNote = createQueuedAction(\r\n * async (note: Note) => {\r\n * await api.saveNote(note);\r\n * return { success: true };\r\n * },\r\n * {\r\n * storage: indexedDBAdapter({ dbName: 'myapp' }),\r\n * retryStrategy: exponentialBackoff({ maxAttempts: 5 }),\r\n * onStatusChange: (status) => console.log('Queue status:', status),\r\n * }\r\n * );\r\n * \r\n * // 3. Use it - works offline!\r\n * await saveNote({ title: 'My Note', content: '...' });\r\n * // If offline: queued and synced later\r\n * // If online: executed immediately\r\n * ```\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * A queued action entry\r\n */\r\nexport interface QueuedActionEntry<TInput = unknown> {\r\n /** Unique ID for this entry */\r\n id: string;\r\n /** Action identifier */\r\n actionId: string;\r\n /** Action arguments */\r\n input: TInput;\r\n /** When the action was queued */\r\n queuedAt: number;\r\n /** Number of execution attempts */\r\n attempts: number;\r\n /** Last error message if failed */\r\n lastError?: string;\r\n /** Status */\r\n status: 'pending' | 'processing' | 'failed';\r\n /** Optional metadata */\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Queue storage adapter interface.\r\n * \r\n * Flight does NOT provide storage implementations - you choose:\r\n * - @flight-framework/queue-indexeddb (browser)\r\n * - @flight-framework/queue-sqlite (mobile/desktop)\r\n * - @flight-framework/queue-memory (testing)\r\n * - Your own implementation\r\n */\r\nexport interface QueueStorageAdapter {\r\n /** Add an action to the queue */\r\n enqueue<TInput>(entry: QueuedActionEntry<TInput>): Promise<void>;\r\n\r\n /** Get and remove the next pending action */\r\n dequeue(): Promise<QueuedActionEntry | null>;\r\n\r\n /** Get all pending actions without removing */\r\n peek(): Promise<QueuedActionEntry[]>;\r\n\r\n /** Update an existing entry */\r\n update(id: string, updates: Partial<QueuedActionEntry>): Promise<void>;\r\n\r\n /** Remove an entry by ID */\r\n remove(id: string): Promise<void>;\r\n\r\n /** Clear all entries */\r\n clear(): Promise<void>;\r\n\r\n /** Get queue length */\r\n length(): Promise<number>;\r\n}\r\n\r\n/**\r\n * Retry strategy function\r\n */\r\nexport type RetryStrategy = (\r\n entry: QueuedActionEntry,\r\n error: Error\r\n) => { shouldRetry: boolean; delayMs: number };\r\n\r\n/**\r\n * Queue status for observability\r\n */\r\nexport interface QueueStatus {\r\n /** Whether the queue processor is running */\r\n isProcessing: boolean;\r\n /** Number of pending actions */\r\n pendingCount: number;\r\n /** Number of failed actions */\r\n failedCount: number;\r\n /** Whether online */\r\n isOnline: boolean;\r\n}\r\n\r\n/**\r\n * Options for creating a queued action\r\n */\r\nexport interface QueuedActionOptions {\r\n /** Storage adapter (required - Flight doesn't provide default) */\r\n storage: QueueStorageAdapter;\r\n /** Custom action ID */\r\n actionId?: string;\r\n /** Retry strategy */\r\n retryStrategy?: RetryStrategy;\r\n /** Check if online (default: navigator.onLine on browser) */\r\n isOnline?: () => boolean | Promise<boolean>;\r\n /** Called when queue status changes */\r\n onStatusChange?: (status: QueueStatus) => void;\r\n /** Called when an action is successfully processed */\r\n onSuccess?: (entry: QueuedActionEntry, result: unknown) => void;\r\n /** Called when an action fails permanently */\r\n onFailure?: (entry: QueuedActionEntry, error: Error) => void;\r\n}\r\n\r\n/**\r\n * Action result for queued actions\r\n */\r\nexport interface QueuedActionResult<TOutput = unknown> {\r\n /** Whether immediately executed or queued */\r\n queued: boolean;\r\n /** Queue entry ID if queued */\r\n entryId?: string;\r\n /** Result if immediately executed */\r\n result?: { success: boolean; data?: TOutput; error?: string };\r\n}\r\n\r\n/**\r\n * A queued action function\r\n */\r\nexport type QueuedAction<TInput, TOutput> = (\r\n input: TInput\r\n) => Promise<QueuedActionResult<TOutput>>;\r\n\r\n// ============================================================================\r\n// Queue Creation\r\n// ============================================================================\r\n\r\nlet entryCounter = 0;\r\n\r\nfunction generateEntryId(): string {\r\n return `${Date.now()}_${++entryCounter}_${Math.random().toString(36).substring(2, 9)}`;\r\n}\r\n\r\n/**\r\n * Create an offline-capable queued action.\r\n * \r\n * Flight provides this PRIMITIVE - you provide the storage adapter.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Create with your storage adapter\r\n * const syncData = createQueuedAction(\r\n * async (data: MyData) => {\r\n * await api.sync(data);\r\n * return { success: true };\r\n * },\r\n * {\r\n * storage: myStorageAdapter,\r\n * retryStrategy: exponentialBackoff(),\r\n * }\r\n * );\r\n * \r\n * // Use it - works offline automatically\r\n * const result = await syncData({ items: [...] });\r\n * \r\n * if (result.queued) {\r\n * console.log('Queued for later sync:', result.entryId);\r\n * } else {\r\n * console.log('Synced immediately:', result.result);\r\n * }\r\n * ```\r\n */\r\nexport function createQueuedAction<TInput, TOutput>(\r\n action: (input: TInput) => Promise<{ success: boolean; data?: TOutput; error?: string }>,\r\n options: QueuedActionOptions\r\n): QueuedAction<TInput, TOutput> {\r\n const {\r\n storage,\r\n actionId = action.name || `action_${Date.now()}`,\r\n retryStrategy = defaultRetryStrategy,\r\n isOnline = defaultIsOnline,\r\n onStatusChange,\r\n onSuccess,\r\n onFailure,\r\n } = options;\r\n\r\n // Queue processor state\r\n let isProcessing = false;\r\n let processorRunning = false;\r\n\r\n // Start background processor\r\n startProcessor();\r\n\r\n async function startProcessor() {\r\n if (processorRunning) return;\r\n processorRunning = true;\r\n\r\n // Process queue periodically\r\n while (processorRunning) {\r\n await processQueue();\r\n await sleep(1000); // Check every second\r\n }\r\n }\r\n\r\n async function processQueue() {\r\n // Check if online\r\n const online = await isOnline();\r\n if (!online) {\r\n return;\r\n }\r\n\r\n // Get next entry\r\n const entry = await storage.dequeue();\r\n if (!entry) {\r\n if (isProcessing) {\r\n isProcessing = false;\r\n await notifyStatus();\r\n }\r\n return;\r\n }\r\n\r\n isProcessing = true;\r\n await notifyStatus();\r\n\r\n // Update status to processing\r\n await storage.update(entry.id, { status: 'processing' });\r\n\r\n try {\r\n // Execute the action\r\n const result = await action(entry.input as TInput);\r\n\r\n // Success - remove from queue\r\n await storage.remove(entry.id);\r\n onSuccess?.(entry, result);\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Check retry strategy\r\n const { shouldRetry, delayMs } = retryStrategy(entry, err);\r\n\r\n if (shouldRetry) {\r\n // Re-queue with updated attempts\r\n await storage.update(entry.id, {\r\n status: 'pending',\r\n attempts: entry.attempts + 1,\r\n lastError: err.message,\r\n });\r\n\r\n // Wait before next attempt\r\n if (delayMs > 0) {\r\n await sleep(delayMs);\r\n }\r\n } else {\r\n // Mark as failed\r\n await storage.update(entry.id, {\r\n status: 'failed',\r\n lastError: err.message,\r\n });\r\n onFailure?.(entry, err);\r\n }\r\n }\r\n }\r\n\r\n async function notifyStatus() {\r\n if (!onStatusChange) return;\r\n\r\n const entries = await storage.peek();\r\n const status: QueueStatus = {\r\n isProcessing,\r\n pendingCount: entries.filter(e => e.status === 'pending').length,\r\n failedCount: entries.filter(e => e.status === 'failed').length,\r\n isOnline: await isOnline(),\r\n };\r\n onStatusChange(status);\r\n }\r\n\r\n // Return the queued action function\r\n return async (input: TInput): Promise<QueuedActionResult<TOutput>> => {\r\n const online = await isOnline();\r\n\r\n if (online) {\r\n // Try to execute immediately\r\n try {\r\n const result = await action(input);\r\n return { queued: false, result };\r\n } catch {\r\n // Fall through to queue\r\n }\r\n }\r\n\r\n // Queue for later\r\n const entry: QueuedActionEntry<TInput> = {\r\n id: generateEntryId(),\r\n actionId,\r\n input,\r\n queuedAt: Date.now(),\r\n attempts: 0,\r\n status: 'pending',\r\n };\r\n\r\n await storage.enqueue(entry);\r\n await notifyStatus();\r\n\r\n return { queued: true, entryId: entry.id };\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Built-in Retry Strategies\r\n// ============================================================================\r\n\r\n/**\r\n * Default retry strategy: 3 attempts with 1 second delay\r\n */\r\nexport const defaultRetryStrategy: RetryStrategy = (entry) => ({\r\n shouldRetry: entry.attempts < 3,\r\n delayMs: 1000,\r\n});\r\n\r\n/**\r\n * Create an exponential backoff retry strategy.\r\n * \r\n * @example\r\n * ```typescript\r\n * const retry = exponentialBackoff({\r\n * maxAttempts: 5,\r\n * baseDelayMs: 1000,\r\n * maxDelayMs: 30000,\r\n * });\r\n * ```\r\n */\r\nexport function exponentialBackoff(options: {\r\n maxAttempts?: number;\r\n baseDelayMs?: number;\r\n maxDelayMs?: number;\r\n} = {}): RetryStrategy {\r\n const {\r\n maxAttempts = 5,\r\n baseDelayMs = 1000,\r\n maxDelayMs = 30000,\r\n } = options;\r\n\r\n return (entry) => {\r\n const shouldRetry = entry.attempts < maxAttempts;\r\n const delayMs = Math.min(\r\n baseDelayMs * Math.pow(2, entry.attempts),\r\n maxDelayMs\r\n );\r\n\r\n return { shouldRetry, delayMs };\r\n };\r\n}\r\n\r\n/**\r\n * Create a fixed delay retry strategy.\r\n */\r\nexport function fixedDelay(options: {\r\n maxAttempts?: number;\r\n delayMs?: number;\r\n} = {}): RetryStrategy {\r\n const { maxAttempts = 3, delayMs = 1000 } = options;\r\n\r\n return (entry) => ({\r\n shouldRetry: entry.attempts < maxAttempts,\r\n delayMs,\r\n });\r\n}\r\n\r\n// ============================================================================\r\n// In-Memory Storage Adapter (for testing only)\r\n// ============================================================================\r\n\r\n/**\r\n * In-memory queue storage adapter.\r\n * \r\n * ⚠️ FOR TESTING ONLY - data is lost on page refresh.\r\n * \r\n * For production, use:\r\n * - @flight-framework/queue-indexeddb (browser)\r\n * - @flight-framework/queue-sqlite (native apps)\r\n * - Your own implementation\r\n */\r\nexport function createMemoryAdapter(): QueueStorageAdapter {\r\n const store = new Map<string, QueuedActionEntry>();\r\n\r\n return {\r\n async enqueue(entry) {\r\n store.set(entry.id, entry);\r\n },\r\n\r\n async dequeue() {\r\n for (const [id, entry] of store.entries()) {\r\n if (entry.status === 'pending') {\r\n store.delete(id);\r\n return entry;\r\n }\r\n }\r\n return null;\r\n },\r\n\r\n async peek() {\r\n return Array.from(store.values());\r\n },\r\n\r\n async update(id, updates) {\r\n const entry = store.get(id);\r\n if (entry) {\r\n store.set(id, { ...entry, ...updates });\r\n }\r\n },\r\n\r\n async remove(id) {\r\n store.delete(id);\r\n },\r\n\r\n async clear() {\r\n store.clear();\r\n },\r\n\r\n async length() {\r\n return store.size;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Utility Functions\r\n// ============================================================================\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\nfunction defaultIsOnline(): boolean {\r\n if (typeof navigator !== 'undefined' && 'onLine' in navigator) {\r\n return navigator.onLine;\r\n }\r\n // Assume online in non-browser environments\r\n return true;\r\n}\r\n\r\n/**\r\n * Create a queue manager to control multiple queued actions.\r\n * \r\n * @example\r\n * ```typescript\r\n * const queueManager = createQueueManager({\r\n * storage: myStorageAdapter,\r\n * });\r\n * \r\n * // Pause all processing\r\n * queueManager.pause();\r\n * \r\n * // Resume\r\n * queueManager.resume();\r\n * \r\n * // Get status\r\n * const status = await queueManager.getStatus();\r\n * ```\r\n */\r\nexport function createQueueManager(options: {\r\n storage: QueueStorageAdapter;\r\n}): {\r\n pause: () => void;\r\n resume: () => void;\r\n getStatus: () => Promise<QueueStatus>;\r\n clearFailed: () => Promise<void>;\r\n retryFailed: () => Promise<void>;\r\n} {\r\n let paused = false;\r\n\r\n return {\r\n pause() {\r\n paused = true;\r\n },\r\n\r\n resume() {\r\n paused = false;\r\n },\r\n\r\n async getStatus() {\r\n const entries = await options.storage.peek();\r\n return {\r\n isProcessing: !paused,\r\n pendingCount: entries.filter(e => e.status === 'pending').length,\r\n failedCount: entries.filter(e => e.status === 'failed').length,\r\n isOnline: defaultIsOnline(),\r\n };\r\n },\r\n\r\n async clearFailed() {\r\n const entries = await options.storage.peek();\r\n for (const entry of entries) {\r\n if (entry.status === 'failed') {\r\n await options.storage.remove(entry.id);\r\n }\r\n }\r\n },\r\n\r\n async retryFailed() {\r\n const entries = await options.storage.peek();\r\n for (const entry of entries) {\r\n if (entry.status === 'failed') {\r\n await options.storage.update(entry.id, {\r\n status: 'pending',\r\n attempts: 0,\r\n lastError: undefined,\r\n });\r\n }\r\n }\r\n },\r\n };\r\n}\r\n","/**\r\n * @flight-framework/core - Server Actions\r\n * \r\n * Implementation of React 19 style Server Actions.\r\n * Functions marked with 'use server' run on the server.\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Server action metadata\r\n */\r\nexport interface ServerAction {\r\n /** Unique action ID */\r\n id: string;\r\n /** Original function name */\r\n name: string;\r\n /** File path where action is defined */\r\n filePath: string;\r\n /** The actual action function */\r\n fn: (...args: unknown[]) => Promise<unknown>;\r\n}\r\n\r\n/**\r\n * Server action result\r\n */\r\nexport interface ActionResult<T = unknown> {\r\n success: boolean;\r\n data?: T;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Form action data\r\n */\r\nexport interface FormActionData {\r\n actionId: string;\r\n formData: FormData;\r\n}\r\n\r\n// ============================================================================\r\n// Action Registry\r\n// ============================================================================\r\n\r\nconst actionRegistry = new Map<string, ServerAction>();\r\n\r\n/**\r\n * Register a server action\r\n */\r\nexport function registerAction(action: ServerAction): void {\r\n actionRegistry.set(action.id, action);\r\n}\r\n\r\n/**\r\n * Get a registered action by ID\r\n */\r\nexport function getAction(id: string): ServerAction | undefined {\r\n return actionRegistry.get(id);\r\n}\r\n\r\n/**\r\n * Get all registered actions\r\n */\r\nexport function getAllActions(): ServerAction[] {\r\n return Array.from(actionRegistry.values());\r\n}\r\n\r\n/**\r\n * Clear all registered actions (useful for testing)\r\n */\r\nexport function clearActions(): void {\r\n actionRegistry.clear();\r\n}\r\n\r\n// ============================================================================\r\n// Action Execution\r\n// ============================================================================\r\n\r\n/**\r\n * Execute a server action\r\n */\r\nexport async function executeAction<T = unknown>(\r\n actionId: string,\r\n args: unknown[]\r\n): Promise<ActionResult<T>> {\r\n const action = getAction(actionId);\r\n\r\n if (!action) {\r\n return {\r\n success: false,\r\n error: `Action not found: ${actionId}`,\r\n };\r\n }\r\n\r\n try {\r\n const result = await action.fn(...args);\r\n return {\r\n success: true,\r\n data: result as T,\r\n };\r\n } catch (error) {\r\n // Re-throw RedirectError so handleActionRequest can return 303\r\n if (isRedirectError(error)) {\r\n throw error;\r\n }\r\n console.error(`[Flight] Action error (${actionId}):`, error);\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Execute a form action\r\n */\r\nexport async function executeFormAction<T = unknown>(\r\n actionId: string,\r\n formData: FormData\r\n): Promise<ActionResult<T>> {\r\n return executeAction<T>(actionId, [formData]);\r\n}\r\n\r\n// ============================================================================\r\n// Action ID Generation\r\n// ============================================================================\r\n\r\nlet actionCounter = 0;\r\n\r\n/**\r\n * Generate a unique action ID\r\n */\r\nexport function generateActionId(name: string, filePath: string): string {\r\n const hash = simpleHash(`${filePath}:${name}`);\r\n return `action_${hash}_${actionCounter++}`;\r\n}\r\n\r\n/**\r\n * Simple hash function for action IDs\r\n */\r\nfunction simpleHash(str: string): string {\r\n let hash = 0;\r\n for (let i = 0; i < str.length; i++) {\r\n const char = str.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash; // Convert to 32bit integer\r\n }\r\n return Math.abs(hash).toString(36);\r\n}\r\n\r\n// ============================================================================\r\n// Action Helpers (for use inside actions)\r\n// ============================================================================\r\n\r\n/**\r\n * Get cookies in server action context\r\n */\r\nexport function cookies(): {\r\n get: (name: string) => string | undefined;\r\n set: (name: string, value: string, options?: CookieOptions) => void;\r\n delete: (name: string) => void;\r\n} {\r\n // This will be populated by the runtime\r\n const cookieStore = (globalThis as any).__flightCookies;\r\n\r\n if (!cookieStore) {\r\n console.warn('[Flight] Cookies not available outside of action context');\r\n return {\r\n get: () => undefined,\r\n set: () => { },\r\n delete: () => { },\r\n };\r\n }\r\n\r\n return cookieStore;\r\n}\r\n\r\nexport interface CookieOptions {\r\n maxAge?: number;\r\n expires?: Date;\r\n path?: string;\r\n domain?: string;\r\n secure?: boolean;\r\n httpOnly?: boolean;\r\n sameSite?: 'strict' | 'lax' | 'none';\r\n}\r\n\r\n/**\r\n * Redirect in server action context\r\n */\r\nexport function redirect(url: string): never {\r\n throw new RedirectError(url);\r\n}\r\n\r\n/**\r\n * Special error for redirects\r\n */\r\nexport class RedirectError extends Error {\r\n public readonly url: string;\r\n\r\n constructor(url: string) {\r\n super(`Redirect to ${url}`);\r\n this.name = 'RedirectError';\r\n this.url = url;\r\n }\r\n}\r\n\r\n/**\r\n * Check if error is a redirect\r\n */\r\nexport function isRedirectError(error: unknown): error is RedirectError {\r\n return error instanceof RedirectError;\r\n}\r\n\r\n// ============================================================================\r\n// Form Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Parse form data to typed object\r\n */\r\nexport function parseFormData<T extends Record<string, string>>(\r\n formData: FormData\r\n): T {\r\n const result: Record<string, string> = {};\r\n\r\n formData.forEach((value, key) => {\r\n result[key] = String(value);\r\n });\r\n\r\n return result as T;\r\n}\r\n\r\n/**\r\n * Create action reference for form action attribute\r\n */\r\nexport function createActionReference(actionId: string): string {\r\n return `/__flight_action/${actionId}`;\r\n}\r\n\r\n// ============================================================================\r\n// Action Handler (for HTTP endpoint)\r\n// ============================================================================\r\n\r\n/**\r\n * Handle action request from client\r\n */\r\nexport async function handleActionRequest(\r\n request: Request\r\n): Promise<Response> {\r\n const url = new URL(request.url);\r\n const actionPath = url.pathname;\r\n\r\n // Extract action ID from path: /__flight_action/{actionId}\r\n const match = actionPath.match(/^\\/__flight_action\\/(.+)$/);\r\n\r\n if (!match) {\r\n return new Response(JSON.stringify({ error: 'Invalid action path' }), {\r\n status: 400,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n }\r\n\r\n const actionId = match[1];\r\n\r\n if (!actionId) {\r\n return new Response(JSON.stringify({ error: 'Missing action ID' }), {\r\n status: 400,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n }\r\n\r\n try {\r\n let result: ActionResult;\r\n\r\n // Check content type for form vs JSON\r\n const contentType = request.headers.get('content-type') || '';\r\n\r\n if (contentType.includes('application/x-www-form-urlencoded') ||\r\n contentType.includes('multipart/form-data')) {\r\n const formData = await request.formData();\r\n result = await executeFormAction(actionId, formData);\r\n } else {\r\n const args = await request.json();\r\n result = await executeAction(actionId, Array.isArray(args) ? args : [args]);\r\n }\r\n\r\n return new Response(JSON.stringify(result), {\r\n status: result.success ? 200 : 400,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n } catch (error) {\r\n if (isRedirectError(error)) {\r\n return new Response(null, {\r\n status: 303,\r\n headers: { Location: error.url },\r\n });\r\n }\r\n\r\n return new Response(JSON.stringify({\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n }), {\r\n status: 500,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Re-export New Modules\r\n// ============================================================================\r\n\r\n// Action Middleware - composable middleware for actions\r\nexport * from './middleware.js';\r\n\r\n// Action Streaming - async generator-based streaming actions\r\nexport * from './streaming.js';\r\n\r\n// Action Queue - offline-first action queuing\r\nexport * from './queue.js';\r\n\r\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins/server-boundary-plugin.ts"],"names":["options"],"mappings":";AA6EO,SAAS,oBAAA,CACZ,OAAA,GAAuC,EAAC,EAClC;AACN,EAAA,MAAM;AAAA,IACF,kBAAA,GAAqB,CAAC,YAAA,EAAc,aAAA,EAAe,cAAc,aAAa,CAAA;AAAA,IAC9E,iBAAA,GAAoB,CAAC,UAAA,EAAY,OAAO,CAAA;AAAA,IACxC,iBAAA,GAAoB,OAAA;AAAA,IACpB,kBAAA;AAAA,IACA,OAAA,GAAU,CAAC,aAAA,EAAe,aAAA,EAAe,oBAAoB;AAAA,GACjE,GAAI,OAAA;AAGJ,EAAA,MAAM,eAAe,kBAAA,CAAmB,GAAA;AAAA,IAAI,CAAA,CAAA,KACxC,IAAI,MAAA,CAAO,CAAA,CAAE,QAAQ,KAAA,EAAO,KAAK,CAAA,GAAI,GAAA,EAAK,GAAG;AAAA,GACjD;AACA,EAAA,MAAM,cAAc,iBAAA,CAAkB,GAAA;AAAA,IAAI,CAAA,CAAA,KACtC,IAAI,MAAA,CAAO,CAAA,CAAE,QAAQ,KAAA,EAAO,SAAS,GAAG,GAAG;AAAA,GAC/C;AAEA,EAAA,SAAS,mBAAmB,EAAA,EAAqB;AAE7C,IAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAChC,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AAAA,IACjC;AAGA,IAAA,KAAA,MAAW,WAAW,WAAA,EAAa;AAC/B,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AAAA,IACjC;AAEA,IAAA,OAAO,KAAA;AAAA,EACX;AAEA,EAAA,SAAS,WAAW,EAAA,EAAqB;AACrC,IAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAE3B,MAAA,MAAM,QAAQ,IAAI,MAAA;AAAA,QACd,OAAA,CACK,OAAA,CAAQ,OAAA,EAAS,IAAI,CAAA,CACrB,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA,CAC1B,OAAA,CAAQ,KAAA,EAAO,KAAK;AAAA,OAC7B;AACA,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AAAA,IAC/B;AACA,IAAA,OAAO,KAAA;AAAA,EACX;AAEA,EAAA,SAAS,kBAAA,CAAmB,QAAgB,QAAA,EAA0B;AAClE,IAAA,IAAI,kBAAA,EAAoB;AACpB,MAAA,OAAO,kBAAA,CAAmB,QAAQ,QAAQ,CAAA;AAAA,IAC9C;AAEA,IAAA,OACI,CAAA;;AAAA,UAAA,EACa,MAAM;AAAA,eAAA,EACD,QAAQ;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,sEAAA,CAAA;AAAA,EAQlC;AAEA,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,wBAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IAET,SAAA,CAAU,MAAA,EAAQ,QAAA,EAAUA,QAAAA,EAAS;AAEjC,MAAA,IAAIA,QAAAA,EAAS,KAAK,OAAO,IAAA;AAGzB,MAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAGtB,MAAA,IAAI,UAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,IAAA;AAGjC,MAAA,IAAI,kBAAA,CAAmB,QAAQ,CAAA,EAAG,OAAO,IAAA;AAIzC,MAAA,IAAI,kBAAA,CAAmB,MAAM,CAAA,EAAG;AAC5B,QAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,MAAA,EAAQ,QAAQ,CAAA;AAEnD,QAAA,IAAI,sBAAsB,OAAA,EAAS;AAC/B,UAAA,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,QACtB,CAAA,MAAO;AACH,UAAA,IAAA,CAAK,KAAK,OAAO,CAAA;AAAA,QACrB;AAAA,MACJ;AAEA,MAAA,OAAO,IAAA;AAAA,IACX,CAAA;AAAA,IAEA,SAAA,CAAU,IAAA,EAAM,EAAA,EAAIA,QAAAA,EAAS;AAEzB,MAAA,IAAIA,QAAAA,EAAS,KAAK,OAAO,IAAA;AAGzB,MAAA,IAAI,UAAA,CAAW,EAAE,CAAA,EAAG,OAAO,IAAA;AAG3B,MAAA,IAAI,kBAAA,CAAmB,EAAE,CAAA,EAAG,OAAO,IAAA;AAGnC,MAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,MAAA,IAAI,QAAQ,UAAA,CAAW,cAAc,KAAK,OAAA,CAAQ,UAAA,CAAW,cAAc,CAAA,EAAG;AAC1E,QAAA,MAAM,OAAA,GACF,CAAA;;AAAA,QAAA,EACW,EAAE;;AAAA,gGAAA,CAAA;AAIjB,QAAA,IAAI,sBAAsB,OAAA,EAAS;AAC/B,UAAA,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,QACtB,CAAA,MAAO;AACH,UAAA,IAAA,CAAK,KAAK,OAAO,CAAA;AAAA,QACrB;AAAA,MACJ;AAEA,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,GACJ;AACJ","file":"chunk-56ZZNOJD.js","sourcesContent":["/**\r\n * @flight-framework/core - Server Boundary Plugin\r\n * \r\n * Vite plugin to detect server-only code imported in client bundles.\r\n * OPTIONAL - use if you want build-time protection.\r\n * \r\n * Features:\r\n * - Detects *.server.ts files imported in client code\r\n * - Detects /server/ and /api/ directory imports\r\n * - Configurable behavior (warn, error)\r\n * - Clear error messages with solutions\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { serverBoundaryPlugin } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [serverBoundaryPlugin()],\r\n * };\r\n * ```\r\n */\r\n\r\nimport type { Plugin } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface ServerBoundaryPluginOptions {\r\n /**\r\n * File patterns that are server-only.\r\n * @default ['.server.ts', '.server.tsx', '.server.js', '.server.jsx']\r\n */\r\n serverFilePatterns?: string[];\r\n\r\n /**\r\n * Directory patterns that are server-only.\r\n * @default ['/server/', '/api/']\r\n */\r\n serverDirPatterns?: string[];\r\n\r\n /**\r\n * How to handle violations.\r\n * - 'error': Build error (recommended for production)\r\n * - 'warn': Warning only (for migration)\r\n * @default 'error'\r\n */\r\n violationBehavior?: 'error' | 'warn';\r\n\r\n /**\r\n * Custom error message template.\r\n */\r\n customErrorMessage?: (module: string, importer: string) => string;\r\n\r\n /**\r\n * Files to exclude from checking (e.g., tests).\r\n * @default ['**\\/*.test.*', '**\\/*.spec.*']\r\n */\r\n exclude?: string[];\r\n}\r\n\r\n// ============================================================================\r\n// Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin to detect server-only imports in client code.\r\n * \r\n * This plugin is OPTIONAL. Use it if you want build-time\r\n * detection of server code leaking to the client.\r\n * \r\n * By default, it will:\r\n * - Block imports of *.server.ts files in client code\r\n * - Block imports from /server/ and /api/ directories\r\n * - Throw build errors with clear solutions\r\n */\r\nexport function serverBoundaryPlugin(\r\n options: ServerBoundaryPluginOptions = {}\r\n): Plugin {\r\n const {\r\n serverFilePatterns = ['.server.ts', '.server.tsx', '.server.js', '.server.jsx'],\r\n serverDirPatterns = ['/server/', '/api/'],\r\n violationBehavior = 'error',\r\n customErrorMessage,\r\n exclude = ['**/*.test.*', '**/*.spec.*', '**/node_modules/**'],\r\n } = options;\r\n\r\n // Build regex patterns\r\n const filePatterns = serverFilePatterns.map(p =>\r\n new RegExp(p.replace(/\\./g, '\\\\.') + '$', 'i')\r\n );\r\n const dirPatterns = serverDirPatterns.map(p =>\r\n new RegExp(p.replace(/\\//g, '[\\\\\\\\/]'), 'i')\r\n );\r\n\r\n function isServerOnlyModule(id: string): boolean {\r\n // Check file patterns\r\n for (const pattern of filePatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n\r\n // Check directory patterns\r\n for (const pattern of dirPatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n function isExcluded(id: string): boolean {\r\n for (const pattern of exclude) {\r\n // Simple glob matching\r\n const regex = new RegExp(\r\n pattern\r\n .replace(/\\*\\*/g, '.*')\r\n .replace(/\\*/g, '[^/\\\\\\\\]*')\r\n .replace(/\\./g, '\\\\.')\r\n );\r\n if (regex.test(id)) return true;\r\n }\r\n return false;\r\n }\r\n\r\n function createErrorMessage(module: string, importer: string): string {\r\n if (customErrorMessage) {\r\n return customErrorMessage(module, importer);\r\n }\r\n\r\n return (\r\n `[Flight] Cannot import server-only module in client code.\\n\\n` +\r\n ` Module: ${module}\\n` +\r\n ` Imported by: ${importer}\\n\\n` +\r\n `Solutions:\\n` +\r\n ` 1. Move the import to a 'use server' file\\n` +\r\n ` 2. Use an API route instead\\n` +\r\n ` 3. Use dynamic import with typeof window check\\n` +\r\n ` 4. Rename the importing file to *.server.ts\\n\\n` +\r\n `Learn more: https://flight-framework.dev/docs/server-client-boundaries`\r\n );\r\n }\r\n\r\n return {\r\n name: 'flight:server-boundary',\r\n enforce: 'pre',\r\n\r\n resolveId(source, importer, options) {\r\n // Skip SSR builds - server can import anything\r\n if (options?.ssr) return null;\r\n\r\n // Need an importer to check\r\n if (!importer) return null;\r\n\r\n // Skip excluded files\r\n if (isExcluded(importer)) return null;\r\n\r\n // Skip if importer is also server-only\r\n if (isServerOnlyModule(importer)) return null;\r\n\r\n // Check if the import target is server-only\r\n // This is a simplified check - the resolved ID would be more accurate\r\n if (isServerOnlyModule(source)) {\r\n const message = createErrorMessage(source, importer);\r\n\r\n if (violationBehavior === 'error') {\r\n this.error(message);\r\n } else {\r\n this.warn(message);\r\n }\r\n }\r\n\r\n return null;\r\n },\r\n\r\n transform(code, id, options) {\r\n // Skip SSR builds\r\n if (options?.ssr) return null;\r\n\r\n // Skip excluded files\r\n if (isExcluded(id)) return null;\r\n\r\n // Skip server-only files (they shouldn't be in client bundle anyway)\r\n if (isServerOnlyModule(id)) return null;\r\n\r\n // Check for 'use server' directive at file level\r\n const trimmed = code.trim();\r\n if (trimmed.startsWith(\"'use server'\") || trimmed.startsWith('\"use server\"')) {\r\n const message =\r\n `[Flight] 'use server' file imported in client bundle.\\n\\n` +\r\n ` File: ${id}\\n\\n` +\r\n `This file should only run on the server. ` +\r\n `Check your import graph to find where this is imported.`;\r\n\r\n if (violationBehavior === 'error') {\r\n this.error(message);\r\n } else {\r\n this.warn(message);\r\n }\r\n }\r\n\r\n return null;\r\n },\r\n };\r\n}\r\n"]}
|