@flink-app/flink 0.14.3 → 2.0.0-alpha.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/cli/build.ts +8 -1
  3. package/cli/run.ts +8 -1
  4. package/dist/cli/build.js +8 -1
  5. package/dist/cli/run.js +8 -1
  6. package/dist/src/FlinkApp.d.ts +33 -0
  7. package/dist/src/FlinkApp.js +279 -35
  8. package/dist/src/FlinkContext.d.ts +21 -0
  9. package/dist/src/FlinkHttpHandler.d.ts +152 -9
  10. package/dist/src/FlinkHttpHandler.js +37 -1
  11. package/dist/src/TypeScriptCompiler.d.ts +42 -0
  12. package/dist/src/TypeScriptCompiler.js +346 -4
  13. package/dist/src/TypeScriptUtils.js +4 -0
  14. package/dist/src/ai/AgentRunner.d.ts +39 -0
  15. package/dist/src/ai/AgentRunner.js +625 -0
  16. package/dist/src/ai/FlinkAgent.d.ts +446 -0
  17. package/dist/src/ai/FlinkAgent.js +633 -0
  18. package/dist/src/ai/FlinkTool.d.ts +37 -0
  19. package/dist/src/ai/FlinkTool.js +2 -0
  20. package/dist/src/ai/LLMAdapter.d.ts +119 -0
  21. package/dist/src/ai/LLMAdapter.js +2 -0
  22. package/dist/src/ai/SubAgentExecutor.d.ts +36 -0
  23. package/dist/src/ai/SubAgentExecutor.js +220 -0
  24. package/dist/src/ai/ToolExecutor.d.ts +35 -0
  25. package/dist/src/ai/ToolExecutor.js +237 -0
  26. package/dist/src/ai/index.d.ts +5 -0
  27. package/dist/src/ai/index.js +21 -0
  28. package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
  29. package/dist/src/handlers/StreamWriterFactory.js +83 -0
  30. package/dist/src/index.d.ts +4 -0
  31. package/dist/src/index.js +4 -0
  32. package/dist/src/utils.d.ts +30 -0
  33. package/dist/src/utils.js +52 -0
  34. package/package.json +16 -2
  35. package/readme.md +425 -0
  36. package/spec/AgentDuplicateDetection.spec.ts +112 -0
  37. package/spec/AgentRunner.spec.ts +527 -0
  38. package/spec/ConversationHooks.spec.ts +290 -0
  39. package/spec/FlinkAgent.spec.ts +310 -0
  40. package/spec/FlinkApp.onError.spec.ts +1 -2
  41. package/spec/FlinkApp.query.spec.ts +107 -0
  42. package/spec/FlinkApp.validationMode.spec.ts +155 -0
  43. package/spec/StreamingIntegration.spec.ts +138 -0
  44. package/spec/SubAgentSupport.spec.ts +941 -0
  45. package/spec/ToolExecutor.spec.ts +360 -0
  46. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +57 -0
  47. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +59 -0
  48. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +53 -0
  49. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +53 -0
  50. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +53 -0
  51. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +55 -0
  52. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +55 -0
  53. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +58 -0
  54. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +58 -0
  55. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
  56. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
  57. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +58 -0
  58. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +76 -0
  59. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +58 -0
  60. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +59 -0
  61. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +59 -0
  62. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +55 -0
  63. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +56 -0
  64. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +55 -0
  65. package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +55 -0
  66. package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
  67. package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
  68. package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
  69. package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
  70. package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
  71. package/spec/mock-project/dist/src/FlinkApp.js +1012 -0
  72. package/spec/mock-project/dist/src/FlinkContext.js +2 -0
  73. package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
  74. package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
  75. package/spec/mock-project/dist/src/FlinkJob.js +2 -0
  76. package/spec/mock-project/dist/src/FlinkLog.js +26 -0
  77. package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
  78. package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
  79. package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
  80. package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
  81. package/spec/mock-project/dist/src/ai/AgentRunner.js +625 -0
  82. package/spec/mock-project/dist/src/ai/FlinkAgent.js +633 -0
  83. package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
  84. package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
  85. package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +220 -0
  86. package/spec/mock-project/dist/src/ai/ToolExecutor.js +237 -0
  87. package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
  88. package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
  89. package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
  90. package/spec/mock-project/dist/src/index.js +17 -69
  91. package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
  92. package/spec/mock-project/dist/src/utils.js +290 -0
  93. package/spec/mock-project/tsconfig.json +6 -1
  94. package/spec/testHelpers.ts +49 -0
  95. package/spec/utils.caseConversion.spec.ts +80 -0
  96. package/spec/utils.spec.ts +13 -13
  97. package/src/FlinkApp.ts +275 -8
  98. package/src/FlinkContext.ts +22 -0
  99. package/src/FlinkHttpHandler.ts +164 -10
  100. package/src/TypeScriptCompiler.ts +398 -7
  101. package/src/TypeScriptUtils.ts +5 -0
  102. package/src/ai/AgentRunner.ts +549 -0
  103. package/src/ai/FlinkAgent.ts +770 -0
  104. package/src/ai/FlinkTool.ts +40 -0
  105. package/src/ai/LLMAdapter.ts +96 -0
  106. package/src/ai/SubAgentExecutor.ts +199 -0
  107. package/src/ai/ToolExecutor.ts +193 -0
  108. package/src/ai/index.ts +5 -0
  109. package/src/handlers/StreamWriterFactory.ts +84 -0
  110. package/src/index.ts +4 -0
  111. package/src/utils.ts +52 -0
  112. package/tsconfig.json +6 -1
