@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.
- package/CHANGELOG.md +1051 -0
- package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
- package/SIMPLE_AST_FEASIBILITY.md +570 -0
- package/bin/flink.ts +13 -2
- package/cli/build.ts +24 -44
- package/cli/clean.ts +13 -25
- package/cli/cli-utils.ts +190 -17
- package/cli/dev.ts +252 -0
- package/cli/loadEnvFiles.ts +116 -0
- package/cli/run.ts +45 -62
- package/dist/bin/flink.js +61 -2
- package/dist/cli/build.js +20 -25
- package/dist/cli/clean.js +12 -10
- package/dist/cli/cli-utils.d.ts +34 -3
- package/dist/cli/cli-utils.js +193 -12
- package/dist/cli/dev.d.ts +2 -0
- package/dist/cli/dev.js +279 -0
- package/dist/cli/loadEnvFiles.d.ts +30 -0
- package/dist/cli/loadEnvFiles.js +113 -0
- package/dist/cli/run.js +47 -46
- package/dist/src/DependencyTracker.d.ts +44 -0
- package/dist/src/DependencyTracker.js +239 -0
- package/dist/src/FlinkApp.d.ts +163 -10
- package/dist/src/FlinkApp.js +847 -184
- package/dist/src/FlinkContext.d.ts +41 -0
- package/dist/src/FlinkErrors.d.ts +19 -6
- package/dist/src/FlinkErrors.js +36 -42
- package/dist/src/FlinkHttpHandler.d.ts +219 -26
- package/dist/src/FlinkHttpHandler.js +37 -1
- package/dist/src/FlinkJob.d.ts +10 -0
- package/dist/src/FlinkLog.d.ts +82 -18
- package/dist/src/FlinkLog.js +165 -13
- package/dist/src/FlinkLogFactory.d.ts +288 -0
- package/dist/src/FlinkLogFactory.js +619 -0
- package/dist/src/FlinkRepo.d.ts +10 -2
- package/dist/src/FlinkRepo.js +11 -1
- package/dist/src/FlinkRequestContext.d.ts +63 -0
- package/dist/src/FlinkRequestContext.js +74 -0
- package/dist/src/FlinkResponse.d.ts +6 -0
- package/dist/src/FlinkService.d.ts +38 -0
- package/dist/src/FlinkService.js +46 -0
- package/dist/src/LeaderElection.d.ts +45 -0
- package/dist/src/LeaderElection.js +269 -0
- package/dist/src/SchemaCache.d.ts +84 -0
- package/dist/src/SchemaCache.js +289 -0
- package/dist/src/TypeScriptCompiler.d.ts +161 -51
- package/dist/src/TypeScriptCompiler.js +1253 -617
- package/dist/src/TypeScriptUtils.js +4 -0
- package/dist/src/ai/AgentRunner.d.ts +39 -0
- package/dist/src/ai/AgentRunner.js +760 -0
- package/dist/src/ai/ConversationAgent.d.ts +279 -0
- package/dist/src/ai/ConversationAgent.js +404 -0
- package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
- package/dist/src/ai/ConversationFlinkAgent.js +404 -0
- package/dist/src/ai/FlinkAgent.d.ts +690 -0
- package/dist/src/ai/FlinkAgent.js +729 -0
- package/dist/src/ai/FlinkTool.d.ts +135 -0
- package/dist/src/ai/FlinkTool.js +2 -0
- package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
- package/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/dist/src/ai/LLMAdapter.d.ts +148 -0
- package/dist/src/ai/LLMAdapter.js +2 -0
- package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
- package/dist/src/ai/PersistentFlinkAgent.js +403 -0
- package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
- package/dist/src/ai/SubAgentExecutor.js +223 -0
- package/dist/src/ai/ToolExecutor.d.ts +64 -0
- package/dist/src/ai/ToolExecutor.js +497 -0
- package/dist/src/ai/agentInstructions.d.ts +68 -0
- package/dist/src/ai/agentInstructions.js +286 -0
- package/dist/src/ai/index.d.ts +8 -0
- package/dist/src/ai/index.js +26 -0
- package/dist/src/ai/instructionFileLoader.d.ts +44 -0
- package/dist/src/ai/instructionFileLoader.js +179 -0
- package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
- package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
- package/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +17 -0
- package/dist/src/loadPluginSchemas.d.ts +45 -0
- package/dist/src/loadPluginSchemas.js +143 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
- package/dist/src/schema-extraction/index.d.ts +2 -0
- package/dist/src/schema-extraction/index.js +20 -0
- package/dist/src/schema-extraction/types.d.ts +31 -0
- package/dist/src/schema-extraction/types.js +2 -0
- package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
- package/dist/src/utils/loadFlinkConfig.js +77 -0
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.js +52 -0
- package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
- package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
- package/dist/src/workers/WorkerPool.d.ts +60 -0
- package/dist/src/workers/WorkerPool.js +306 -0
- package/examples/logging-hierarchical-example.ts +125 -0
- package/package.json +29 -4
- package/readme.md +499 -0
- package/spec/AgentDescendantDetection.spec.ts +335 -0
- package/spec/AgentDuplicateDetection.spec.ts +112 -0
- package/spec/AgentObserver.spec.ts +266 -0
- package/spec/AgentRunner.spec.ts +1062 -0
- package/spec/AsyncLocalStorageContext.spec.ts +223 -0
- package/spec/ConversationHooks.spec.ts +257 -0
- package/spec/FlinkAgent.spec.ts +681 -0
- package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
- package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
- package/spec/FlinkApp.onError.spec.ts +1 -2
- package/spec/FlinkApp.query.spec.ts +107 -0
- package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
- package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
- package/spec/FlinkApp.validationMode.spec.ts +155 -0
- package/spec/FlinkJob.spec.ts +171 -0
- package/spec/FlinkLogFactory.spec.ts +337 -0
- package/spec/FlinkRepo.spec.ts +1 -1
- package/spec/LeaderElection.spec.ts +174 -0
- package/spec/StreamingIntegration.spec.ts +139 -0
- package/spec/ToolExecutor.spec.ts +465 -0
- package/spec/TypeScriptCompiler.spec.ts +1 -1
- package/spec/TypeScriptSourceParser.spec.ts +1215 -0
- package/spec/TypeScriptTokenizer.spec.ts +366 -0
- package/spec/ai/ContextCompaction.spec.ts +405 -0
- package/spec/ai/ConversationAgent.spec.ts +520 -0
- package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
- package/spec/ai/agentInstructions.spec.ts +358 -0
- package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
- package/spec/fixtures/agent-instructions/simple.md +3 -0
- package/spec/fixtures/agent-instructions/template.md +18 -0
- package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
- package/spec/mock-project/dist/.tsbuildinfo +1 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
- package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
- package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
- package/spec/mock-project/dist/src/FlinkContext.js +2 -0
- package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
- package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
- package/spec/mock-project/dist/src/FlinkJob.js +2 -0
- package/spec/mock-project/dist/src/FlinkLog.js +119 -0
- package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
- package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
- package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
- package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
- package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
- package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
- package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
- package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
- package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
- package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
- package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
- package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
- package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
- package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
- package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
- package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
- package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
- package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
- package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/spec/mock-project/dist/src/index.js +52 -76
- package/spec/mock-project/dist/src/index.js.map +1 -0
- package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
- package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
- package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/Car.js +3 -1
- package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
- package/spec/mock-project/dist/src/utils.js +290 -0
- package/spec/mock-project/tsconfig.json +6 -1
- package/spec/schema-generation-nested-objects.spec.ts +97 -0
- package/spec/testHelpers.ts +49 -0
- package/spec/utils.caseConversion.spec.ts +78 -0
- package/spec/utils.spec.ts +13 -13
- package/src/DependencyTracker.ts +166 -0
- package/src/FlinkApp.ts +919 -155
- package/src/FlinkContext.ts +43 -0
- package/src/FlinkErrors.ts +32 -12
- package/src/FlinkHttpHandler.ts +246 -28
- package/src/FlinkJob.ts +11 -0
- package/src/FlinkLog.ts +119 -12
- package/src/FlinkLogFactory.ts +699 -0
- package/src/FlinkRepo.ts +10 -3
- package/src/FlinkRequestContext.ts +95 -0
- package/src/FlinkResponse.ts +6 -0
- package/src/FlinkService.ts +49 -0
- package/src/LeaderElection.ts +203 -0
- package/src/SchemaCache.ts +232 -0
- package/src/TypeScriptCompiler.ts +1347 -610
- package/src/TypeScriptUtils.ts +5 -0
- package/src/ai/AgentRunner.ts +646 -0
- package/src/ai/ConversationAgent.ts +413 -0
- package/src/ai/FlinkAgent.ts +1069 -0
- package/src/ai/FlinkTool.ts +165 -0
- package/src/ai/InMemoryConversationAgent.ts +149 -0
- package/src/ai/LLMAdapter.ts +126 -0
- package/src/ai/ToolExecutor.ts +485 -0
- package/src/ai/agentInstructions.ts +245 -0
- package/src/ai/index.ts +8 -0
- package/src/ai/instructionFileLoader.ts +156 -0
- package/src/auth/FlinkAuthPlugin.ts +2 -1
- package/src/handlers/StreamWriterFactory.ts +84 -0
- package/src/index.ts +14 -0
- package/src/loadPluginSchemas.ts +141 -0
- package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
- package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
- package/src/schema-extraction/index.ts +2 -0
- package/src/schema-extraction/types.ts +34 -0
- package/src/utils/loadFlinkConfig.ts +89 -0
- package/src/utils.ts +52 -0
- 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
|
+
}
|