@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
package/dist/src/FlinkApp.js
CHANGED
|
@@ -50,7 +50,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
50
50
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
51
|
};
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
-
exports.FlinkApp = exports.autoRegisteredJobs = exports.autoRegisteredRepos = exports.autoRegisteredHandlers = exports.expressFn = void 0;
|
|
53
|
+
exports.FlinkApp = exports.autoRegisteredServices = exports.autoRegisteredAgents = exports.autoRegisteredTools = exports.autoRegisteredJobs = exports.autoRegisteredRepos = exports.autoRegisteredHandlers = exports.expressFn = void 0;
|
|
54
54
|
var ajv_1 = __importDefault(require("ajv"));
|
|
55
55
|
var ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
56
56
|
var body_parser_1 = __importDefault(require("body-parser"));
|
|
@@ -62,9 +62,17 @@ var ms_1 = __importDefault(require("ms"));
|
|
|
62
62
|
var toad_scheduler_1 = require("toad-scheduler");
|
|
63
63
|
var uuid_1 = require("uuid");
|
|
64
64
|
var FlinkErrors_1 = require("./FlinkErrors");
|
|
65
|
+
var FlinkHttpHandler_1 = require("./FlinkHttpHandler");
|
|
66
|
+
var LeaderElection_1 = require("./LeaderElection");
|
|
65
67
|
var FlinkLog_1 = require("./FlinkLog");
|
|
68
|
+
var FlinkLogFactory_1 = require("./FlinkLogFactory");
|
|
69
|
+
var FlinkRequestContext_1 = require("./FlinkRequestContext");
|
|
70
|
+
var StreamWriterFactory_1 = require("./handlers/StreamWriterFactory");
|
|
66
71
|
var mock_data_generator_1 = __importDefault(require("./mock-data-generator"));
|
|
67
72
|
var utils_1 = require("./utils");
|
|
73
|
+
var initLog = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.init");
|
|
74
|
+
var perfLog = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.perf");
|
|
75
|
+
var schedulerLog = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.scheduler");
|
|
68
76
|
var ajv = new ajv_1.default();
|
|
69
77
|
(0, ajv_formats_1.default)(ajv);
|
|
70
78
|
var defaultCorsOptions = {
|
|
@@ -92,8 +100,24 @@ exports.autoRegisteredRepos = [];
|
|
|
92
100
|
* are picked up by TypeScript compiler
|
|
93
101
|
*/
|
|
94
102
|
exports.autoRegisteredJobs = [];
|
|
103
|
+
/**
|
|
104
|
+
* This will be populated at compile time when the apps tools
|
|
105
|
+
* are picked up by TypeScript compiler
|
|
106
|
+
*/
|
|
107
|
+
exports.autoRegisteredTools = [];
|
|
108
|
+
/**
|
|
109
|
+
* This will be populated at compile time when the apps agents
|
|
110
|
+
* are picked up by TypeScript compiler
|
|
111
|
+
*/
|
|
112
|
+
exports.autoRegisteredAgents = [];
|
|
113
|
+
/**
|
|
114
|
+
* This will be populated at compile time when the apps services
|
|
115
|
+
* are picked up by TypeScript compiler
|
|
116
|
+
*/
|
|
117
|
+
exports.autoRegisteredServices = [];
|
|
95
118
|
var FlinkApp = /** @class */ (function () {
|
|
96
119
|
function FlinkApp(opts) {
|
|
120
|
+
var _a, _b;
|
|
97
121
|
this.handlers = [];
|
|
98
122
|
this.started = false;
|
|
99
123
|
this.debug = false;
|
|
@@ -101,10 +125,18 @@ var FlinkApp = /** @class */ (function () {
|
|
|
101
125
|
this.routingConfigured = false;
|
|
102
126
|
this.disableHttpServer = false;
|
|
103
127
|
this.repos = {};
|
|
128
|
+
this.services = {};
|
|
129
|
+
this.llmAdapters = new Map();
|
|
130
|
+
this.tools = {};
|
|
131
|
+
this.agents = {}; // FlinkAgent<C> instances
|
|
104
132
|
/**
|
|
105
133
|
* Internal cache used to track registered handlers and potentially any overlapping routes
|
|
106
134
|
*/
|
|
107
135
|
this.handlerRouteCache = new Map();
|
|
136
|
+
// Load config file and initialize logging
|
|
137
|
+
var loadFlinkConfig = require("./utils/loadFlinkConfig").loadFlinkConfig;
|
|
138
|
+
var flinkConfig = loadFlinkConfig();
|
|
139
|
+
FlinkLogFactory_1.FlinkLogFactory.configure(flinkConfig === null || flinkConfig === void 0 ? void 0 : flinkConfig.logging);
|
|
108
140
|
this.name = opts.name;
|
|
109
141
|
this.port = opts.port || 3333;
|
|
110
142
|
this.dbOpts = opts.db;
|
|
@@ -123,6 +155,13 @@ var FlinkApp = /** @class */ (function () {
|
|
|
123
155
|
this.disableHttpServer = !!opts.disableHttpServer;
|
|
124
156
|
this.accessLog = __assign({ enabled: true, format: "dev" }, opts.accessLog);
|
|
125
157
|
this.onError = opts.onError;
|
|
158
|
+
// Register LLM adapters if configured
|
|
159
|
+
if ((_a = opts.ai) === null || _a === void 0 ? void 0 : _a.llms) {
|
|
160
|
+
// Convert plain object to Map for internal use
|
|
161
|
+
this.llmAdapters = new Map(Object.entries(opts.ai.llms));
|
|
162
|
+
}
|
|
163
|
+
// Register global agent observer if configured
|
|
164
|
+
this.agentObserver = (_b = opts.ai) === null || _b === void 0 ? void 0 : _b.observer;
|
|
126
165
|
}
|
|
127
166
|
Object.defineProperty(FlinkApp.prototype, "ctx", {
|
|
128
167
|
get: function () {
|
|
@@ -136,33 +175,43 @@ var FlinkApp = /** @class */ (function () {
|
|
|
136
175
|
});
|
|
137
176
|
FlinkApp.prototype.start = function () {
|
|
138
177
|
return __awaiter(this, void 0, void 0, function () {
|
|
139
|
-
var startTime,
|
|
178
|
+
var startTime, dbStartTime, contextStartTime, toolsStartTime, agentsStartTime, agentInitStartTime, _i, _a, type, pluginsStartTime, _b, _c, plugin, db, handlersStartTime, jobsStartTime, totalStartTime;
|
|
140
179
|
var _this = this;
|
|
141
180
|
var _d;
|
|
142
181
|
return __generator(this, function (_e) {
|
|
143
182
|
switch (_e.label) {
|
|
144
183
|
case 0:
|
|
145
184
|
startTime = Date.now();
|
|
146
|
-
|
|
185
|
+
dbStartTime = Date.now();
|
|
147
186
|
return [4 /*yield*/, this.initDb()];
|
|
148
187
|
case 1:
|
|
149
188
|
_e.sent();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
FlinkLog_1.log.bgColorLog("cyan", "Init db took ".concat(offsetTime - startTime, " ms"));
|
|
153
|
-
}
|
|
189
|
+
perfLog.debug("Init db took ".concat(Date.now() - dbStartTime, "ms"));
|
|
190
|
+
contextStartTime = Date.now();
|
|
154
191
|
return [4 /*yield*/, this.buildContext()];
|
|
155
192
|
case 2:
|
|
156
193
|
_e.sent();
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
194
|
+
perfLog.debug("Build context took ".concat(Date.now() - contextStartTime, "ms"));
|
|
195
|
+
toolsStartTime = Date.now();
|
|
196
|
+
return [4 /*yield*/, this.registerAutoRegisterableTools()];
|
|
197
|
+
case 3:
|
|
198
|
+
_e.sent();
|
|
199
|
+
perfLog.debug("Register tools took ".concat(Date.now() - toolsStartTime, "ms"));
|
|
200
|
+
agentsStartTime = Date.now();
|
|
201
|
+
return [4 /*yield*/, this.registerAutoRegisterableAgents()];
|
|
202
|
+
case 4:
|
|
203
|
+
_e.sent();
|
|
204
|
+
perfLog.debug("Register agents took ".concat(Date.now() - agentsStartTime, "ms"));
|
|
205
|
+
agentInitStartTime = Date.now();
|
|
206
|
+
return [4 /*yield*/, this.initializeAgents()];
|
|
207
|
+
case 5:
|
|
208
|
+
_e.sent();
|
|
209
|
+
perfLog.debug("Initialize agents took ".concat(Date.now() - agentInitStartTime, "ms"));
|
|
210
|
+
if (this.isSchedulingEnabled && !this.leaderElectionConfig) {
|
|
162
211
|
this.scheduler = new toad_scheduler_1.ToadScheduler();
|
|
163
212
|
}
|
|
164
|
-
else {
|
|
165
|
-
|
|
213
|
+
else if (!this.isSchedulingEnabled) {
|
|
214
|
+
schedulerLog.info("Scheduling is disabled");
|
|
166
215
|
}
|
|
167
216
|
if (!this.disableHttpServer) {
|
|
168
217
|
this.expressApp = (0, express_1.default)();
|
|
@@ -182,46 +231,53 @@ var FlinkApp = /** @class */ (function () {
|
|
|
182
231
|
next();
|
|
183
232
|
});
|
|
184
233
|
}
|
|
234
|
+
pluginsStartTime = Date.now();
|
|
185
235
|
_b = 0, _c = this.plugins;
|
|
186
|
-
_e.label =
|
|
187
|
-
case
|
|
188
|
-
if (!(_b < _c.length)) return [3 /*break*/,
|
|
236
|
+
_e.label = 6;
|
|
237
|
+
case 6:
|
|
238
|
+
if (!(_b < _c.length)) return [3 /*break*/, 12];
|
|
189
239
|
plugin = _c[_b];
|
|
190
240
|
db = void 0;
|
|
191
|
-
if (!plugin.db) return [3 /*break*/,
|
|
241
|
+
if (!plugin.db) return [3 /*break*/, 8];
|
|
192
242
|
return [4 /*yield*/, this.initPluginDb(plugin)];
|
|
193
|
-
case 4:
|
|
194
|
-
db = _e.sent();
|
|
195
|
-
_e.label = 5;
|
|
196
|
-
case 5:
|
|
197
|
-
if (!plugin.init) return [3 /*break*/, 7];
|
|
198
|
-
return [4 /*yield*/, plugin.init(this, db)];
|
|
199
|
-
case 6:
|
|
200
|
-
_e.sent();
|
|
201
|
-
_e.label = 7;
|
|
202
243
|
case 7:
|
|
203
|
-
|
|
244
|
+
db = _e.sent();
|
|
204
245
|
_e.label = 8;
|
|
205
246
|
case 8:
|
|
206
|
-
|
|
207
|
-
return [
|
|
208
|
-
case 9:
|
|
209
|
-
case 10:
|
|
247
|
+
if (!plugin.init) return [3 /*break*/, 10];
|
|
248
|
+
return [4 /*yield*/, plugin.init(this, db)];
|
|
249
|
+
case 9:
|
|
210
250
|
_e.sent();
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
251
|
+
_e.label = 10;
|
|
252
|
+
case 10:
|
|
253
|
+
initLog.info("Initialized plugin '".concat(plugin.id, "'"));
|
|
254
|
+
_e.label = 11;
|
|
255
|
+
case 11:
|
|
256
|
+
_b++;
|
|
257
|
+
return [3 /*break*/, 6];
|
|
258
|
+
case 12:
|
|
259
|
+
if (this.plugins.length > 0) {
|
|
260
|
+
perfLog.debug("Initialize plugins took ".concat(Date.now() - pluginsStartTime, "ms (").concat(this.plugins.length, " plugins)"));
|
|
214
261
|
}
|
|
215
|
-
|
|
262
|
+
handlersStartTime = Date.now();
|
|
263
|
+
return [4 /*yield*/, this.registerAutoRegisterableHandlers()];
|
|
264
|
+
case 13:
|
|
265
|
+
_e.sent();
|
|
266
|
+
perfLog.debug("Register handlers took ".concat(Date.now() - handlersStartTime, "ms"));
|
|
267
|
+
if (!this.isSchedulingEnabled) return [3 /*break*/, 17];
|
|
268
|
+
if (!this.leaderElectionConfig) return [3 /*break*/, 15];
|
|
269
|
+
return [4 /*yield*/, this.startLeaderElection()];
|
|
270
|
+
case 14:
|
|
271
|
+
_e.sent();
|
|
272
|
+
return [3 /*break*/, 17];
|
|
273
|
+
case 15:
|
|
274
|
+
jobsStartTime = Date.now();
|
|
216
275
|
return [4 /*yield*/, this.registerAutoRegisterableJobs()];
|
|
217
|
-
case
|
|
276
|
+
case 16:
|
|
218
277
|
_e.sent();
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
_e.label = 12;
|
|
224
|
-
case 12:
|
|
278
|
+
perfLog.debug("Register jobs took ".concat(Date.now() - jobsStartTime, "ms"));
|
|
279
|
+
_e.label = 17;
|
|
280
|
+
case 17:
|
|
225
281
|
// Register 404 with slight delay to allow all manually added routes to be added
|
|
226
282
|
// TODO: Is there a better solution to force this handler to always run last?
|
|
227
283
|
setTimeout(function () {
|
|
@@ -233,7 +289,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
233
289
|
_this.routingConfigured = true;
|
|
234
290
|
});
|
|
235
291
|
if (this.disableHttpServer) {
|
|
236
|
-
|
|
292
|
+
initLog.info("🚧 HTTP server is disabled, but flink app is running");
|
|
237
293
|
this.started = true;
|
|
238
294
|
}
|
|
239
295
|
else {
|
|
@@ -242,6 +298,8 @@ var FlinkApp = /** @class */ (function () {
|
|
|
242
298
|
_this.started = true;
|
|
243
299
|
});
|
|
244
300
|
}
|
|
301
|
+
totalStartTime = Date.now() - startTime;
|
|
302
|
+
perfLog.info("\u2713 FlinkApp started in ".concat(totalStartTime, "ms"));
|
|
245
303
|
return [2 /*return*/, this];
|
|
246
304
|
}
|
|
247
305
|
});
|
|
@@ -254,12 +312,24 @@ var FlinkApp = /** @class */ (function () {
|
|
|
254
312
|
switch (_a.label) {
|
|
255
313
|
case 0:
|
|
256
314
|
FlinkLog_1.log.info("🛑 Stopping Flink app...");
|
|
257
|
-
if (!this.
|
|
258
|
-
return [4 /*yield*/, this.
|
|
315
|
+
if (!this.leaderElection) return [3 /*break*/, 2];
|
|
316
|
+
return [4 /*yield*/, this.leaderElection.stop()];
|
|
259
317
|
case 1:
|
|
260
318
|
_a.sent();
|
|
261
319
|
_a.label = 2;
|
|
262
320
|
case 2:
|
|
321
|
+
if (!this.scheduler) return [3 /*break*/, 4];
|
|
322
|
+
return [4 /*yield*/, this.scheduler.stop()];
|
|
323
|
+
case 3:
|
|
324
|
+
_a.sent();
|
|
325
|
+
_a.label = 4;
|
|
326
|
+
case 4:
|
|
327
|
+
if (!this.allInstanceScheduler) return [3 /*break*/, 6];
|
|
328
|
+
return [4 /*yield*/, this.allInstanceScheduler.stop()];
|
|
329
|
+
case 5:
|
|
330
|
+
_a.sent();
|
|
331
|
+
_a.label = 6;
|
|
332
|
+
case 6:
|
|
263
333
|
if (this.expressServer) {
|
|
264
334
|
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
265
335
|
var int = setTimeout(function () {
|
|
@@ -284,7 +354,6 @@ var FlinkApp = /** @class */ (function () {
|
|
|
284
354
|
* which are derived from handler function type arguments.
|
|
285
355
|
*/
|
|
286
356
|
FlinkApp.prototype.addHandler = function (handler, routePropsOverride) {
|
|
287
|
-
var _a, _b, _c, _d, _e, _f;
|
|
288
357
|
if (this.routingConfigured) {
|
|
289
358
|
throw new Error("Cannot add handler after routes has been registered, make sure to invoke earlier");
|
|
290
359
|
}
|
|
@@ -303,28 +372,37 @@ var FlinkApp = /** @class */ (function () {
|
|
|
303
372
|
// TODO: Not sure if there is a case where you'd want to overwrite a route?
|
|
304
373
|
FlinkLog_1.log.warn("".concat(methodAndPath, " overlaps existing route"));
|
|
305
374
|
}
|
|
375
|
+
// Use direct schemas from routeProps if provided, otherwise fall back to manifest lookup
|
|
376
|
+
var reqSchema = routeProps.reqSchema;
|
|
377
|
+
var resSchema = routeProps.resSchema;
|
|
378
|
+
var queryMetadata = [];
|
|
379
|
+
var paramsMetadata = [];
|
|
380
|
+
if (!reqSchema || !resSchema) {
|
|
381
|
+
var schemaManifest = this.loadSchemaManifest();
|
|
382
|
+
var metadata = handler.__file ? schemaManifest.handlers[handler.__file] : undefined;
|
|
383
|
+
if (!reqSchema)
|
|
384
|
+
reqSchema = this.resolveSchema(metadata === null || metadata === void 0 ? void 0 : metadata.reqSchemaName);
|
|
385
|
+
if (!resSchema)
|
|
386
|
+
resSchema = this.resolveSchema(metadata === null || metadata === void 0 ? void 0 : metadata.resSchemaName);
|
|
387
|
+
queryMetadata = (metadata === null || metadata === void 0 ? void 0 : metadata.queryMetadata) || [];
|
|
388
|
+
paramsMetadata = (metadata === null || metadata === void 0 ? void 0 : metadata.paramsMetadata) || [];
|
|
389
|
+
}
|
|
306
390
|
var handlerConfig = {
|
|
307
391
|
routeProps: __assign(__assign({}, routeProps), { method: routeProps.method, path: routeProps.path }),
|
|
308
392
|
schema: {
|
|
309
|
-
reqSchema:
|
|
310
|
-
resSchema:
|
|
393
|
+
reqSchema: reqSchema,
|
|
394
|
+
resSchema: resSchema,
|
|
311
395
|
},
|
|
312
|
-
queryMetadata:
|
|
313
|
-
paramsMetadata:
|
|
396
|
+
queryMetadata: queryMetadata,
|
|
397
|
+
paramsMetadata: paramsMetadata,
|
|
314
398
|
};
|
|
315
|
-
if (((_c = handler.__schemas) === null || _c === void 0 ? void 0 : _c.reqSchema) && !((_d = handlerConfig.schema) === null || _d === void 0 ? void 0 : _d.reqSchema)) {
|
|
316
|
-
FlinkLog_1.log.warn("Expected request schema ".concat(handler.__schemas.reqSchema, " for handler ").concat(methodAndPath, " but no such schema was found"));
|
|
317
|
-
}
|
|
318
|
-
if (((_e = handler.__schemas) === null || _e === void 0 ? void 0 : _e.resSchema) && !((_f = handlerConfig.schema) === null || _f === void 0 ? void 0 : _f.resSchema)) {
|
|
319
|
-
FlinkLog_1.log.warn("Expected response schema ".concat(handler.__schemas.resSchema, " for handler ").concat(methodAndPath, " but no such schema was found"));
|
|
320
|
-
}
|
|
321
399
|
this.registerHandler(handlerConfig, handler.default);
|
|
322
400
|
};
|
|
323
401
|
FlinkApp.prototype.registerHandler = function (handlerConfig, handler) {
|
|
324
402
|
var _this = this;
|
|
325
403
|
this.handlers.push(handlerConfig);
|
|
326
404
|
var routeProps = handlerConfig.routeProps, _a = handlerConfig.schema, schema = _a === void 0 ? {} : _a;
|
|
327
|
-
var method = routeProps.method;
|
|
405
|
+
var method = routeProps.method, streamFormat = routeProps.streamFormat;
|
|
328
406
|
if (!method) {
|
|
329
407
|
FlinkLog_1.log.error("Route ".concat(routeProps.path, " is missing http method"));
|
|
330
408
|
}
|
|
@@ -335,41 +413,77 @@ var FlinkApp = /** @class */ (function () {
|
|
|
335
413
|
}
|
|
336
414
|
var validateReq_1;
|
|
337
415
|
var validateRes_1;
|
|
338
|
-
|
|
339
|
-
|
|
416
|
+
// Select AJV instance (use schemaAjv for v2.0 manifests, fallback to global ajv)
|
|
417
|
+
var ajvInstance = this.schemaAjv || ajv;
|
|
418
|
+
// Determine validation mode (default to Validate if not specified)
|
|
419
|
+
var validationMode = routeProps.validation || FlinkHttpHandler_1.ValidationMode.Validate;
|
|
420
|
+
// Compile request schema if validation mode requires it
|
|
421
|
+
if (schema.reqSchema && validationMode !== FlinkHttpHandler_1.ValidationMode.SkipValidation && validationMode !== FlinkHttpHandler_1.ValidationMode.ValidateResponse) {
|
|
422
|
+
// For v2.0 manifests with $id, use getSchema() if available
|
|
423
|
+
if (schema.reqSchema.$id && this.schemaAjv) {
|
|
424
|
+
validateReq_1 = this.schemaAjv.getSchema(schema.reqSchema.$id);
|
|
425
|
+
if (!validateReq_1) {
|
|
426
|
+
FlinkLog_1.log.warn("Schema ".concat(schema.reqSchema.$id, " not found in AJV registry, compiling inline"));
|
|
427
|
+
validateReq_1 = ajvInstance.compile(schema.reqSchema);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
validateReq_1 = ajvInstance.compile(schema.reqSchema);
|
|
432
|
+
}
|
|
340
433
|
}
|
|
341
|
-
|
|
342
|
-
|
|
434
|
+
// Skip response validation for streaming handlers (responses are stream chunks, not final JSON)
|
|
435
|
+
// Skip response validation for non-JSON response types (html, csv, etc.)
|
|
436
|
+
if (!streamFormat &&
|
|
437
|
+
!routeProps.responseType &&
|
|
438
|
+
schema.resSchema &&
|
|
439
|
+
validationMode !== FlinkHttpHandler_1.ValidationMode.SkipValidation &&
|
|
440
|
+
validationMode !== FlinkHttpHandler_1.ValidationMode.ValidateRequest) {
|
|
441
|
+
// For v2.0 manifests with $id, use getSchema() if available
|
|
442
|
+
if (schema.resSchema.$id && this.schemaAjv) {
|
|
443
|
+
validateRes_1 = this.schemaAjv.getSchema(schema.resSchema.$id);
|
|
444
|
+
if (!validateRes_1) {
|
|
445
|
+
FlinkLog_1.log.warn("Schema ".concat(schema.resSchema.$id, " not found in AJV registry, compiling inline"));
|
|
446
|
+
validateRes_1 = ajvInstance.compile(schema.resSchema);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
validateRes_1 = ajvInstance.compile(schema.resSchema);
|
|
451
|
+
}
|
|
343
452
|
}
|
|
344
453
|
this.expressApp[method](routeProps.path, function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
345
|
-
var valid, formattedErrors, data, handlerRes, err_1, errorResponse,
|
|
346
|
-
|
|
347
|
-
|
|
454
|
+
var valid, formattedErrors, errorResponse, data, normalizedQuery, _i, _a, _b, key, value, stream, handlerRes, flinkReq_1, err_1, errorResponse, detail, errorResponse, valid, formattedErrors, errorResponse;
|
|
455
|
+
var _this = this;
|
|
456
|
+
var _c;
|
|
457
|
+
return __generator(this, function (_d) {
|
|
458
|
+
switch (_d.label) {
|
|
348
459
|
case 0:
|
|
349
460
|
if (!routeProps.permissions) return [3 /*break*/, 2];
|
|
350
461
|
return [4 /*yield*/, this.authenticate(req, routeProps.permissions)];
|
|
351
462
|
case 1:
|
|
352
|
-
if (!(
|
|
463
|
+
if (!(_d.sent())) {
|
|
353
464
|
return [2 /*return*/, res.status(401).json((0, FlinkErrors_1.unauthorized)())];
|
|
354
465
|
}
|
|
355
|
-
|
|
466
|
+
_d.label = 2;
|
|
356
467
|
case 2:
|
|
357
468
|
if (validateReq_1) {
|
|
358
469
|
valid = validateReq_1(req.body);
|
|
359
470
|
if (!valid) {
|
|
360
471
|
formattedErrors = (0, utils_1.formatValidationErrors)(validateReq_1.errors, req.body);
|
|
361
472
|
FlinkLog_1.log.warn("[".concat(req.reqId, "] ").concat(methodAndRoute_1, ": Bad request\n").concat(formattedErrors));
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
473
|
+
errorResponse = {
|
|
474
|
+
status: 400,
|
|
475
|
+
error: {
|
|
476
|
+
id: (0, uuid_1.v4)(),
|
|
477
|
+
title: "Bad request",
|
|
478
|
+
detail: formattedErrors,
|
|
479
|
+
},
|
|
480
|
+
};
|
|
481
|
+
this.invokeOnError(errorResponse, req, method, routeProps.path);
|
|
482
|
+
return [2 /*return*/, res.status(400).json(errorResponse)];
|
|
370
483
|
}
|
|
371
484
|
}
|
|
372
|
-
|
|
485
|
+
// Skip mock API for streaming handlers
|
|
486
|
+
if (routeProps.mockApi && schema.resSchema && !streamFormat) {
|
|
373
487
|
FlinkLog_1.log.warn("Mock response for ".concat(req.method.toUpperCase(), " ").concat(req.path));
|
|
374
488
|
data = (0, mock_data_generator_1.default)(schema.resSchema);
|
|
375
489
|
res.status(200).json({
|
|
@@ -378,20 +492,66 @@ var FlinkApp = /** @class */ (function () {
|
|
|
378
492
|
});
|
|
379
493
|
return [2 /*return*/];
|
|
380
494
|
}
|
|
381
|
-
|
|
495
|
+
// Normalize query parameters to predictable string or string[] types
|
|
496
|
+
// Express query parser can produce numbers, booleans, objects, etc.
|
|
497
|
+
// We normalize everything to strings or string arrays for consistency
|
|
498
|
+
if (req.query && typeof req.query === "object") {
|
|
499
|
+
normalizedQuery = {};
|
|
500
|
+
for (_i = 0, _a = Object.entries(req.query); _i < _a.length; _i++) {
|
|
501
|
+
_b = _a[_i], key = _b[0], value = _b[1];
|
|
502
|
+
if (Array.isArray(value)) {
|
|
503
|
+
// Handle array values (e.g., ?tag=a&tag=b)
|
|
504
|
+
normalizedQuery[key] = value.map(function (v) { return String(v); });
|
|
505
|
+
}
|
|
506
|
+
else if (value !== undefined && value !== null) {
|
|
507
|
+
// Convert single values to strings
|
|
508
|
+
normalizedQuery[key] = String(value);
|
|
509
|
+
}
|
|
510
|
+
// Skip undefined/null values - they won't appear in the normalized query
|
|
511
|
+
}
|
|
512
|
+
req.query = normalizedQuery;
|
|
513
|
+
}
|
|
514
|
+
stream = streamFormat ? StreamWriterFactory_1.StreamWriterFactory.create(res, streamFormat) : undefined;
|
|
515
|
+
_d.label = 3;
|
|
382
516
|
case 3:
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
517
|
+
_d.trys.push([3, 5, , 6]);
|
|
518
|
+
flinkReq_1 = req;
|
|
519
|
+
return [4 /*yield*/, FlinkRequestContext_1.requestContext.run({
|
|
520
|
+
reqId: flinkReq_1.reqId,
|
|
521
|
+
user: flinkReq_1.user,
|
|
522
|
+
userPermissions: flinkReq_1.userPermissions,
|
|
523
|
+
method: method,
|
|
524
|
+
path: routeProps.path,
|
|
525
|
+
timestamp: Date.now(),
|
|
526
|
+
isStreaming: !!streamFormat,
|
|
527
|
+
}, function () { return __awaiter(_this, void 0, void 0, function () {
|
|
528
|
+
return __generator(this, function (_a) {
|
|
529
|
+
switch (_a.label) {
|
|
530
|
+
case 0: return [4 /*yield*/, handler({
|
|
531
|
+
req: flinkReq_1,
|
|
532
|
+
ctx: this.ctx,
|
|
533
|
+
origin: routeProps.origin,
|
|
534
|
+
stream: stream,
|
|
535
|
+
})];
|
|
536
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
}); })];
|
|
389
540
|
case 4:
|
|
390
|
-
|
|
391
|
-
handlerRes = _a.sent();
|
|
541
|
+
handlerRes = _d.sent();
|
|
392
542
|
return [3 /*break*/, 6];
|
|
393
543
|
case 5:
|
|
394
|
-
err_1 =
|
|
544
|
+
err_1 = _d.sent();
|
|
545
|
+
// Handle errors for streaming handlers
|
|
546
|
+
if (streamFormat && stream) {
|
|
547
|
+
FlinkLog_1.log.error("Streaming handler error on ".concat(req.method.toUpperCase(), " ").concat(req.path, ": ").concat(err_1.message), {
|
|
548
|
+
error: err_1,
|
|
549
|
+
path: req.path,
|
|
550
|
+
method: req.method,
|
|
551
|
+
});
|
|
552
|
+
stream.error(err_1);
|
|
553
|
+
return [2 /*return*/];
|
|
554
|
+
}
|
|
395
555
|
errorResponse = void 0;
|
|
396
556
|
// duck typing to check if it is a FlinkError
|
|
397
557
|
if (typeof err_1.status === "number" && err_1.status >= 400 && err_1.status < 600 && err_1.error) {
|
|
@@ -410,44 +570,64 @@ var FlinkApp = /** @class */ (function () {
|
|
|
410
570
|
console.error(err_1);
|
|
411
571
|
errorResponse = (0, FlinkErrors_1.internalServerError)(err_1);
|
|
412
572
|
}
|
|
413
|
-
|
|
414
|
-
if (this.onError) {
|
|
415
|
-
try {
|
|
416
|
-
result = this.onError(errorResponse, {
|
|
417
|
-
req: req,
|
|
418
|
-
method: method,
|
|
419
|
-
path: routeProps.path,
|
|
420
|
-
reqId: req.reqId,
|
|
421
|
-
});
|
|
422
|
-
// Handle async callbacks - don't wait for them
|
|
423
|
-
if (result instanceof Promise) {
|
|
424
|
-
result.catch(function (callbackErr) {
|
|
425
|
-
FlinkLog_1.log.error("onError callback rejected with: ".concat(callbackErr));
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
catch (callbackErr) {
|
|
430
|
-
FlinkLog_1.log.error("onError callback threw an exception: ".concat(callbackErr));
|
|
431
|
-
}
|
|
432
|
-
}
|
|
573
|
+
this.invokeOnError(errorResponse, req, method, routeProps.path);
|
|
433
574
|
return [2 /*return*/, res.status(errorResponse.status || 500).json(errorResponse)];
|
|
434
575
|
case 6:
|
|
576
|
+
// Skip response handling for streaming handlers (stream controls response lifecycle)
|
|
577
|
+
if (streamFormat) {
|
|
578
|
+
return [2 /*return*/];
|
|
579
|
+
}
|
|
580
|
+
// Ensure handlerRes is defined for non-streaming handlers
|
|
581
|
+
if (!handlerRes) {
|
|
582
|
+
return [2 /*return*/, res.status(204).send()];
|
|
583
|
+
}
|
|
435
584
|
if (validateRes_1 && !(0, utils_1.isError)(handlerRes)) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
585
|
+
if (handlerRes.data === undefined) {
|
|
586
|
+
if (handlerRes.status !== 204) {
|
|
587
|
+
detail = "Response schema is defined but handler returned no data";
|
|
588
|
+
FlinkLog_1.log.warn("[".concat(req.reqId, "] ").concat(methodAndRoute_1, ": Bad response - ").concat(detail));
|
|
589
|
+
errorResponse = {
|
|
590
|
+
status: 500,
|
|
591
|
+
error: { id: (0, uuid_1.v4)(), title: "Bad response", detail: detail },
|
|
592
|
+
};
|
|
593
|
+
this.invokeOnError(errorResponse, req, method, routeProps.path);
|
|
594
|
+
return [2 /*return*/, res.status(500).json(errorResponse)];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
valid = validateRes_1(JSON.parse(JSON.stringify(handlerRes.data)));
|
|
599
|
+
if (!valid) {
|
|
600
|
+
formattedErrors = (0, utils_1.formatValidationErrors)(validateRes_1.errors, handlerRes.data);
|
|
601
|
+
FlinkLog_1.log.warn("[".concat(req.reqId, "] ").concat(methodAndRoute_1, ": Bad response\n").concat(formattedErrors));
|
|
602
|
+
errorResponse = {
|
|
441
603
|
status: 500,
|
|
442
604
|
error: {
|
|
443
605
|
id: (0, uuid_1.v4)(),
|
|
444
606
|
title: "Bad response",
|
|
445
607
|
detail: formattedErrors,
|
|
446
608
|
},
|
|
447
|
-
}
|
|
609
|
+
};
|
|
610
|
+
this.invokeOnError(errorResponse, req, method, routeProps.path);
|
|
611
|
+
return [2 /*return*/, res.status(500).json(errorResponse)];
|
|
612
|
+
}
|
|
448
613
|
}
|
|
449
614
|
}
|
|
450
615
|
res.set(handlerRes.headers);
|
|
616
|
+
if (routeProps.responseType) {
|
|
617
|
+
return [2 /*return*/, res
|
|
618
|
+
.status(handlerRes.status || 200)
|
|
619
|
+
.type(routeProps.responseType)
|
|
620
|
+
.send(handlerRes.data)];
|
|
621
|
+
}
|
|
622
|
+
if (((_c = handlerRes.error) === null || _c === void 0 ? void 0 : _c.meta) !== undefined) {
|
|
623
|
+
try {
|
|
624
|
+
JSON.stringify(handlerRes.error.meta);
|
|
625
|
+
}
|
|
626
|
+
catch (e) {
|
|
627
|
+
FlinkLog_1.log.warn("[".concat(handlerRes.reqId, "] error.meta stripped from error ").concat(handlerRes.error.id, ": not JSON-serializable (").concat(e.message, ")"));
|
|
628
|
+
delete handlerRes.error.meta;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
451
631
|
res.status(handlerRes.status || 200).json(handlerRes);
|
|
452
632
|
return [2 /*return*/];
|
|
453
633
|
}
|
|
@@ -459,9 +639,174 @@ var FlinkApp = /** @class */ (function () {
|
|
|
459
639
|
}
|
|
460
640
|
else {
|
|
461
641
|
this.handlerRouteCache.set(methodAndRoute_1, JSON.stringify(routeProps));
|
|
462
|
-
|
|
642
|
+
initLog.info("Registered ".concat(streamFormat ? "streaming " : "", "route ").concat(methodAndRoute_1).concat(streamFormat ? " (".concat(streamFormat, ")") : ""));
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
/**
|
|
647
|
+
* Load schema manifest from .flink directory.
|
|
648
|
+
* Returns empty structure if manifest doesn't exist (dev mode without build).
|
|
649
|
+
*
|
|
650
|
+
* The manifest contains:
|
|
651
|
+
* - definitions: ALL JSON Schema type definitions (supports $ref resolution)
|
|
652
|
+
* - handlers: Handler metadata with schema names (references to definitions)
|
|
653
|
+
* - tools: Tool metadata with schema names (references to definitions)
|
|
654
|
+
*/
|
|
655
|
+
FlinkApp.prototype.loadSchemaManifest = function () {
|
|
656
|
+
// Return cached manifest if already loaded
|
|
657
|
+
if (this.schemaManifest) {
|
|
658
|
+
return this.schemaManifest;
|
|
659
|
+
}
|
|
660
|
+
var fs = require("fs");
|
|
661
|
+
var path = require("path");
|
|
662
|
+
var manifestPath = path.join(process.cwd(), "dist/.flink/schema-manifest.json");
|
|
663
|
+
if (!fs.existsSync(manifestPath)) {
|
|
664
|
+
FlinkLog_1.log.warn("Schema manifest not found at dist/.flink/schema-manifest.json - handlers/tools may not have validation schemas");
|
|
665
|
+
var emptyManifest = { definitions: {}, handlers: {}, tools: {} };
|
|
666
|
+
this.schemaManifest = emptyManifest;
|
|
667
|
+
return emptyManifest;
|
|
668
|
+
}
|
|
669
|
+
try {
|
|
670
|
+
var manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
671
|
+
// Check version for backward compatibility
|
|
672
|
+
if (manifest.version === "2.0") {
|
|
673
|
+
// New format with schema universe and AJV global registry
|
|
674
|
+
this.schemaManifest = manifest;
|
|
675
|
+
// Initialize AJV and register all schemas
|
|
676
|
+
this.schemaAjv = new ajv_1.default({
|
|
677
|
+
strict: false, // Allow additional properties by default
|
|
678
|
+
allErrors: true, // Return all validation errors, not just first
|
|
679
|
+
});
|
|
680
|
+
(0, ajv_formats_1.default)(this.schemaAjv);
|
|
681
|
+
// Register all schemas in the universe
|
|
682
|
+
var schemas = manifest.schemas || {};
|
|
683
|
+
for (var _i = 0, _a = Object.values(schemas); _i < _a.length; _i++) {
|
|
684
|
+
var schema = _a[_i];
|
|
685
|
+
if (schema && typeof schema === "object" && schema.$id) {
|
|
686
|
+
// Skip schemas with unresolved generic type parameters (T, U, V, etc.)
|
|
687
|
+
if (this.hasUnresolvedTypeParams(schema, Object.keys(schemas))) {
|
|
688
|
+
FlinkLog_1.log.debug("Skipping registration of generic schema: ".concat(schema.$id));
|
|
689
|
+
continue;
|
|
690
|
+
}
|
|
691
|
+
this.schemaAjv.addSchema(schema);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
FlinkLog_1.log.debug("Loaded schema manifest v2.0: ".concat(Object.keys(schemas).length, " schemas, ").concat(Object.keys(manifest.handlers).length, " handlers, ").concat(Object.keys(manifest.tools).length, " tools"));
|
|
695
|
+
return manifest;
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
// Old format (v1.0) - still supported for migration
|
|
699
|
+
FlinkLog_1.log.debug("Loaded schema manifest v1.0: ".concat(Object.keys(manifest.definitions || {}).length, " definitions, ").concat(Object.keys(manifest.handlers).length, " handlers, ").concat(Object.keys(manifest.tools).length, " tools"));
|
|
700
|
+
this.schemaManifest = manifest;
|
|
701
|
+
return manifest;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
catch (error) {
|
|
705
|
+
FlinkLog_1.log.error("Failed to parse schema manifest:", error);
|
|
706
|
+
var errorManifest = { definitions: {}, handlers: {}, tools: {} };
|
|
707
|
+
this.schemaManifest = errorManifest;
|
|
708
|
+
return errorManifest;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
/**
|
|
712
|
+
* Get the AJV instance for validation (v2.0 manifests).
|
|
713
|
+
* Returns undefined for v1.0 manifests.
|
|
714
|
+
*/
|
|
715
|
+
FlinkApp.prototype.getSchemaAjv = function () {
|
|
716
|
+
return this.schemaAjv;
|
|
717
|
+
};
|
|
718
|
+
/**
|
|
719
|
+
* Register plugin schemas into the app's AJV instance.
|
|
720
|
+
* Schema $id values are prefixed with `pluginId::` to avoid collisions
|
|
721
|
+
* with the app's own schemas or other plugins.
|
|
722
|
+
*
|
|
723
|
+
* @param pluginId Unique identifier for the plugin (used as namespace prefix)
|
|
724
|
+
* @param schemas Record of schema name to JSON Schema object (already prefixed)
|
|
725
|
+
*/
|
|
726
|
+
FlinkApp.prototype.registerSchemas = function (pluginId, schemas) {
|
|
727
|
+
// Ensure schema manifest and AJV are initialized
|
|
728
|
+
this.loadSchemaManifest();
|
|
729
|
+
if (!this.schemaAjv) {
|
|
730
|
+
// If no v2.0 manifest exists, create a fresh AJV instance
|
|
731
|
+
this.schemaAjv = new ajv_1.default({
|
|
732
|
+
strict: false,
|
|
733
|
+
allErrors: true,
|
|
734
|
+
});
|
|
735
|
+
(0, ajv_formats_1.default)(this.schemaAjv);
|
|
736
|
+
}
|
|
737
|
+
for (var _i = 0, _a = Object.values(schemas); _i < _a.length; _i++) {
|
|
738
|
+
var schema = _a[_i];
|
|
739
|
+
if (schema && typeof schema === "object" && schema.$id) {
|
|
740
|
+
// Skip if already registered
|
|
741
|
+
if (this.schemaAjv.getSchema(schema.$id)) {
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
this.schemaAjv.addSchema(schema);
|
|
746
|
+
}
|
|
747
|
+
catch (err) {
|
|
748
|
+
FlinkLog_1.log.warn("Failed to register plugin schema ".concat(schema.$id, ": ").concat(err));
|
|
749
|
+
}
|
|
463
750
|
}
|
|
464
751
|
}
|
|
752
|
+
FlinkLog_1.log.debug("Registered ".concat(Object.keys(schemas).length, " schemas from plugin '").concat(pluginId, "'"));
|
|
753
|
+
};
|
|
754
|
+
/**
|
|
755
|
+
* Check if a schema has unresolved generic type parameter references.
|
|
756
|
+
* Generic type parameters like T, U, V are single uppercase letters.
|
|
757
|
+
*
|
|
758
|
+
* @param schema JSON schema object
|
|
759
|
+
* @param registeredSchemaIds List of schema IDs in the manifest
|
|
760
|
+
* @returns true if schema references generic type params that don't exist
|
|
761
|
+
*/
|
|
762
|
+
FlinkApp.prototype.hasUnresolvedTypeParams = function (schema, registeredSchemaIds) {
|
|
763
|
+
var schemaIdSet = new Set(registeredSchemaIds);
|
|
764
|
+
var checkRefs = function (obj) {
|
|
765
|
+
if (!obj || typeof obj !== "object") {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
if (Array.isArray(obj)) {
|
|
769
|
+
return obj.some(function (item) { return checkRefs(item); });
|
|
770
|
+
}
|
|
771
|
+
for (var _i = 0, _a = Object.entries(obj); _i < _a.length; _i++) {
|
|
772
|
+
var _b = _a[_i], key = _b[0], value = _b[1];
|
|
773
|
+
if (key === "$ref" && typeof value === "string") {
|
|
774
|
+
// Check if ref is a single uppercase letter (generic type param)
|
|
775
|
+
// and not in the registered schema IDs
|
|
776
|
+
if (/^[A-Z]$/.test(value) && !schemaIdSet.has(value)) {
|
|
777
|
+
return true;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
else if (typeof value === "object") {
|
|
781
|
+
if (checkRefs(value)) {
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return false;
|
|
787
|
+
};
|
|
788
|
+
return checkRefs(schema);
|
|
789
|
+
};
|
|
790
|
+
/**
|
|
791
|
+
* Resolve schema by name from manifest.
|
|
792
|
+
* Works with both v1.0 (definitions) and v2.0 (schema universe) formats.
|
|
793
|
+
*
|
|
794
|
+
* @param schemaName Schema name or $id
|
|
795
|
+
* @returns JSON schema object or undefined
|
|
796
|
+
*/
|
|
797
|
+
FlinkApp.prototype.resolveSchema = function (schemaName) {
|
|
798
|
+
if (!schemaName)
|
|
799
|
+
return undefined;
|
|
800
|
+
var manifest = this.loadSchemaManifest();
|
|
801
|
+
// v2.0 manifest - return schema from universe
|
|
802
|
+
if (manifest.version === "2.0" && manifest.schemas) {
|
|
803
|
+
return manifest.schemas[schemaName];
|
|
804
|
+
}
|
|
805
|
+
// v1.0 manifest - return from definitions
|
|
806
|
+
if (manifest.definitions) {
|
|
807
|
+
return manifest.definitions[schemaName];
|
|
808
|
+
}
|
|
809
|
+
return undefined;
|
|
465
810
|
};
|
|
466
811
|
/**
|
|
467
812
|
* Register handlers found within the `/src/handlers`
|
|
@@ -471,47 +816,77 @@ var FlinkApp = /** @class */ (function () {
|
|
|
471
816
|
*/
|
|
472
817
|
FlinkApp.prototype.registerAutoRegisterableHandlers = function () {
|
|
473
818
|
return __awaiter(this, void 0, void 0, function () {
|
|
474
|
-
var _i, _a, _b, handler, assumedHttpMethod, pathParams, _c, _d, param;
|
|
475
|
-
var _e
|
|
476
|
-
return __generator(this, function (
|
|
477
|
-
|
|
478
|
-
|
|
819
|
+
var schemaManifest, schemaCount, _i, _a, _b, handler, assumedHttpMethod, __file, metadata, reqSchema, resSchema, pathParams, _c, _d, param;
|
|
820
|
+
var _e;
|
|
821
|
+
return __generator(this, function (_f) {
|
|
822
|
+
schemaManifest = this.loadSchemaManifest();
|
|
823
|
+
schemaCount = schemaManifest.version === "2.0" ? Object.keys(schemaManifest.schemas || {}).length : Object.keys(schemaManifest.definitions || {}).length;
|
|
824
|
+
FlinkLog_1.log.debug("Registering ".concat(schemaCount, " schemas with AJV (manifest version: ").concat(schemaManifest.version || "1.0", ")"));
|
|
825
|
+
for (_i = 0, _a = exports.autoRegisteredHandlers.sort(function (a, b) {
|
|
826
|
+
var _a, _b, _c, _d, _e, _f;
|
|
827
|
+
var orderDiff = (((_a = a.handler.Route) === null || _a === void 0 ? void 0 : _a.order) || 0) - (((_b = b.handler.Route) === null || _b === void 0 ? void 0 : _b.order) || 0);
|
|
828
|
+
if (orderDiff !== 0)
|
|
829
|
+
return orderDiff;
|
|
830
|
+
// Static segments must be registered before parameterized ones to avoid
|
|
831
|
+
// Express matching e.g. GET /jobs/by-tags with the /jobs/:id route.
|
|
832
|
+
var aHasParam = ((_d = (_c = a.handler.Route) === null || _c === void 0 ? void 0 : _c.path) === null || _d === void 0 ? void 0 : _d.includes("/:")) ? 1 : 0;
|
|
833
|
+
var bHasParam = ((_f = (_e = b.handler.Route) === null || _e === void 0 ? void 0 : _e.path) === null || _f === void 0 ? void 0 : _f.includes("/:")) ? 1 : 0;
|
|
834
|
+
return aHasParam - bHasParam;
|
|
835
|
+
}); _i < _a.length; _i++) {
|
|
836
|
+
_b = _a[_i], handler = _b.handler, assumedHttpMethod = _b.assumedHttpMethod, __file = _b.__file;
|
|
479
837
|
if (!handler.Route) {
|
|
480
|
-
FlinkLog_1.log.error("Missing Props in handler ".concat(
|
|
838
|
+
FlinkLog_1.log.error("Missing Props in handler ".concat(__file));
|
|
481
839
|
continue;
|
|
482
840
|
}
|
|
483
841
|
if (!handler.default) {
|
|
484
|
-
FlinkLog_1.log.error("Missing exported handler function in handler ".concat(
|
|
842
|
+
FlinkLog_1.log.error("Missing exported handler function in handler ".concat(__file));
|
|
485
843
|
continue;
|
|
486
844
|
}
|
|
487
|
-
|
|
845
|
+
metadata = schemaManifest.handlers[__file || ""];
|
|
846
|
+
reqSchema = handler.Route.reqSchema || this.resolveSchema(metadata === null || metadata === void 0 ? void 0 : metadata.reqSchemaName);
|
|
847
|
+
resSchema = handler.Route.resSchema || this.resolveSchema(metadata === null || metadata === void 0 ? void 0 : metadata.resSchemaName);
|
|
848
|
+
// Validation warnings
|
|
849
|
+
if (!metadata &&
|
|
850
|
+
(handler.Route.validation === FlinkHttpHandler_1.ValidationMode.Validate ||
|
|
851
|
+
handler.Route.validation === FlinkHttpHandler_1.ValidationMode.ValidateRequest ||
|
|
852
|
+
handler.Route.validation === FlinkHttpHandler_1.ValidationMode.ValidateResponse)) {
|
|
853
|
+
FlinkLog_1.log.warn("Handler ".concat(__file, " expects validation but no metadata found in manifest"));
|
|
854
|
+
}
|
|
855
|
+
// Warn if schema name doesn't resolve
|
|
856
|
+
if ((metadata === null || metadata === void 0 ? void 0 : metadata.reqSchemaName) && !reqSchema) {
|
|
857
|
+
FlinkLog_1.log.warn("Handler ".concat(__file, " references reqSchema \"").concat(metadata.reqSchemaName, "\" but not found in schema universe"));
|
|
858
|
+
}
|
|
859
|
+
if ((metadata === null || metadata === void 0 ? void 0 : metadata.resSchemaName) && !resSchema) {
|
|
860
|
+
FlinkLog_1.log.warn("Handler ".concat(__file, " references resSchema \"").concat(metadata.resSchemaName, "\" but not found in schema universe"));
|
|
861
|
+
}
|
|
862
|
+
if (!!((_e = metadata === null || metadata === void 0 ? void 0 : metadata.paramsMetadata) === null || _e === void 0 ? void 0 : _e.length)) {
|
|
488
863
|
pathParams = (0, utils_1.getPathParams)(handler.Route.path);
|
|
489
|
-
for (_c = 0, _d =
|
|
864
|
+
for (_c = 0, _d = metadata.paramsMetadata; _c < _d.length; _c++) {
|
|
490
865
|
param = _d[_c];
|
|
491
866
|
if (!pathParams.includes(param.name)) {
|
|
492
|
-
FlinkLog_1.log.error("Handler ".concat(
|
|
867
|
+
FlinkLog_1.log.error("Handler ".concat(__file, " has param ").concat(param.name, " but it is not present in the path '").concat(handler.Route.path, "'"));
|
|
493
868
|
throw new Error("Invalid/missing handler path param");
|
|
494
869
|
}
|
|
495
870
|
}
|
|
496
|
-
if (pathParams.length !==
|
|
497
|
-
FlinkLog_1.log.warn("Handler ".concat(
|
|
871
|
+
if (pathParams.length !== metadata.paramsMetadata.length) {
|
|
872
|
+
FlinkLog_1.log.warn("Handler ".concat(__file, " has ").concat(metadata.paramsMetadata.length, " typed params but the path '").concat(handler.Route.path, "' has ").concat(pathParams.length, " params"));
|
|
498
873
|
}
|
|
499
874
|
}
|
|
500
875
|
this.registerHandler({
|
|
501
|
-
routeProps: __assign(__assign({}, handler.Route), { method: handler.Route.method || assumedHttpMethod, origin: this.name }),
|
|
876
|
+
routeProps: __assign(__assign({}, handler.Route), { method: handler.Route.method || assumedHttpMethod || (metadata === null || metadata === void 0 ? void 0 : metadata.assumedMethod), origin: this.name }),
|
|
502
877
|
schema: {
|
|
503
|
-
reqSchema:
|
|
504
|
-
resSchema:
|
|
878
|
+
reqSchema: reqSchema,
|
|
879
|
+
resSchema: resSchema,
|
|
505
880
|
},
|
|
506
|
-
queryMetadata:
|
|
507
|
-
paramsMetadata:
|
|
881
|
+
queryMetadata: (metadata === null || metadata === void 0 ? void 0 : metadata.queryMetadata) || [],
|
|
882
|
+
paramsMetadata: (metadata === null || metadata === void 0 ? void 0 : metadata.paramsMetadata) || [],
|
|
508
883
|
}, handler.default);
|
|
509
884
|
}
|
|
510
885
|
return [2 /*return*/];
|
|
511
886
|
});
|
|
512
887
|
});
|
|
513
888
|
};
|
|
514
|
-
FlinkApp.prototype.registerAutoRegisterableJobs = function () {
|
|
889
|
+
FlinkApp.prototype.registerAutoRegisterableJobs = function (filter) {
|
|
515
890
|
return __awaiter(this, void 0, void 0, function () {
|
|
516
891
|
var _loop_1, this_1, _i, autoRegisteredJobs_1, _a, jobProps, jobFn, __file;
|
|
517
892
|
var _this = this;
|
|
@@ -520,30 +895,33 @@ var FlinkApp = /** @class */ (function () {
|
|
|
520
895
|
throw new Error("Scheduler not initialized"); // should never happen
|
|
521
896
|
}
|
|
522
897
|
_loop_1 = function (jobProps, jobFn, __file) {
|
|
898
|
+
if (filter && !filter(jobProps)) {
|
|
899
|
+
return "continue";
|
|
900
|
+
}
|
|
523
901
|
if (jobProps.cron && jobProps.interval) {
|
|
524
|
-
|
|
902
|
+
schedulerLog.error("Cannot register job ".concat(jobProps.id, " - both cron and interval are set in ").concat(__file));
|
|
525
903
|
return "continue";
|
|
526
904
|
}
|
|
527
905
|
if (jobProps.cron && jobProps.afterDelay) {
|
|
528
|
-
|
|
906
|
+
schedulerLog.error("Cannot register job ".concat(jobProps.id, " - both cron and afterDelay are set in ").concat(__file));
|
|
529
907
|
return "continue";
|
|
530
908
|
}
|
|
531
909
|
if (jobProps.interval && jobProps.afterDelay) {
|
|
532
|
-
|
|
910
|
+
schedulerLog.error("Cannot register job ".concat(jobProps.id, " - both interval and afterDelay are set in ").concat(__file));
|
|
533
911
|
return "continue";
|
|
534
912
|
}
|
|
535
913
|
if (this_1.scheduler.existsById(jobProps.id)) {
|
|
536
|
-
|
|
914
|
+
schedulerLog.error("Job with id ".concat(jobProps.id, " is already registered, found duplicate in ").concat(__file));
|
|
537
915
|
return "continue";
|
|
538
916
|
}
|
|
539
|
-
|
|
917
|
+
schedulerLog.debug("Registering job ".concat(jobProps.id, ": ").concat(JSON.stringify(jobProps), " from ").concat(__file));
|
|
540
918
|
var task = new toad_scheduler_1.AsyncTask(jobProps.id, function () { return __awaiter(_this, void 0, void 0, function () {
|
|
541
919
|
return __generator(this, function (_a) {
|
|
542
920
|
switch (_a.label) {
|
|
543
921
|
case 0: return [4 /*yield*/, jobFn({ ctx: this.ctx })];
|
|
544
922
|
case 1:
|
|
545
923
|
_a.sent();
|
|
546
|
-
|
|
924
|
+
schedulerLog.debug("Job ".concat(jobProps.id, " completed"));
|
|
547
925
|
if (jobProps.afterDelay) {
|
|
548
926
|
// afterDelay runs only once, so we remove the job
|
|
549
927
|
this.scheduler.removeById(jobProps.id);
|
|
@@ -552,7 +930,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
552
930
|
}
|
|
553
931
|
});
|
|
554
932
|
}); }, function (err) {
|
|
555
|
-
|
|
933
|
+
schedulerLog.error("Job ".concat(jobProps.id, " threw unhandled exception ").concat(err));
|
|
556
934
|
console.error(err);
|
|
557
935
|
});
|
|
558
936
|
if (jobProps.cron) {
|
|
@@ -573,17 +951,41 @@ var FlinkApp = /** @class */ (function () {
|
|
|
573
951
|
this_1.scheduler.addSimpleIntervalJob(job);
|
|
574
952
|
}
|
|
575
953
|
else if (jobProps.afterDelay !== undefined) {
|
|
576
|
-
var
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
954
|
+
var delayMs = (0, ms_1.default)(jobProps.afterDelay);
|
|
955
|
+
if (delayMs === 0) {
|
|
956
|
+
setImmediate(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
957
|
+
var err_2;
|
|
958
|
+
return __generator(this, function (_a) {
|
|
959
|
+
switch (_a.label) {
|
|
960
|
+
case 0:
|
|
961
|
+
_a.trys.push([0, 2, , 3]);
|
|
962
|
+
return [4 /*yield*/, jobFn({ ctx: this.ctx })];
|
|
963
|
+
case 1:
|
|
964
|
+
_a.sent();
|
|
965
|
+
return [3 /*break*/, 3];
|
|
966
|
+
case 2:
|
|
967
|
+
err_2 = _a.sent();
|
|
968
|
+
schedulerLog.error("Job ".concat(jobProps.id, " threw unhandled exception ").concat(err_2));
|
|
969
|
+
console.error(err_2);
|
|
970
|
+
return [3 /*break*/, 3];
|
|
971
|
+
case 3: return [2 /*return*/];
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
}); });
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
var job = new toad_scheduler_1.SimpleIntervalJob({
|
|
978
|
+
milliseconds: delayMs,
|
|
979
|
+
runImmediately: false,
|
|
980
|
+
}, task, {
|
|
981
|
+
id: jobProps.id,
|
|
982
|
+
preventOverrun: jobProps.singleton,
|
|
983
|
+
});
|
|
984
|
+
this_1.scheduler.addSimpleIntervalJob(job);
|
|
985
|
+
}
|
|
584
986
|
}
|
|
585
987
|
else {
|
|
586
|
-
|
|
988
|
+
schedulerLog.error("Cannot register job ".concat(jobProps.id, " - no cron, interval or once set in ").concat(__file));
|
|
587
989
|
return "continue";
|
|
588
990
|
}
|
|
589
991
|
};
|
|
@@ -601,40 +1003,201 @@ var FlinkApp = /** @class */ (function () {
|
|
|
601
1003
|
// TODO: Find out if we need to set ctx here or wanted not to if plugin has its own context
|
|
602
1004
|
// repoInstance.ctx = this.ctx;
|
|
603
1005
|
};
|
|
1006
|
+
FlinkApp.prototype.registerAutoRegisterableTools = function () {
|
|
1007
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1008
|
+
var ToolExecutor, getRepoInstanceName, schemaManifest, _i, autoRegisteredTools_1, toolFile, toolId, toolInstanceName, metadata, schemas, allSchemas, toolExecutor;
|
|
1009
|
+
return __generator(this, function (_a) {
|
|
1010
|
+
ToolExecutor = require("./ai/ToolExecutor").ToolExecutor;
|
|
1011
|
+
getRepoInstanceName = require("./utils").getRepoInstanceName;
|
|
1012
|
+
schemaManifest = this.loadSchemaManifest();
|
|
1013
|
+
for (_i = 0, autoRegisteredTools_1 = exports.autoRegisteredTools; _i < autoRegisteredTools_1.length; _i++) {
|
|
1014
|
+
toolFile = autoRegisteredTools_1[_i];
|
|
1015
|
+
if (!toolFile.Tool) {
|
|
1016
|
+
FlinkLog_1.log.error("Missing FlinkToolProps export in tool ".concat(toolFile.__file));
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
1019
|
+
if (!toolFile.default) {
|
|
1020
|
+
FlinkLog_1.log.error("Missing exported tool function in tool ".concat(toolFile.__file));
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
toolId = toolFile.Tool.id;
|
|
1024
|
+
if (!toolId) {
|
|
1025
|
+
FlinkLog_1.log.error("Tool ".concat(toolFile.__file, " missing 'id' property"));
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
toolInstanceName = getRepoInstanceName(toolId);
|
|
1029
|
+
metadata = schemaManifest.tools[toolFile.__file || ""];
|
|
1030
|
+
schemas = metadata
|
|
1031
|
+
? {
|
|
1032
|
+
inputSchema: this.resolveSchema(metadata.inputSchemaName),
|
|
1033
|
+
outputSchema: this.resolveSchema(metadata.outputSchemaName),
|
|
1034
|
+
inputTypeHint: metadata.inputTypeHint,
|
|
1035
|
+
outputTypeHint: metadata.outputTypeHint,
|
|
1036
|
+
}
|
|
1037
|
+
: undefined;
|
|
1038
|
+
// Warn if schema name doesn't resolve
|
|
1039
|
+
if ((metadata === null || metadata === void 0 ? void 0 : metadata.inputSchemaName) && !(schemas === null || schemas === void 0 ? void 0 : schemas.inputSchema)) {
|
|
1040
|
+
FlinkLog_1.log.warn("Tool ".concat(toolFile.__file, " references inputSchema \"").concat(metadata.inputSchemaName, "\" but not found in schema universe"));
|
|
1041
|
+
}
|
|
1042
|
+
if ((metadata === null || metadata === void 0 ? void 0 : metadata.outputSchemaName) && !(schemas === null || schemas === void 0 ? void 0 : schemas.outputSchema)) {
|
|
1043
|
+
FlinkLog_1.log.warn("Tool ".concat(toolFile.__file, " references outputSchema \"").concat(metadata.outputSchemaName, "\" but not found in schema universe"));
|
|
1044
|
+
}
|
|
1045
|
+
allSchemas = schemaManifest.version === "2.0" ? schemaManifest.schemas : schemaManifest.definitions;
|
|
1046
|
+
toolExecutor = new ToolExecutor(toolFile.Tool, toolFile.default, this.ctx, schemas, // Auto-generated schemas from manifest (resolved from definitions)
|
|
1047
|
+
allSchemas);
|
|
1048
|
+
this.tools[toolInstanceName] = toolExecutor;
|
|
1049
|
+
initLog.info("Registered tool ".concat(toolInstanceName, " (").concat(toolId, ")"));
|
|
1050
|
+
}
|
|
1051
|
+
return [2 /*return*/];
|
|
1052
|
+
});
|
|
1053
|
+
});
|
|
1054
|
+
};
|
|
1055
|
+
FlinkApp.prototype.registerAutoRegisterableAgents = function () {
|
|
1056
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1057
|
+
var _a, getRepoInstanceName, toKebabCase, _loop_2, this_2, _i, autoRegisteredAgents_1, agentFile;
|
|
1058
|
+
return __generator(this, function (_b) {
|
|
1059
|
+
_a = require("./utils"), getRepoInstanceName = _a.getRepoInstanceName, toKebabCase = _a.toKebabCase;
|
|
1060
|
+
_loop_2 = function (agentFile) {
|
|
1061
|
+
// agentFile now exports a class, not a config object
|
|
1062
|
+
var AgentClass = agentFile.default;
|
|
1063
|
+
if (!AgentClass) {
|
|
1064
|
+
FlinkLog_1.log.error("Missing default export in agent ".concat(agentFile.__file));
|
|
1065
|
+
return "continue";
|
|
1066
|
+
}
|
|
1067
|
+
// Instantiate agent (similar to repo instantiation)
|
|
1068
|
+
var agentInstance = new AgentClass();
|
|
1069
|
+
// Derive instance name from class name (camelCase)
|
|
1070
|
+
var agentInstanceName = getRepoInstanceName(AgentClass.name);
|
|
1071
|
+
// Get agent ID (kebab-case) - either explicit or derived
|
|
1072
|
+
var agentId = agentInstance.id;
|
|
1073
|
+
// Check for duplicate instance name
|
|
1074
|
+
if (this_2.agents[agentInstanceName]) {
|
|
1075
|
+
var existingAgent = this_2.agents[agentInstanceName];
|
|
1076
|
+
throw new Error("Duplicate agent instance name: \"".concat(agentInstanceName, "\". ") +
|
|
1077
|
+
"Agent class \"".concat(AgentClass.name, "\" conflicts with existing agent \"").concat(existingAgent.constructor.name, "\". ") +
|
|
1078
|
+
"Instance names are derived by lowercasing the first letter of the class name. " +
|
|
1079
|
+
"Rename one of the classes or use a unique explicit 'id' property.");
|
|
1080
|
+
}
|
|
1081
|
+
// Check for duplicate agent ID
|
|
1082
|
+
var existingAgentWithSameId = Object.values(this_2.agents).find(function (agent) { return agent.id === agentId; });
|
|
1083
|
+
if (existingAgentWithSameId) {
|
|
1084
|
+
throw new Error("Duplicate agent ID: \"".concat(agentId, "\". ") +
|
|
1085
|
+
"Agent class \"".concat(AgentClass.name, "\" conflicts with existing agent \"").concat(existingAgentWithSameId.constructor.name, "\". ") +
|
|
1086
|
+
"Change the 'id' property on one of them to resolve the conflict.");
|
|
1087
|
+
}
|
|
1088
|
+
// Validate tools exist
|
|
1089
|
+
if (agentInstance.tools) {
|
|
1090
|
+
for (var _c = 0, _d = agentInstance.tools; _c < _d.length; _c++) {
|
|
1091
|
+
var toolRef = _d[_c];
|
|
1092
|
+
// Handle string IDs, tool file references, and tool props
|
|
1093
|
+
var toolId = void 0;
|
|
1094
|
+
if (typeof toolRef === "string") {
|
|
1095
|
+
toolId = toolRef;
|
|
1096
|
+
}
|
|
1097
|
+
else if ("Tool" in toolRef) {
|
|
1098
|
+
// FlinkToolFile - extract ID from Tool property
|
|
1099
|
+
toolId = toolRef.Tool.id;
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
// FlinkToolProps - extract ID directly
|
|
1103
|
+
toolId = toolRef.id;
|
|
1104
|
+
}
|
|
1105
|
+
var tool = this_2.tools[toolId];
|
|
1106
|
+
if (!tool) {
|
|
1107
|
+
FlinkLog_1.log.error("Agent ".concat(AgentClass.name, " references tool ").concat(toolId, " which is not registered"));
|
|
1108
|
+
throw new Error("Invalid tool reference in agent ".concat(AgentClass.name));
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
// Register agent (duplicate checks already performed above)
|
|
1113
|
+
this_2.agents[agentInstanceName] = agentInstance;
|
|
1114
|
+
initLog.info("Registered agent ".concat(agentInstanceName, " (").concat(AgentClass.name, ") with ID: ").concat(agentId));
|
|
1115
|
+
};
|
|
1116
|
+
this_2 = this;
|
|
1117
|
+
for (_i = 0, autoRegisteredAgents_1 = exports.autoRegisteredAgents; _i < autoRegisteredAgents_1.length; _i++) {
|
|
1118
|
+
agentFile = autoRegisteredAgents_1[_i];
|
|
1119
|
+
_loop_2(agentFile);
|
|
1120
|
+
}
|
|
1121
|
+
return [2 /*return*/];
|
|
1122
|
+
});
|
|
1123
|
+
});
|
|
1124
|
+
};
|
|
604
1125
|
/**
|
|
605
1126
|
* Constructs the app context. Will inject context in all components
|
|
606
1127
|
* except for handlers which are handled in later stage.
|
|
607
1128
|
*/
|
|
608
1129
|
FlinkApp.prototype.buildContext = function () {
|
|
609
1130
|
return __awaiter(this, void 0, void 0, function () {
|
|
610
|
-
var _i, autoRegisteredRepos_1, _a, collectionName, repoInstanceName, Repo, repoInstance, pluginCtx, _b, _c, repo;
|
|
611
|
-
return __generator(this, function (
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
1131
|
+
var _i, autoRegisteredRepos_1, _a, collectionName, repoInstanceName, Repo, repoInstance, pluginCtx, _b, autoRegisteredServices_1, _c, serviceInstanceName, Service, serviceInstance, _d, _e, repo, _f, _g, service, servicesWithInit;
|
|
1132
|
+
return __generator(this, function (_h) {
|
|
1133
|
+
switch (_h.label) {
|
|
1134
|
+
case 0:
|
|
1135
|
+
if (this.dbOpts) {
|
|
1136
|
+
for (_i = 0, autoRegisteredRepos_1 = exports.autoRegisteredRepos; _i < autoRegisteredRepos_1.length; _i++) {
|
|
1137
|
+
_a = autoRegisteredRepos_1[_i], collectionName = _a.collectionName, repoInstanceName = _a.repoInstanceName, Repo = _a.Repo;
|
|
1138
|
+
repoInstance = new Repo(collectionName, this.db, this.dbClient);
|
|
1139
|
+
this.repos[repoInstanceName] = repoInstance;
|
|
1140
|
+
initLog.info("Registered repo ".concat(repoInstanceName));
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
else if (exports.autoRegisteredRepos.length > 0) {
|
|
1144
|
+
FlinkLog_1.log.warn("No db configured but found repo(s)");
|
|
1145
|
+
}
|
|
1146
|
+
pluginCtx = this.plugins.reduce(function (out, plugin) {
|
|
1147
|
+
if (out[plugin.id]) {
|
|
1148
|
+
throw new Error("Plugin ".concat(plugin.id, " is already registered"));
|
|
1149
|
+
}
|
|
1150
|
+
out[plugin.id] = plugin.ctx;
|
|
1151
|
+
return out;
|
|
1152
|
+
}, {});
|
|
1153
|
+
// Instantiate services (ctx not yet available - constructors must not access it)
|
|
1154
|
+
for (_b = 0, autoRegisteredServices_1 = exports.autoRegisteredServices; _b < autoRegisteredServices_1.length; _b++) {
|
|
1155
|
+
_c = autoRegisteredServices_1[_b], serviceInstanceName = _c.serviceInstanceName, Service = _c.Service;
|
|
1156
|
+
serviceInstance = new Service();
|
|
1157
|
+
this.services[serviceInstanceName] = serviceInstance;
|
|
1158
|
+
initLog.info("Registered service ".concat(serviceInstanceName));
|
|
1159
|
+
}
|
|
1160
|
+
this._ctx = {
|
|
1161
|
+
repos: this.repos,
|
|
1162
|
+
plugins: pluginCtx,
|
|
1163
|
+
auth: this.auth,
|
|
1164
|
+
agents: this.agents,
|
|
1165
|
+
services: this.services,
|
|
1166
|
+
};
|
|
1167
|
+
// Inject context into repos
|
|
1168
|
+
for (_d = 0, _e = Object.values(this.repos); _d < _e.length; _d++) {
|
|
1169
|
+
repo = _e[_d];
|
|
1170
|
+
repo.ctx = this.ctx;
|
|
1171
|
+
}
|
|
1172
|
+
// Inject context into services, then call onInit() in parallel
|
|
1173
|
+
for (_f = 0, _g = Object.values(this.services); _f < _g.length; _f++) {
|
|
1174
|
+
service = _g[_f];
|
|
1175
|
+
service.ctx = this.ctx;
|
|
1176
|
+
}
|
|
1177
|
+
servicesWithInit = Object.values(this.services).filter(function (s) { return typeof s.onInit === "function"; });
|
|
1178
|
+
if (!(servicesWithInit.length > 0)) return [3 /*break*/, 2];
|
|
1179
|
+
return [4 /*yield*/, Promise.all(servicesWithInit.map(function (s) { return s.onInit(); }))];
|
|
1180
|
+
case 1:
|
|
1181
|
+
_h.sent();
|
|
1182
|
+
_h.label = 2;
|
|
1183
|
+
case 2: return [2 /*return*/];
|
|
622
1184
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
for (
|
|
636
|
-
|
|
637
|
-
|
|
1185
|
+
});
|
|
1186
|
+
});
|
|
1187
|
+
};
|
|
1188
|
+
/**
|
|
1189
|
+
* Initialize agents after they've been registered and context is ready
|
|
1190
|
+
* Must be called after registerAutoRegisterableAgents()
|
|
1191
|
+
*/
|
|
1192
|
+
FlinkApp.prototype.initializeAgents = function () {
|
|
1193
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1194
|
+
var _i, _a, agent;
|
|
1195
|
+
return __generator(this, function (_b) {
|
|
1196
|
+
// Inject context and initialize agents
|
|
1197
|
+
for (_i = 0, _a = Object.values(this.agents); _i < _a.length; _i++) {
|
|
1198
|
+
agent = _a[_i];
|
|
1199
|
+
agent.ctx = this.ctx;
|
|
1200
|
+
agent.__init(this.llmAdapters, this.tools, this.agentObserver);
|
|
638
1201
|
}
|
|
639
1202
|
return [2 /*return*/];
|
|
640
1203
|
});
|
|
@@ -645,7 +1208,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
645
1208
|
*/
|
|
646
1209
|
FlinkApp.prototype.initDb = function () {
|
|
647
1210
|
return __awaiter(this, void 0, void 0, function () {
|
|
648
|
-
var client,
|
|
1211
|
+
var client, err_3;
|
|
649
1212
|
return __generator(this, function (_a) {
|
|
650
1213
|
switch (_a.label) {
|
|
651
1214
|
case 0:
|
|
@@ -661,8 +1224,8 @@ var FlinkApp = /** @class */ (function () {
|
|
|
661
1224
|
this.dbClient = client;
|
|
662
1225
|
return [3 /*break*/, 4];
|
|
663
1226
|
case 3:
|
|
664
|
-
|
|
665
|
-
FlinkLog_1.log.error("Failed to connect to db: " +
|
|
1227
|
+
err_3 = _a.sent();
|
|
1228
|
+
FlinkLog_1.log.error("Failed to connect to db: " + err_3);
|
|
666
1229
|
process.exit(1);
|
|
667
1230
|
return [3 /*break*/, 4];
|
|
668
1231
|
case 4:
|
|
@@ -681,7 +1244,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
681
1244
|
*/
|
|
682
1245
|
FlinkApp.prototype.initPluginDb = function (plugin) {
|
|
683
1246
|
return __awaiter(this, void 0, void 0, function () {
|
|
684
|
-
var client,
|
|
1247
|
+
var client, err_4;
|
|
685
1248
|
return __generator(this, function (_a) {
|
|
686
1249
|
switch (_a.label) {
|
|
687
1250
|
case 0:
|
|
@@ -702,14 +1265,14 @@ var FlinkApp = /** @class */ (function () {
|
|
|
702
1265
|
_a.label = 2;
|
|
703
1266
|
case 2:
|
|
704
1267
|
_a.trys.push([2, 4, , 5]);
|
|
705
|
-
|
|
1268
|
+
initLog.debug("Connecting to '".concat(plugin.id, "' db"));
|
|
706
1269
|
return [4 /*yield*/, mongodb_1.MongoClient.connect(plugin.db.uri, this.getMongoConnectionOptions())];
|
|
707
1270
|
case 3:
|
|
708
1271
|
client = _a.sent();
|
|
709
1272
|
return [2 /*return*/, client.db()];
|
|
710
1273
|
case 4:
|
|
711
|
-
|
|
712
|
-
FlinkLog_1.log.error("Failed to connect to db defined in plugin '".concat(plugin.id, "': ") +
|
|
1274
|
+
err_4 = _a.sent();
|
|
1275
|
+
FlinkLog_1.log.error("Failed to connect to db defined in plugin '".concat(plugin.id, "': ") + err_4);
|
|
713
1276
|
return [3 /*break*/, 5];
|
|
714
1277
|
case 5: return [2 /*return*/];
|
|
715
1278
|
}
|
|
@@ -724,12 +1287,40 @@ var FlinkApp = /** @class */ (function () {
|
|
|
724
1287
|
if (!this.auth) {
|
|
725
1288
|
throw new Error("Attempting to authenticate request (".concat(req.method, " ").concat(req.path, ") but no authPlugin is set"));
|
|
726
1289
|
}
|
|
727
|
-
return [4 /*yield*/, this.auth.authenticateRequest(req, permissions)];
|
|
1290
|
+
return [4 /*yield*/, this.auth.authenticateRequest(req, permissions, this._ctx)];
|
|
728
1291
|
case 1: return [2 /*return*/, _a.sent()];
|
|
729
1292
|
}
|
|
730
1293
|
});
|
|
731
1294
|
});
|
|
732
1295
|
};
|
|
1296
|
+
/**
|
|
1297
|
+
* Invokes the optional onError callback in a fire-and-forget manner.
|
|
1298
|
+
* Any error thrown or rejected by the callback is caught and logged so
|
|
1299
|
+
* it never affects the error response sent to the client.
|
|
1300
|
+
*/
|
|
1301
|
+
FlinkApp.prototype.invokeOnError = function (errorResponse, req, method, path) {
|
|
1302
|
+
if (!this.onError) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
try {
|
|
1306
|
+
var result = this.onError(errorResponse, {
|
|
1307
|
+
req: req,
|
|
1308
|
+
method: method,
|
|
1309
|
+
path: path,
|
|
1310
|
+
reqId: req.reqId,
|
|
1311
|
+
ctx: this.ctx,
|
|
1312
|
+
});
|
|
1313
|
+
// Handle async callbacks - don't wait for them
|
|
1314
|
+
if (result instanceof Promise) {
|
|
1315
|
+
result.catch(function (callbackErr) {
|
|
1316
|
+
FlinkLog_1.log.error("onError callback rejected with: ".concat(callbackErr));
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
catch (callbackErr) {
|
|
1321
|
+
FlinkLog_1.log.error("onError callback threw an exception: ".concat(callbackErr));
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
733
1324
|
FlinkApp.prototype.getRegisteredRoutes = function () {
|
|
734
1325
|
return Array.from(this.handlerRouteCache.values());
|
|
735
1326
|
};
|
|
@@ -741,19 +1332,91 @@ var FlinkApp = /** @class */ (function () {
|
|
|
741
1332
|
enumerable: false,
|
|
742
1333
|
configurable: true
|
|
743
1334
|
});
|
|
1335
|
+
Object.defineProperty(FlinkApp.prototype, "leaderElectionConfig", {
|
|
1336
|
+
get: function () {
|
|
1337
|
+
var _a;
|
|
1338
|
+
var opt = (_a = this.schedulingOptions) === null || _a === void 0 ? void 0 : _a.leaderElection;
|
|
1339
|
+
if (!opt)
|
|
1340
|
+
return undefined;
|
|
1341
|
+
return opt === true ? {} : opt;
|
|
1342
|
+
},
|
|
1343
|
+
enumerable: false,
|
|
1344
|
+
configurable: true
|
|
1345
|
+
});
|
|
1346
|
+
FlinkApp.prototype.startLeaderElection = function () {
|
|
1347
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1348
|
+
var hasAllInstanceJobs, opts;
|
|
1349
|
+
var _this = this;
|
|
1350
|
+
return __generator(this, function (_a) {
|
|
1351
|
+
switch (_a.label) {
|
|
1352
|
+
case 0:
|
|
1353
|
+
if (!!this.db) return [3 /*break*/, 2];
|
|
1354
|
+
schedulerLog.warn("Leader election is enabled but no database is configured. " +
|
|
1355
|
+
"Leader election requires a MongoDB connection to coordinate between instances. " +
|
|
1356
|
+
"Either add a database connection via the `db` option, or remove `scheduling.leaderElection` from your config. " +
|
|
1357
|
+
"Jobs will run on ALL instances without leader election.");
|
|
1358
|
+
// Fall back to running jobs on all instances
|
|
1359
|
+
this.scheduler = new toad_scheduler_1.ToadScheduler();
|
|
1360
|
+
return [4 /*yield*/, this.registerAutoRegisterableJobs()];
|
|
1361
|
+
case 1:
|
|
1362
|
+
_a.sent();
|
|
1363
|
+
return [2 /*return*/];
|
|
1364
|
+
case 2:
|
|
1365
|
+
hasAllInstanceJobs = exports.autoRegisteredJobs.some(function (j) { return j.Job.runOnAllInstances; });
|
|
1366
|
+
if (!hasAllInstanceJobs) return [3 /*break*/, 4];
|
|
1367
|
+
this.allInstanceScheduler = new toad_scheduler_1.ToadScheduler();
|
|
1368
|
+
this.scheduler = this.allInstanceScheduler;
|
|
1369
|
+
return [4 /*yield*/, this.registerAutoRegisterableJobs(function (job) { return !!job.runOnAllInstances; })];
|
|
1370
|
+
case 3:
|
|
1371
|
+
_a.sent();
|
|
1372
|
+
this.scheduler = undefined;
|
|
1373
|
+
_a.label = 4;
|
|
1374
|
+
case 4:
|
|
1375
|
+
opts = this.leaderElectionConfig;
|
|
1376
|
+
this.leaderElection = new LeaderElection_1.LeaderElection(this.db, opts);
|
|
1377
|
+
return [4 /*yield*/, this.leaderElection.start(
|
|
1378
|
+
// onBecameLeader
|
|
1379
|
+
function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1380
|
+
return __generator(this, function (_a) {
|
|
1381
|
+
switch (_a.label) {
|
|
1382
|
+
case 0:
|
|
1383
|
+
schedulerLog.info("This instance is now the leader - starting scheduled jobs");
|
|
1384
|
+
this.scheduler = new toad_scheduler_1.ToadScheduler();
|
|
1385
|
+
return [4 /*yield*/, this.registerAutoRegisterableJobs(function (job) { return !job.runOnAllInstances; })];
|
|
1386
|
+
case 1:
|
|
1387
|
+
_a.sent();
|
|
1388
|
+
return [2 /*return*/];
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
}); },
|
|
1392
|
+
// onLostLeadership
|
|
1393
|
+
function () {
|
|
1394
|
+
schedulerLog.info("This instance lost leadership - stopping scheduled jobs");
|
|
1395
|
+
if (_this.scheduler) {
|
|
1396
|
+
_this.scheduler.stop();
|
|
1397
|
+
_this.scheduler = undefined;
|
|
1398
|
+
}
|
|
1399
|
+
})];
|
|
1400
|
+
case 5:
|
|
1401
|
+
_a.sent();
|
|
1402
|
+
return [2 /*return*/];
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
});
|
|
1406
|
+
};
|
|
744
1407
|
FlinkApp.prototype.getMongoConnectionOptions = function () {
|
|
745
1408
|
if (!this.dbOpts) {
|
|
746
1409
|
throw new Error("No db configured");
|
|
747
1410
|
}
|
|
748
1411
|
var driverVersion = require("mongodb/package.json").version;
|
|
749
1412
|
if (driverVersion.startsWith("3")) {
|
|
750
|
-
|
|
1413
|
+
initLog.debug("Using legacy mongodb connection options as mongo client is version ".concat(driverVersion));
|
|
751
1414
|
return {
|
|
752
1415
|
useNewUrlParser: true,
|
|
753
1416
|
useUnifiedTopology: true,
|
|
754
1417
|
};
|
|
755
1418
|
}
|
|
756
|
-
|
|
1419
|
+
initLog.debug("Using modern MongoDB client options (driver version ".concat(driverVersion, ")"));
|
|
757
1420
|
return {
|
|
758
1421
|
serverApi: {
|
|
759
1422
|
version: mongodb_1.ServerApiVersion.v1,
|