@@ -10,24 +10,95 @@ export declare enum HttpMethod {
10
10
  delete = "delete",
11
11
  patch = "patch"
12
12
  }
13
- type Params = Request["params"];
13
+ /**
14
+ * Validation mode for handler request and response schemas.
15
+ *
16
+ * Controls whether request and/or response data is validated against JSON schemas.
17
+ *
18
+ * **Security Note:** Skipping validation can introduce security risks. Only use
19
+ * SkipValidation or ValidateResponse when you have implemented custom validation
20
+ * or the endpoint is internal/trusted.
21
+ *
22
+ * - Validate: Validate both request and response (default behavior)
23
+ * - SkipValidation: Skip both request and response validation
24
+ * - ValidateRequest: Validate only request, skip response validation
25
+ * - ValidateResponse: Validate only response, skip request validation
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // Skip validation for webhook with custom signature verification
30
+ * export const Route: RouteProps = {
31
+ * path: "/webhook",
32
+ * validation: ValidationMode.SkipValidation
33
+ * };
34
+ *
35
+ * // Validate request but allow flexible response during development
36
+ * export const Route: RouteProps = {
37
+ * path: "/api/data",
38
+ * validation: ValidationMode.ValidateRequest
39
+ * };
40
+ * ```
41
+ */
42
+ export declare enum ValidationMode {
43
+ Validate = "Validate",
44
+ SkipValidation = "SkipValidation",
45
+ ValidateRequest = "ValidateRequest",
46
+ ValidateResponse = "ValidateResponse"
47
+ }
48
+ type Params = Record<string, string>;
14
49
  /**
15
50
  * Query type for request query parameters.
16
- * Does currently not allow nested objects, although
17
- * underlying express Request does allow it.
18
51
  *
19
- * Uses index signature to allow both Record types and interface types
20
- * to be assignable to Query without requiring explicit index signatures.
52
+ * All query parameter values are normalized to strings or string arrays:
53
+ * - Single values: string (e.g., ?name=John becomes { name: "John" })
54
+ * - Multiple values: string[] (e.g., ?tag=a&tag=b becomes { tag: ["a", "b"] })
55
+ *
56
+ * Does not allow nested objects, although underlying Express Request does allow it.
21
57
  */
22
- type Query = {
23
- [x: string]: string | string[] | undefined;
24
- };
58
+ type Query = Record<string, string | string[]>;
59
+ /**
60
+ * Stream format for streaming handlers.
61
+ * - sse: Server-Sent Events (text/event-stream)
62
+ * - ndjson: Newline-Delimited JSON (application/x-ndjson)
63
+ */
64
+ export type StreamFormat = "sse" | "ndjson";
65
+ /**
66
+ * Stream writer interface for SSE/NDJSON streaming.
67
+ *
68
+ * Provides methods to write data chunks, handle errors, and manage the stream lifecycle.
69
+ * Only available in handlers where streamFormat is specified in RouteProps.
70
+ */
71
+ export interface StreamWriter<T = any> {
72
+ /**
73
+ * Write data to the stream.
74
+ * Data is automatically JSON-stringified and formatted according to streamFormat.
75
+ */
76
+ write(data: T): void;
77
+ /**
78
+ * Send error to client and close the stream.
79
+ */
80
+ error(error: Error | string): void;
81
+ /**
82
+ * Close the stream gracefully.
83
+ */
84
+ end(): void;
85
+ /**
86
+ * Check if stream is still open (client connected).
87
+ * Returns false if client has disconnected.
88
+ */
89
+ isOpen(): boolean;
90
+ }
25
91
  /**
26
- * Flink request extends express Request but adds reqId and user object.
92
+ * Flink request extends express Request but adds reqId, user object, and userPermissions.
93
+ *
94
+ * userPermissions is populated by auth plugins during authentication and contains
95
+ * the resolved permissions array based on the plugin's configuration (roles, dynamic
96
+ * roles, custom permissions, etc.)
27
97
  */
