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

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 (280) hide show
  1. package/CHANGELOG.md +1051 -0
  2. package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
  3. package/SIMPLE_AST_FEASIBILITY.md +570 -0
  4. package/bin/flink.ts +13 -2
  5. package/cli/build.ts +24 -44
  6. package/cli/clean.ts +13 -25
  7. package/cli/cli-utils.ts +190 -17
  8. package/cli/dev.ts +252 -0
  9. package/cli/loadEnvFiles.ts +116 -0
  10. package/cli/run.ts +45 -62
  11. package/dist/bin/flink.js +61 -2
  12. package/dist/cli/build.js +20 -25
  13. package/dist/cli/clean.js +12 -10
  14. package/dist/cli/cli-utils.d.ts +34 -3
  15. package/dist/cli/cli-utils.js +193 -12
  16. package/dist/cli/dev.d.ts +2 -0
  17. package/dist/cli/dev.js +279 -0
  18. package/dist/cli/loadEnvFiles.d.ts +30 -0
  19. package/dist/cli/loadEnvFiles.js +113 -0
  20. package/dist/cli/run.js +47 -46
  21. package/dist/src/DependencyTracker.d.ts +44 -0
  22. package/dist/src/DependencyTracker.js +239 -0
  23. package/dist/src/FlinkApp.d.ts +163 -10
  24. package/dist/src/FlinkApp.js +847 -184
  25. package/dist/src/FlinkContext.d.ts +41 -0
  26. package/dist/src/FlinkErrors.d.ts +19 -6
  27. package/dist/src/FlinkErrors.js +36 -42
  28. package/dist/src/FlinkHttpHandler.d.ts +219 -26
  29. package/dist/src/FlinkHttpHandler.js +37 -1
  30. package/dist/src/FlinkJob.d.ts +10 -0
  31. package/dist/src/FlinkLog.d.ts +82 -18
  32. package/dist/src/FlinkLog.js +165 -13
  33. package/dist/src/FlinkLogFactory.d.ts +288 -0
  34. package/dist/src/FlinkLogFactory.js +619 -0
  35. package/dist/src/FlinkRepo.d.ts +10 -2
  36. package/dist/src/FlinkRepo.js +11 -1
  37. package/dist/src/FlinkRequestContext.d.ts +63 -0
  38. package/dist/src/FlinkRequestContext.js +74 -0
  39. package/dist/src/FlinkResponse.d.ts +6 -0
  40. package/dist/src/FlinkService.d.ts +38 -0
  41. package/dist/src/FlinkService.js +46 -0
  42. package/dist/src/LeaderElection.d.ts +45 -0
  43. package/dist/src/LeaderElection.js +269 -0
  44. package/dist/src/SchemaCache.d.ts +84 -0
  45. package/dist/src/SchemaCache.js +289 -0
  46. package/dist/src/TypeScriptCompiler.d.ts +161 -51
  47. package/dist/src/TypeScriptCompiler.js +1253 -617
  48. package/dist/src/TypeScriptUtils.js +4 -0
  49. package/dist/src/ai/AgentRunner.d.ts +39 -0
  50. package/dist/src/ai/AgentRunner.js +760 -0
  51. package/dist/src/ai/ConversationAgent.d.ts +279 -0
  52. package/dist/src/ai/ConversationAgent.js +404 -0
  53. package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
  54. package/dist/src/ai/ConversationFlinkAgent.js +404 -0
  55. package/dist/src/ai/FlinkAgent.d.ts +690 -0
  56. package/dist/src/ai/FlinkAgent.js +729 -0
  57. package/dist/src/ai/FlinkTool.d.ts +135 -0
  58. package/dist/src/ai/FlinkTool.js +2 -0
  59. package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
  60. package/dist/src/ai/InMemoryConversationAgent.js +209 -0
  61. package/dist/src/ai/LLMAdapter.d.ts +148 -0
  62. package/dist/src/ai/LLMAdapter.js +2 -0
  63. package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
  64. package/dist/src/ai/PersistentFlinkAgent.js +403 -0
  65. package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
  66. package/dist/src/ai/SubAgentExecutor.js +223 -0
  67. package/dist/src/ai/ToolExecutor.d.ts +64 -0
  68. package/dist/src/ai/ToolExecutor.js +497 -0
  69. package/dist/src/ai/agentInstructions.d.ts +68 -0
  70. package/dist/src/ai/agentInstructions.js +286 -0
  71. package/dist/src/ai/index.d.ts +8 -0
  72. package/dist/src/ai/index.js +26 -0
  73. package/dist/src/ai/instructionFileLoader.d.ts +44 -0
  74. package/dist/src/ai/instructionFileLoader.js +179 -0
  75. package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
  76. package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
  77. package/dist/src/handlers/StreamWriterFactory.js +83 -0
  78. package/dist/src/index.d.ts +14 -0
  79. package/dist/src/index.js +17 -0
  80. package/dist/src/loadPluginSchemas.d.ts +45 -0
  81. package/dist/src/loadPluginSchemas.js +143 -0
  82. package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
  83. package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
  84. package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
  85. package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
  86. package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
  87. package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
  88. package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
  89. package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
  90. package/dist/src/schema-extraction/index.d.ts +2 -0
  91. package/dist/src/schema-extraction/index.js +20 -0
  92. package/dist/src/schema-extraction/types.d.ts +31 -0
  93. package/dist/src/schema-extraction/types.js +2 -0
  94. package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
  95. package/dist/src/utils/loadFlinkConfig.js +77 -0
  96. package/dist/src/utils.d.ts +30 -0
  97. package/dist/src/utils.js +52 -0
  98. package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
  99. package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
  100. package/dist/src/workers/WorkerPool.d.ts +60 -0
  101. package/dist/src/workers/WorkerPool.js +306 -0
  102. package/examples/logging-hierarchical-example.ts +125 -0
  103. package/package.json +29 -4
  104. package/readme.md +499 -0
  105. package/spec/AgentDescendantDetection.spec.ts +335 -0
  106. package/spec/AgentDuplicateDetection.spec.ts +112 -0
  107. package/spec/AgentObserver.spec.ts +266 -0
  108. package/spec/AgentRunner.spec.ts +1062 -0
  109. package/spec/AsyncLocalStorageContext.spec.ts +223 -0
  110. package/spec/ConversationHooks.spec.ts +257 -0
  111. package/spec/FlinkAgent.spec.ts +681 -0
  112. package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
  113. package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
  114. package/spec/FlinkApp.onError.spec.ts +1 -2
  115. package/spec/FlinkApp.query.spec.ts +107 -0
  116. package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
  117. package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
  118. package/spec/FlinkApp.validationMode.spec.ts +155 -0
  119. package/spec/FlinkJob.spec.ts +171 -0
  120. package/spec/FlinkLogFactory.spec.ts +337 -0
  121. package/spec/FlinkRepo.spec.ts +1 -1
  122. package/spec/LeaderElection.spec.ts +174 -0
  123. package/spec/StreamingIntegration.spec.ts +139 -0
  124. package/spec/ToolExecutor.spec.ts +465 -0
  125. package/spec/TypeScriptCompiler.spec.ts +1 -1
  126. package/spec/TypeScriptSourceParser.spec.ts +1215 -0
  127. package/spec/TypeScriptTokenizer.spec.ts +366 -0
  128. package/spec/ai/ContextCompaction.spec.ts +405 -0
  129. package/spec/ai/ConversationAgent.spec.ts +520 -0
  130. package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
  131. package/spec/ai/agentInstructions.spec.ts +358 -0
  132. package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
  133. package/spec/fixtures/agent-instructions/simple.md +3 -0
  134. package/spec/fixtures/agent-instructions/template.md +18 -0
  135. package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
  136. package/spec/mock-project/dist/.tsbuildinfo +1 -0
  137. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
  138. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
  139. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
  140. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
  141. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
  142. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
  143. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
  144. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
  145. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
  146. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
  147. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
  148. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
  149. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
  150. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
  151. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
  152. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
  153. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
  154. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
  155. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
  156. package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
  157. package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
  158. package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
  159. package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
  160. package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
  161. package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
  162. package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
  163. package/spec/mock-project/dist/src/FlinkContext.js +2 -0
  164. package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
  165. package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
  166. package/spec/mock-project/dist/src/FlinkJob.js +2 -0
  167. package/spec/mock-project/dist/src/FlinkLog.js +119 -0
  168. package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
  169. package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
  170. package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
  171. package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
  172. package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
  173. package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
  174. package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
  175. package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
  176. package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
  177. package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
  178. package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
  179. package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
  180. package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
  181. package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
  182. package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
  183. package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
  184. package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
  185. package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
  186. package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
  187. package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
  188. package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
  189. package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
  190. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
  191. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
  192. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
  193. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
  194. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
  195. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
  196. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
  197. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
  198. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
  199. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
  200. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
  201. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
  202. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
  203. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
  204. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
  205. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
  206. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
  207. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
  208. package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
  209. package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
  210. package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
  211. package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
  212. package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
  213. package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
  214. package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
  215. package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
  216. package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
  217. package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
  218. package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
  219. package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
  220. package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
  221. package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
  222. package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
  223. package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
  224. package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
  225. package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
  226. package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
  227. package/spec/mock-project/dist/src/index.js +52 -76
  228. package/spec/mock-project/dist/src/index.js.map +1 -0
  229. package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
  230. package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
  231. package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
  232. package/spec/mock-project/dist/src/schemas/Car.js +3 -1
  233. package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
  234. package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
  235. package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
  236. package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
  237. package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
  238. package/spec/mock-project/dist/src/utils.js +290 -0
  239. package/spec/mock-project/tsconfig.json +6 -1
  240. package/spec/schema-generation-nested-objects.spec.ts +97 -0
  241. package/spec/testHelpers.ts +49 -0
  242. package/spec/utils.caseConversion.spec.ts +78 -0
  243. package/spec/utils.spec.ts +13 -13
  244. package/src/DependencyTracker.ts +166 -0
  245. package/src/FlinkApp.ts +919 -155
  246. package/src/FlinkContext.ts +43 -0
  247. package/src/FlinkErrors.ts +32 -12
  248. package/src/FlinkHttpHandler.ts +246 -28
  249. package/src/FlinkJob.ts +11 -0
  250. package/src/FlinkLog.ts +119 -12
  251. package/src/FlinkLogFactory.ts +699 -0
  252. package/src/FlinkRepo.ts +10 -3
  253. package/src/FlinkRequestContext.ts +95 -0
  254. package/src/FlinkResponse.ts +6 -0
  255. package/src/FlinkService.ts +49 -0
  256. package/src/LeaderElection.ts +203 -0
  257. package/src/SchemaCache.ts +232 -0
  258. package/src/TypeScriptCompiler.ts +1347 -610
  259. package/src/TypeScriptUtils.ts +5 -0
  260. package/src/ai/AgentRunner.ts +646 -0
  261. package/src/ai/ConversationAgent.ts +413 -0
  262. package/src/ai/FlinkAgent.ts +1069 -0
  263. package/src/ai/FlinkTool.ts +165 -0
  264. package/src/ai/InMemoryConversationAgent.ts +149 -0
  265. package/src/ai/LLMAdapter.ts +126 -0
  266. package/src/ai/ToolExecutor.ts +485 -0
  267. package/src/ai/agentInstructions.ts +245 -0
  268. package/src/ai/index.ts +8 -0
  269. package/src/ai/instructionFileLoader.ts +156 -0
  270. package/src/auth/FlinkAuthPlugin.ts +2 -1
  271. package/src/handlers/StreamWriterFactory.ts +84 -0
  272. package/src/index.ts +14 -0
  273. package/src/loadPluginSchemas.ts +141 -0
  274. package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
  275. package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
  276. package/src/schema-extraction/index.ts +2 -0
  277. package/src/schema-extraction/types.ts +34 -0
  278. package/src/utils/loadFlinkConfig.ts +89 -0
  279. package/src/utils.ts +52 -0
  280. package/tsconfig.json +6 -1