28
98
  export type FlinkRequest<T = any, P = Params, Q = Query> = Request<P, any, T, Q> & {
29
99
  reqId: string;
30
100
  user?: any;
101
+ userPermissions?: string[];
31
102
  };
32
103
  /**
33
104
  * Route props to control routing.
@@ -59,6 +130,27 @@ export interface RouteProps {
59
130
  mockApi?: boolean;
60
131
  /**
61
132
  * Set permissions needed to access route if route requires authentication.
133
+ *
134
+ * When an array is provided, the user must have **ALL** permissions in the array (AND logic).
135
+ * To require any one of multiple permissions (OR logic), implement custom permission
136
+ * checking in the handler using the `user.permissions` array.
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * // Single permission
141
+ * permissions: "car:create"
142
+ *
143
+ * // Multiple permissions (user must have ALL)
144
+ * permissions: ["car:create", "car:premium"]
145
+ *
146
+ * // OR logic requires custom implementation
147
+ * const handler = async ({ ctx, user }) => {
148
+ * if (!user.permissions.includes("car:admin") && !user.permissions.includes("car:moderator")) {
149
+ * throw forbidden("Need admin or moderator permission");
150
+ * }
151
+ * // ... handler logic
152
+ * };
153
+ * ```
62
154
  */
63
155
  permissions?: string | string[];
64
156
  /**
@@ -82,15 +174,66 @@ export interface RouteProps {
82
174
  * to avoid conflicts you can set a negative order.
83
175
  */
84
176
  order?: number;
177
+ /**
178
+ * Validation mode for request and response schemas.
179
+ *
180
+ * Controls schema validation behavior for this handler. Use with caution as
181
+ * skipping validation can introduce security vulnerabilities.
182
+ *
183
+ * **Options:**
184
+ * - Validate: Validate both request and response (default)
185
+ * - SkipValidation: Skip both request and response validation
186
+ * - ValidateRequest: Validate only request, skip response validation
187
+ * - ValidateResponse: Validate only response, skip request validation
188
+ *
189
+ * **When to skip validation:**
190
+ * - Webhook handlers with custom signature verification
191
+ * - Performance-critical internal endpoints
192
+ * - Handlers using alternative validation methods (e.g., Zod, Joi)
193
+ *
194
+ * @default ValidationMode.Validate
195
+ */
196
+ validation?: ValidationMode;
197
+ /**
198
+ * Stream format for streaming handlers (SSE or NDJSON).
199
+ *
200
+ * When specified, the handler becomes a streaming handler and receives a `stream`
201
+ * parameter for writing data chunks. Response validation is automatically skipped
202
+ * for streaming handlers (chunks are progressive, not a final JSON response).
203
+ *
204
+ * **Formats:**
205
+ * - sse: Server-Sent Events (text/event-stream) - ideal for browser EventSource API
206
+ * - ndjson: Newline-Delimited JSON (application/x-ndjson) - ideal for LLM text streaming
207
+ *
208
+ * **Example:**
209
+ * ```typescript
210
+ * export const Route: RouteProps = {
211
+ * path: "/ai/stream",
212
+ * streamFormat: "sse"
213
+ * };
214
+ *
215
+ * const handler: GetHandler<{}, void> = async ({ ctx, stream }) => {
216
+ * if (!stream) throw new Error("Stream not available");
217
+ * stream.write({ message: "Hello" });
218
+ * stream.end();
219
+ * };
220
+ * ```
221
+ */
222
+ streamFormat?: StreamFormat;
85
223
  }
86
224
  /**
87
225
  * Http handler function that handlers implements in order to
88
226
  * handle HTTP requests and return a JSON response.
227
+ *
228
+ * For streaming handlers (when streamFormat is specified in RouteProps),
229
+ * the stream parameter is available. Streaming handlers should still return
230
+ * a FlinkResponse (can be empty), but it will be ignored by the framework.
89
231
  */
90
232
  export type Handler<Ctx extends FlinkContext, ReqSchema = any, ResSchema = any, P extends Params = Params, Q extends Query = Query> = (props: {
91
233
  req: FlinkRequest<ReqSchema, P, Q>;
92
234
  ctx: Ctx;
93
235
  origin?: string;
236
+ stream?: StreamWriter;
94
237
  }) => Promise<FlinkResponse<ResSchema | FlinkError>>;
95
238
  /**
96
239
  * Http handler function specifically for GET requests as those does
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpMethod = void 0;
3
+ exports.ValidationMode = exports.HttpMethod = void 0;
4
4
  var HttpMethod;
5
5
  (function (HttpMethod) {
6
6
  HttpMethod["get"] = "get";
@@ -9,3 +9,39 @@ var HttpMethod;
9
9
  HttpMethod["delete"] = "delete";
10
10
  HttpMethod["patch"] = "patch";
11
11
  })(HttpMethod || (exports.HttpMethod = HttpMethod = {}));
12
+ /**
13
+ * Validation mode for handler request and response schemas.
14
+ *
15
+ * Controls whether request and/or response data is validated against JSON schemas.
16
+ *
17
+ * **Security Note:** Skipping validation can introduce security risks. Only use
18
+ * SkipValidation or ValidateResponse when you have implemented custom validation
19
+ * or the endpoint is internal/trusted.
20
+ *
21
+ * - Validate: Validate both request and response (default behavior)
22
+ * - SkipValidation: Skip both request and response validation
23
+ * - ValidateRequest: Validate only request, skip response validation
24
+ * - ValidateResponse: Validate only response, skip request validation
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // Skip validation for webhook with custom signature verification
29
+ * export const Route: RouteProps = {
30
+ * path: "/webhook",
31
+ * validation: ValidationMode.SkipValidation
32
+ * };
33
+ *
34
+ * // Validate request but allow flexible response during development
35
+ * export const Route: RouteProps = {
36
+ * path: "/api/data",
37
+ * validation: ValidationMode.ValidateRequest
38
+ * };
39
+ * ```
40
+ */
41
+ var ValidationMode;
42
+ (function (ValidationMode) {
43
+ ValidationMode["Validate"] = "Validate";
44
+ ValidationMode["SkipValidation"] = "SkipValidation";
45
+ ValidationMode["ValidateRequest"] = "ValidateRequest";
46
+ ValidationMode["ValidateResponse"] = "ValidateResponse";
47
+ })(ValidationMode || (exports.ValidationMode = ValidationMode = {}));
@@ -18,6 +18,28 @@ declare class TypeScriptCompiler {
18
18
  */
19
19
  private tsSchemasSymbolsToImports;
20
20
  constructor(cwd: string);
21
+ /**
22
+ * Loads additional source paths from tsconfig.json's flink configuration.
23
+ * Allows projects to specify extra directories to include in compilation.
24
+ *
25
+ * Example tsconfig.json:
26
+ * {
27
+ * "flink": {
28
+ * "sourcePaths": ["src/custom-types/**\/*.ts", "src/utils/**\/*.ts"]
29
+ * }
30
+ * }
31
+ */
32
+ private getFlinkSourcePaths;
33
+ /**
34
+ * Recursively resolves and adds imported files to the project.
35
+ * This ensures that files imported by handlers, schemas, etc. are available for type resolution.
36
+ *
37
+ * Handles three types of imports:
38
+ * 1. Relative imports (./foo, ../bar) - always resolved
39
+ * 2. Workspace package imports (@mycompany/shared) - resolved if symlinked outside node_modules
40
+ * 3. External packages (lodash, express) - skipped to avoid loading entire dependency trees
41
+ */
42
+ private resolveImportedFiles;
21
43
  /**
22
44
  * Detects if the project is using ESM (ECMAScript Modules)
23
45
  * by checking type in package.json.
@@ -41,6 +63,15 @@ declare class TypeScriptCompiler {
41
63
  * exists. Warnings will be passed thru but logged.
42
64
  */
43
65
  getPreEmitDiagnostics(): boolean;
66
+ /**
67
+ * Finds a variable declaration by its TypeScript type name.
68
+ * This allows finding variables based on their type annotation rather than variable name.
69
+ *
70
+ * @param sf Source file to search in
71
+ * @param typeName Name of the type to search for (e.g., "FlinkToolProps", "FlinkAgentProps")
72
+ * @returns The first matching variable declaration, or undefined if not found
73
+ */
74
+ private findVariableDeclarationByType;
44
75
  /**
45
76
  * Scans project for handlers and add those to Flink
46
77
  * "singleton" property `autoRegisteredHandlers` so they can
@@ -55,6 +86,17 @@ declare class TypeScriptCompiler {
55
86
  */
56
87
  private parseHandlerDir;
57
88
  parseRepos(): Promise<SourceFile>;
89
+ /**
90
+ * Scans project for tools and adds those to Flink
91
+ * "singleton" property `autoRegisteredTools` so they can
92
+ * be registered during start.
93
+ */
94
+ parseTools(): Promise<SourceFile>;
95
+ /**
96
+ * Scans project for agents and validates tool references.
97
+ * Agents are declarative (no default function).
98
+ */
99
+ parseAgents(): Promise<SourceFile>;
58
100
  /**
59
101
  * Generates a start script that will import references to handlers, repos and the
60
102
  * actual Flink app to start.