@@ -0,0 +1,63 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ /**
3
+ * Request-scoped context available throughout handler → agent → tool execution
4
+ */
5
+ export interface RequestContext {
6
+ /** Unique request identifier (from req.reqId) */
7
+ reqId: string;
8
+ /** Authenticated user object (from req.user) */
9
+ user?: any;
10
+ /** Resolved user permissions from auth plugin (from req.userPermissions) */
11
+ userPermissions?: string[];
12
+ /** HTTP method (GET, POST, etc.) */
13
+ method?: string;
14
+ /** Request path */
15
+ path?: string;
16
+ /** Request start timestamp */
17
+ timestamp: number;
18
+ /** Whether this is a streaming request (SSE/NDJSON) */
19
+ isStreaming?: boolean;
20
+ }
21
+ /**
22
+ * AsyncLocalStorage instance for request-scoped context
23
+ * Available throughout the entire request lifecycle including async operations
24
+ */
25
+ export declare const requestContext: AsyncLocalStorage<RequestContext>;
26
+ /**
27
+ * Get the current request context
28
+ * Returns undefined if called outside of a request context
29
+ */
30
+ export declare function getRequestContext(): RequestContext | undefined;
31
+ /**
32
+ * Get the authenticated user from request context
33
+ * Returns undefined if no user is authenticated or outside request context
34
+ */
35
+ export declare function getRequestUser<T = any>(): T | undefined;
36
+ /**
37
+ * Get user permissions from request context
38
+ * Returns empty array if no permissions available
39
+ */
40
+ export declare function getRequestPermissions(): string[];
41
+ /**
42
+ * Get request ID from context
43
+ * Returns undefined if called outside of request context
44
+ */
45
+ export declare function getReqId(): string | undefined;
46
+ /**
47
+ * Check if current user has a specific permission
48
+ * @param permission - Permission string to check
49
+ * @returns true if user has the permission, false otherwise
50
+ */
51
+ export declare function hasPermission(permission: string): boolean;
52
+ /**
53
+ * Check if current user has all of the specified permissions (AND logic)
54
+ * @param requiredPermissions - Array of permission strings (all required)
55
+ * @returns true if user has all permissions, false otherwise
56
+ */
57
+ export declare function hasAllPermissions(requiredPermissions: string[]): boolean;
58
+ /**
59
+ * Check if current user has any of the specified permissions (OR logic)
60
+ * @param requiredPermissions - Array of permission strings (any required)
61
+ * @returns true if user has at least one permission, false otherwise
62
+ */
63
+ export declare function hasAnyPermission(requiredPermissions: string[]): boolean;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestContext = void 0;
4
+ exports.getRequestContext = getRequestContext;
5
+ exports.getRequestUser = getRequestUser;
6
+ exports.getRequestPermissions = getRequestPermissions;
7
+ exports.getReqId = getReqId;
8
+ exports.hasPermission = hasPermission;
9
+ exports.hasAllPermissions = hasAllPermissions;
10
+ exports.hasAnyPermission = hasAnyPermission;
11
+ var async_hooks_1 = require("async_hooks");
12
+ /**
13
+ * AsyncLocalStorage instance for request-scoped context
14
+ * Available throughout the entire request lifecycle including async operations
15
+ */
16
+ exports.requestContext = new async_hooks_1.AsyncLocalStorage();
17
+ /**
18
+ * Get the current request context
19
+ * Returns undefined if called outside of a request context
20
+ */
21
+ function getRequestContext() {
22
+ return exports.requestContext.getStore();
23
+ }
24
+ /**
25
+ * Get the authenticated user from request context
26
+ * Returns undefined if no user is authenticated or outside request context
27
+ */
28
+ function getRequestUser() {
29
+ var _a;
30
+ return (_a = exports.requestContext.getStore()) === null || _a === void 0 ? void 0 : _a.user;
31
+ }
32
+ /**
33
+ * Get user permissions from request context
34
+ * Returns empty array if no permissions available
35
+ */
36
+ function getRequestPermissions() {
37
+ var _a;
38
+ return ((_a = exports.requestContext.getStore()) === null || _a === void 0 ? void 0 : _a.userPermissions) || [];
39
+ }
40
+ /**
41
+ * Get request ID from context
42
+ * Returns undefined if called outside of request context
43
+ */
44
+ function getReqId() {
45
+ var _a;
46
+ return (_a = exports.requestContext.getStore()) === null || _a === void 0 ? void 0 : _a.reqId;
47
+ }
48
+ /**
49
+ * Check if current user has a specific permission
50
+ * @param permission - Permission string to check
51
+ * @returns true if user has the permission, false otherwise
52
+ */
53
+ function hasPermission(permission) {
54
+ var permissions = getRequestPermissions();
55
+ return permissions.includes(permission);
56
+ }
57
+ /**
58
+ * Check if current user has all of the specified permissions (AND logic)
59
+ * @param requiredPermissions - Array of permission strings (all required)
60
+ * @returns true if user has all permissions, false otherwise
61
+ */
62
+ function hasAllPermissions(requiredPermissions) {
63
+ var permissions = getRequestPermissions();
64
+ return requiredPermissions.every(function (p) { return permissions.includes(p); });
65
+ }
66
+ /**
67
+ * Check if current user has any of the specified permissions (OR logic)
68
+ * @param requiredPermissions - Array of permission strings (any required)
69
+ * @returns true if user has at least one permission, false otherwise
70
+ */
71
+ function hasAnyPermission(requiredPermissions) {
72
+ var permissions = getRequestPermissions();
73
+ return requiredPermissions.some(function (p) { return permissions.includes(p); });
74
+ }
@@ -28,6 +28,12 @@ export interface FlinkResponse<T = any> {
28
28
  title: string;
29
29
  detail?: string;
30
30
  code?: string;
31
+ /**
32
+ * Optional structured payload with additional error context.
33
+ * Must be JSON-serializable; non-serializable values are stripped
34
+ * with a warning before sending the response.
35
+ */
36
+ meta?: unknown;
31
37
  };
32
38
  /**
33
39
  * HTTP headers, names are lower cased
@@ -0,0 +1,38 @@
1
+ import { FlinkContext } from "./FlinkContext";
2
+ /**
3
+ * Base class for Flink services - optional business logic layer.
4
+ *
5
+ * Services provide a place for shared business logic that can be used by
6
+ * handlers, jobs, agents, and other services via `ctx.services`.
7
+ *
8
+ * Context (`this.ctx`) is not available in the constructor - use `onInit()`
9
+ * for any setup that requires context.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * class CarService extends FlinkService<AppCtx> {
14
+ * async onInit() {
15
+ * // Called after all services are instantiated and ctx is fully wired
16
+ * }
17
+ *
18
+ * async getWithOwner(carId: string) {
19
+ * const car = await this.ctx.repos.carRepo.getById(carId);
20
+ * if (!car) throw notFound("Car not found");
21
+ * return car;
22
+ * }
23
+ * }
24
+ * ```
25
+ */
26
+ export declare abstract class FlinkService<C extends FlinkContext> {
27
+ private _ctx?;
28
+ set ctx(ctx: FlinkContext);
29
+ get ctx(): C;
30
+ /**
31
+ * Optional async initialization hook called after all services are
32
+ * instantiated and ctx is fully wired (repos, plugins, agents, services all available).
33
+ *
34
+ * All service onInit() methods run in parallel via Promise.all.
35
+ * Do not depend on another service's onInit() having completed.
36
+ */
37
+ onInit?(): Promise<void>;
38
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlinkService = void 0;
4
+ /**
5
+ * Base class for Flink services - optional business logic layer.
6
+ *
7
+ * Services provide a place for shared business logic that can be used by
8
+ * handlers, jobs, agents, and other services via `ctx.services`.
9
+ *
10
+ * Context (`this.ctx`) is not available in the constructor - use `onInit()`
11
+ * for any setup that requires context.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class CarService extends FlinkService<AppCtx> {
16
+ * async onInit() {
17
+ * // Called after all services are instantiated and ctx is fully wired
18
+ * }
19
+ *
20
+ * async getWithOwner(carId: string) {
21
+ * const car = await this.ctx.repos.carRepo.getById(carId);
22
+ * if (!car) throw notFound("Car not found");
23
+ * return car;
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ var FlinkService = /** @class */ (function () {
29
+ function FlinkService() {
30
+ }
31
+ Object.defineProperty(FlinkService.prototype, "ctx", {
32
+ get: function () {
33
+ if (!this._ctx) {
34
+ throw new Error("FlinkService: ctx is not available in constructor. Use onInit() for setup logic.");
35
+ }
36
+ return this._ctx;
37
+ },
38
+ set: function (ctx) {
39
+ this._ctx = ctx;
40
+ },
41
+ enumerable: false,
42
+ configurable: true
43
+ });
44
+ return FlinkService;
45
+ }());
46
+ exports.FlinkService = FlinkService;
@@ -0,0 +1,45 @@
1
+ import { Db } from "mongodb";
2
+ export interface LeaderElectionOptions {
3
+ /**
4
+ * Duration in milliseconds before a leader's lease expires.
5
+ * If the leader fails to heartbeat within this time, another instance can take over.
6
+ * @default 15000
7
+ */
8
+ leaseDurationMs?: number;
9
+ /**
10
+ * Interval in milliseconds between heartbeats sent by the leader.
11
+ * Should be significantly less than leaseDurationMs (typically 1/3).
12
+ * @default 5000
13
+ */
14
+ heartbeatIntervalMs?: number;
15
+ /**
16
+ * Name of the MongoDB collection used for leader election.
17
+ * @default "_flink_leader"
18
+ */
19
+ collectionName?: string;
20
+ }
21
+ export declare class LeaderElection {
22
+ private instanceId;
23
+ private _isLeader;
24
+ private timer;
25
+ private collection;
26
+ private leaseDurationMs;
27
+ private heartbeatIntervalMs;
28
+ private onBecameLeader?;
29
+ private onLostLeadership?;
30
+ private stopped;
31
+ private transitioning;
32
+ constructor(db: Db, opts?: LeaderElectionOptions);
33
+ get isLeader(): boolean;
34
+ /**
35
+ * Start the leader election process.
36
+ * @param onBecameLeader Called when this instance becomes the leader
37
+ * @param onLostLeadership Called when this instance loses leadership
38
+ */
39
+ start(onBecameLeader: () => void | Promise<void>, onLostLeadership: () => void | Promise<void>): Promise<void>;
40
+ /**
41
+ * Stop the leader election and release leadership if held.
42
+ */
43
+ stop(): Promise<void>;
44
+ private tryClaimLeadership;
45
+ }
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.LeaderElection = void 0;
40
+ var uuid_1 = require("uuid");
41
+ var FlinkLogFactory_1 = require("./FlinkLogFactory");
42
+ var log = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.scheduler");
43
+ var LOCK_NAME = "job-scheduler";
44
+ var LeaderElection = /** @class */ (function () {
45
+ function LeaderElection(db, opts) {
46
+ this.instanceId = (0, uuid_1.v4)();
47
+ this._isLeader = false;
48
+ this.timer = null;
49
+ this.stopped = false;
50
+ this.transitioning = false;
51
+ var collectionName = (opts === null || opts === void 0 ? void 0 : opts.collectionName) || "_flink_leader";
52
+ this.leaseDurationMs = (opts === null || opts === void 0 ? void 0 : opts.leaseDurationMs) || 15000;
53
+ this.heartbeatIntervalMs = (opts === null || opts === void 0 ? void 0 : opts.heartbeatIntervalMs) || 5000;
54
+ this.collection = db.collection(collectionName);
55
+ }
56
+ Object.defineProperty(LeaderElection.prototype, "isLeader", {
57
+ get: function () {
58
+ return this._isLeader;
59
+ },
60
+ enumerable: false,
61
+ configurable: true
62
+ });
63
+ /**
64
+ * Start the leader election process.
65
+ * @param onBecameLeader Called when this instance becomes the leader
66
+ * @param onLostLeadership Called when this instance loses leadership
67
+ */
68
+ LeaderElection.prototype.start = function (onBecameLeader, onLostLeadership) {
69
+ return __awaiter(this, void 0, void 0, function () {
70
+ var ttlSeconds, err_1;
71
+ return __generator(this, function (_a) {
72
+ switch (_a.label) {
73
+ case 0:
74
+ this.onBecameLeader = onBecameLeader;
75
+ this.onLostLeadership = onLostLeadership;
76
+ this.stopped = false;
77
+ ttlSeconds = Math.ceil((this.leaseDurationMs * 2) / 1000);
78
+ _a.label = 1;
79
+ case 1:
80
+ _a.trys.push([1, 3, , 8]);
81
+ return [4 /*yield*/, this.collection.createIndex({ lastHeartbeat: 1 }, { expireAfterSeconds: ttlSeconds })];
82
+ case 2:
83
+ _a.sent();
84
+ return [3 /*break*/, 8];
85
+ case 3:
86
+ err_1 = _a.sent();
87
+ if (!(err_1.codeName === "IndexOptionsConflict" || err_1.code === 85)) return [3 /*break*/, 6];
88
+ log.debug("TTL index options changed, recreating index");
89
+ return [4 /*yield*/, this.collection.dropIndex("lastHeartbeat_1")];
90
+ case 4:
91
+ _a.sent();
92
+ return [4 /*yield*/, this.collection.createIndex({ lastHeartbeat: 1 }, { expireAfterSeconds: ttlSeconds })];
93
+ case 5:
94
+ _a.sent();
95
+ return [3 /*break*/, 7];
96
+ case 6: throw err_1;
97
+ case 7: return [3 /*break*/, 8];
98
+ case 8:
99
+ log.info("Leader election started (instance: ".concat(this.instanceId.substring(0, 8), ")"));
100
+ // Run first election attempt immediately
101
+ return [4 /*yield*/, this.tryClaimLeadership()];
102
+ case 9:
103
+ // Run first election attempt immediately
104
+ _a.sent();
105
+ return [2 /*return*/];
106
+ }
107
+ });
108
+ });
109
+ };
110
+ /**
111
+ * Stop the leader election and release leadership if held.
112
+ */
113
+ LeaderElection.prototype.stop = function () {
114
+ return __awaiter(this, void 0, void 0, function () {
115
+ var err_2;
116
+ return __generator(this, function (_a) {
117
+ switch (_a.label) {
118
+ case 0:
119
+ this.stopped = true;
120
+ if (this.timer) {
121
+ clearTimeout(this.timer);
122
+ this.timer = null;
123
+ }
124
+ if (!this._isLeader) return [3 /*break*/, 5];
125
+ _a.label = 1;
126
+ case 1:
127
+ _a.trys.push([1, 3, , 4]);
128
+ return [4 /*yield*/, this.collection.deleteOne({
129
+ _id: LOCK_NAME,
130
+ instanceId: this.instanceId,
131
+ })];
132
+ case 2:
133
+ _a.sent();
134
+ log.info("Leadership released on shutdown");
135
+ return [3 /*break*/, 4];
136
+ case 3:
137
+ err_2 = _a.sent();
138
+ log.error("Failed to release leadership on shutdown: ".concat(err_2));
139
+ return [3 /*break*/, 4];
140
+ case 4:
141
+ this._isLeader = false;
142
+ _a.label = 5;
143
+ case 5: return [2 /*return*/];
144
+ }
145
+ });
146
+ });
147
+ };
148
+ LeaderElection.prototype.tryClaimLeadership = function () {
149
+ return __awaiter(this, void 0, void 0, function () {
150
+ var now, leaseExpiry, result, gotLock, err_3, err_4, err_5, cbErr_1, cbErr_2, nextInterval;
151
+ var _this = this;
152
+ var _a, _b, _c, _d;
153
+ return __generator(this, function (_e) {
154
+ switch (_e.label) {
155
+ case 0:
156
+ if (this.stopped || this.transitioning)
157
+ return [2 /*return*/];
158
+ now = new Date();
159
+ leaseExpiry = new Date(now.getTime() - this.leaseDurationMs);
160
+ _e.label = 1;
161
+ case 1:
162
+ _e.trys.push([1, 14, , 24]);
163
+ return [4 /*yield*/, this.collection.findOneAndUpdate({
164
+ _id: LOCK_NAME,
165
+ $or: [
166
+ { instanceId: this.instanceId },
167
+ { lastHeartbeat: { $lt: leaseExpiry } },
168
+ ],
169
+ }, {
170
+ $set: {
171
+ instanceId: this.instanceId,
172
+ lastHeartbeat: now,
173
+ },
174
+ $setOnInsert: {
175
+ claimedAt: now,
176
+ },
177
+ }, { upsert: true, returnDocument: "after" })];
178
+ case 2:
179
+ result = _e.sent();
180
+ gotLock = result && result.instanceId === this.instanceId;
181
+ if (!(gotLock && !this._isLeader)) return [3 /*break*/, 8];
182
+ log.info("This instance became the leader (instance: ".concat(this.instanceId.substring(0, 8), ")"));
183
+ this._isLeader = true;
184
+ this.transitioning = true;
185
+ _e.label = 3;
186
+ case 3:
187
+ _e.trys.push([3, 5, 6, 7]);
188
+ return [4 /*yield*/, ((_a = this.onBecameLeader) === null || _a === void 0 ? void 0 : _a.call(this))];
189
+ case 4:
190
+ _e.sent();
191
+ return [3 /*break*/, 7];
192
+ case 5:
193
+ err_3 = _e.sent();
194
+ log.error("Error in onBecameLeader callback: ".concat(err_3));
195
+ return [3 /*break*/, 7];
196
+ case 6:
197
+ this.transitioning = false;
198
+ return [7 /*endfinally*/];
199
+ case 7: return [3 /*break*/, 13];
200
+ case 8:
201
+ if (!(!gotLock && this._isLeader)) return [3 /*break*/, 13];
202
+ log.warn("This instance lost leadership (instance: ".concat(this.instanceId.substring(0, 8), ")"));
203
+ this._isLeader = false;
204
+ this.transitioning = true;
205
+ _e.label = 9;
206
+ case 9:
207
+ _e.trys.push([9, 11, 12, 13]);
208
+ return [4 /*yield*/, ((_b = this.onLostLeadership) === null || _b === void 0 ? void 0 : _b.call(this))];
209
+ case 10:
210
+ _e.sent();
211
+ return [3 /*break*/, 13];
212
+ case 11:
213
+ err_4 = _e.sent();
214
+ log.error("Error in onLostLeadership callback: ".concat(err_4));
215
+ return [3 /*break*/, 13];
216
+ case 12:
217
+ this.transitioning = false;
218
+ return [7 /*endfinally*/];
219
+ case 13: return [3 /*break*/, 24];
220
+ case 14:
221
+ err_5 = _e.sent();
222
+ if (!(err_5.code === 11000)) return [3 /*break*/, 19];
223
+ if (!this._isLeader) return [3 /*break*/, 18];
224
+ log.warn("This instance lost leadership (instance: ".concat(this.instanceId.substring(0, 8), ")"));
225
+ this._isLeader = false;
226
+ _e.label = 15;
227
+ case 15:
228
+ _e.trys.push([15, 17, , 18]);
229
+ return [4 /*yield*/, ((_c = this.onLostLeadership) === null || _c === void 0 ? void 0 : _c.call(this))];
230
+ case 16:
231
+ _e.sent();
232
+ return [3 /*break*/, 18];
233
+ case 17:
234
+ cbErr_1 = _e.sent();
235
+ log.error("Error in onLostLeadership callback: ".concat(cbErr_1));
236
+ return [3 /*break*/, 18];
237
+ case 18: return [3 /*break*/, 23];
238
+ case 19:
239
+ log.error("Leader election error: ".concat(err_5));
240
+ if (!this._isLeader) return [3 /*break*/, 23];
241
+ this._isLeader = false;
242
+ _e.label = 20;
243
+ case 20:
244
+ _e.trys.push([20, 22, , 23]);
245
+ return [4 /*yield*/, ((_d = this.onLostLeadership) === null || _d === void 0 ? void 0 : _d.call(this))];
246
+ case 21:
247
+ _e.sent();
248
+ return [3 /*break*/, 23];
249
+ case 22:
250
+ cbErr_2 = _e.sent();
251
+ log.error("Error in onLostLeadership callback: ".concat(cbErr_2));
252
+ return [3 /*break*/, 23];
253
+ case 23: return [3 /*break*/, 24];
254
+ case 24:
255
+ // Schedule next attempt
256
+ if (!this.stopped) {
257
+ nextInterval = this._isLeader
258
+ ? this.heartbeatIntervalMs
259
+ : this.heartbeatIntervalMs * 2;
260
+ this.timer = setTimeout(function () { return _this.tryClaimLeadership(); }, nextInterval);
261
+ }
262
+ return [2 /*return*/];
263
+ }
264
+ });
265
+ });
266
+ };
267
+ return LeaderElection;
268
+ }());
269
+ exports.LeaderElection = LeaderElection;
@@ -0,0 +1,84 @@
1
+ import type { JSONSchema7 } from 'json-schema';
2
+ /**
3
+ * Cache entry for a single schema
4
+ */
5
+ export interface SchemaCacheEntry {
6
+ schemaName: string;
7
+ schemaFile: string;
8
+ contentHash: string;
9
+ dependencyHashes: Record<string, string>;
10
+ jsonSchema: JSONSchema7;
11
+ generatedAt: string;
12
+ }
13
+ /**
14
+ * Cache file format
15
+ */
16
+ export interface SchemaCacheFile {
17
+ version: string;
18
+ tsVersion: string;
19
+ generated: string;
20
+ entries: Record<string, SchemaCacheEntry>;
21
+ }
22
+ /**
23
+ * Manages persistent caching of generated JSON schemas
24
+ */
25
+ export declare class SchemaCache {
26
+ private projectRoot;
27
+ private static CACHE_VERSION;
28
+ private cacheFile;
29
+ private entries;
30
+ private dirty;
31
+ constructor(projectRoot: string);
32
+ /**
33
+ * Compute SHA-256 hash of file content
34
+ */
35
+ static hashFile(filePath: string): Promise<string>;
36
+ /**
37
+ * Compute SHA-256 hash of string content
38
+ */
39
+ static hashContent(content: string): string;
40
+ /**
41
+ * Load cache from disk
42
+ */
43
+ load(): Promise<void>;
44
+ /**
45
+ * Save cache to disk
46
+ */
47
+ save(): Promise<void>;
48
+ /**
49
+ * Get cached entry for schema
50
+ */
51
+ get(schemaName: string): SchemaCacheEntry | undefined;
52
+ /**
53
+ * Add or update cache entry
54
+ */
55
+ set(entry: SchemaCacheEntry): void;
56
+ /**
57
+ * Remove cache entry
58
+ */
59
+ delete(schemaName: string): void;
60
+ /**
61
+ * Clear all cache entries
62
+ */
63
+ clear(): void;
64
+ /**
65
+ * Check if schema needs regeneration
66
+ * Returns { needed: boolean, reason?: string }
67
+ */
68
+ needsRegeneration(schemaName: string, schemaFile: string, dependencies: Map<string, string>): Promise<{
69
+ needed: boolean;
70
+ reason?: string;
71
+ }>;
72
+ /**
73
+ * Get TypeScript version (major.minor)
74
+ */
75
+ private getTsVersion;
76
+ /**
77
+ * Get cache statistics
78
+ */
79
+ getStats(): {
80
+ totalEntries: number;
81
+ oldestEntry?: string;
82
+ newestEntry?: string;
83
+ };
84
+ }