@probelabs/visor 0.1.148 → 0.1.149-ee
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/defaults/assistant.yaml +2141 -0
- package/defaults/code-talk.yaml +1250 -0
- package/defaults/intent-router.yaml +478 -0
- package/dist/defaults/assistant.yaml +2141 -0
- package/dist/defaults/code-talk.yaml +1250 -0
- package/dist/defaults/intent-router.yaml +478 -0
- package/dist/index.js +1735 -25
- package/dist/sdk/{check-provider-registry-DVQDGTOE.mjs → check-provider-registry-LVLC4EPF.mjs} +4 -4
- package/dist/sdk/{check-provider-registry-KHPY6LB4.mjs → check-provider-registry-TJAJVSMY.mjs} +4 -4
- package/dist/sdk/{chunk-DIND4ZCV.mjs → chunk-DNDS7R3N.mjs} +11 -1
- package/dist/sdk/{chunk-DIND4ZCV.mjs.map → chunk-DNDS7R3N.mjs.map} +1 -1
- package/dist/sdk/{chunk-6N6JRWCW.mjs → chunk-NYFTDVG5.mjs} +12 -12
- package/dist/sdk/{chunk-IF2UD2KS.mjs.map → chunk-NYFTDVG5.mjs.map} +1 -1
- package/dist/sdk/{chunk-H4AYMOAT.mjs → chunk-V6GI4U2M.mjs} +10 -10
- package/dist/sdk/{chunk-XNTBSV6M.mjs → chunk-YYZAN5NK.mjs} +3 -3
- package/dist/sdk/{config-G5UU4WXT.mjs → config-KQH254CA.mjs} +2 -2
- package/dist/sdk/{host-4F6I3ZXN.mjs → host-NZXGBBJI.mjs} +2 -2
- package/dist/sdk/knex-store-HPXJILBL.mjs +411 -0
- package/dist/sdk/knex-store-HPXJILBL.mjs.map +1 -0
- package/dist/sdk/loader-YSRMVXC3.mjs +89 -0
- package/dist/sdk/loader-YSRMVXC3.mjs.map +1 -0
- package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs +655 -0
- package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs.map +1 -0
- package/dist/sdk/{schedule-tool-SBXAEBDD.mjs → schedule-tool-4U32CSH6.mjs} +4 -4
- package/dist/sdk/{schedule-tool-CONR4VW3.mjs → schedule-tool-NX75VKGA.mjs} +4 -4
- package/dist/sdk/{schedule-tool-handler-R7PG3VMR.mjs → schedule-tool-handler-6S2DNP26.mjs} +4 -4
- package/dist/sdk/{schedule-tool-handler-YUC6CAXX.mjs → schedule-tool-handler-KKN7XJYT.mjs} +4 -4
- package/dist/sdk/sdk.js +1527 -259
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +6 -6
- package/dist/sdk/validator-XTZJZZJH.mjs +134 -0
- package/dist/sdk/validator-XTZJZZJH.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-DYSO3PML.mjs → workflow-check-provider-AGZ5JY2I.mjs} +4 -4
- package/dist/sdk/{workflow-check-provider-FIFFQDQU.mjs → workflow-check-provider-FDNGOBBG.mjs} +4 -4
- package/dist/sdk/{workflow-registry-AAD37XKZ.mjs → workflow-registry-MHUSKSD6.mjs} +2 -2
- package/dist/workflow-registry.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/output/traces/run-2026-03-02T18-32-11-359Z.ndjson +0 -138
- package/dist/output/traces/run-2026-03-02T18-32-55-702Z.ndjson +0 -1442
- package/dist/sdk/check-provider-registry-35BPTY4W.mjs +0 -29
- package/dist/sdk/chunk-6N6JRWCW.mjs.map +0 -1
- package/dist/sdk/chunk-AYQE4JCU.mjs +0 -1502
- package/dist/sdk/chunk-AYQE4JCU.mjs.map +0 -1
- package/dist/sdk/chunk-EGUHXVWS.mjs +0 -443
- package/dist/sdk/chunk-EGUHXVWS.mjs.map +0 -1
- package/dist/sdk/chunk-IF2UD2KS.mjs +0 -43159
- package/dist/sdk/chunk-S2YO4ZE3.mjs +0 -739
- package/dist/sdk/chunk-S2YO4ZE3.mjs.map +0 -1
- package/dist/sdk/failure-condition-evaluator-I6QWFKV3.mjs +0 -17
- package/dist/sdk/github-frontend-2MC77L7F.mjs +0 -1368
- package/dist/sdk/github-frontend-2MC77L7F.mjs.map +0 -1
- package/dist/sdk/routing-UT3BXBXH.mjs +0 -25
- package/dist/sdk/schedule-tool-K3GQXCBN.mjs +0 -35
- package/dist/sdk/schedule-tool-handler-GFQCJAVZ.mjs +0 -39
- package/dist/sdk/schedule-tool-handler-R7PG3VMR.mjs.map +0 -1
- package/dist/sdk/schedule-tool-handler-YUC6CAXX.mjs.map +0 -1
- package/dist/sdk/trace-helpers-J463EU4B.mjs +0 -25
- package/dist/sdk/trace-helpers-J463EU4B.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-DYSO3PML.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-FIFFQDQU.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-GJNGTS3F.mjs +0 -29
- package/dist/sdk/workflow-check-provider-GJNGTS3F.mjs.map +0 -1
- package/dist/sdk/workflow-registry-AAD37XKZ.mjs.map +0 -1
- package/dist/traces/run-2026-03-02T18-32-11-359Z.ndjson +0 -138
- package/dist/traces/run-2026-03-02T18-32-55-702Z.ndjson +0 -1442
- /package/dist/sdk/{check-provider-registry-35BPTY4W.mjs.map → check-provider-registry-LVLC4EPF.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-DVQDGTOE.mjs.map → check-provider-registry-TJAJVSMY.mjs.map} +0 -0
- /package/dist/sdk/{chunk-H4AYMOAT.mjs.map → chunk-V6GI4U2M.mjs.map} +0 -0
- /package/dist/sdk/{chunk-XNTBSV6M.mjs.map → chunk-YYZAN5NK.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-KHPY6LB4.mjs.map → config-KQH254CA.mjs.map} +0 -0
- /package/dist/sdk/{host-4F6I3ZXN.mjs.map → host-NZXGBBJI.mjs.map} +0 -0
- /package/dist/sdk/{config-G5UU4WXT.mjs.map → schedule-tool-4U32CSH6.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-I6QWFKV3.mjs.map → schedule-tool-NX75VKGA.mjs.map} +0 -0
- /package/dist/sdk/{routing-UT3BXBXH.mjs.map → schedule-tool-handler-6S2DNP26.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-CONR4VW3.mjs.map → schedule-tool-handler-KKN7XJYT.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-K3GQXCBN.mjs.map → workflow-check-provider-AGZ5JY2I.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-SBXAEBDD.mjs.map → workflow-check-provider-FDNGOBBG.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-GFQCJAVZ.mjs.map → workflow-registry-MHUSKSD6.mjs.map} +0 -0
|
@@ -29,11 +29,11 @@ import {
|
|
|
29
29
|
WorkflowRegistry,
|
|
30
30
|
init_dependency_resolver,
|
|
31
31
|
init_workflow_registry
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-DNDS7R3N.mjs";
|
|
33
33
|
import {
|
|
34
34
|
config_exports,
|
|
35
35
|
init_config
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-YYZAN5NK.mjs";
|
|
37
37
|
import {
|
|
38
38
|
ExecutionJournal,
|
|
39
39
|
checkLoopBudget,
|
|
@@ -3942,7 +3942,7 @@ async function executeWorkflowAsTool(workflowId, args, context2, argsOverrides)
|
|
|
3942
3942
|
...args,
|
|
3943
3943
|
...argsOverrides
|
|
3944
3944
|
};
|
|
3945
|
-
const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-
|
|
3945
|
+
const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-AGZ5JY2I.mjs");
|
|
3946
3946
|
const provider = new WorkflowCheckProvider2();
|
|
3947
3947
|
const checkConfig = {
|
|
3948
3948
|
type: "workflow",
|
|
@@ -12729,7 +12729,7 @@ var init_state_machine_execution_engine = __esm({
|
|
|
12729
12729
|
try {
|
|
12730
12730
|
const map = options?.webhookContext?.webhookData;
|
|
12731
12731
|
if (map) {
|
|
12732
|
-
const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-
|
|
12732
|
+
const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-LVLC4EPF.mjs");
|
|
12733
12733
|
const reg = CheckProviderRegistry2.getInstance();
|
|
12734
12734
|
const p = reg.getProvider("http_input");
|
|
12735
12735
|
if (p && typeof p.setWebhookContext === "function") p.setWebhookContext(map);
|
|
@@ -12842,7 +12842,7 @@ var init_state_machine_execution_engine = __esm({
|
|
|
12842
12842
|
logger.info("[StateMachine] Using state machine engine");
|
|
12843
12843
|
}
|
|
12844
12844
|
if (!config) {
|
|
12845
|
-
const { ConfigManager } = await import("./config-
|
|
12845
|
+
const { ConfigManager } = await import("./config-KQH254CA.mjs");
|
|
12846
12846
|
const configManager = new ConfigManager();
|
|
12847
12847
|
config = await configManager.getDefaultConfig();
|
|
12848
12848
|
logger.debug("[StateMachine] Using default configuration (no config provided)");
|
|
@@ -12852,7 +12852,7 @@ var init_state_machine_execution_engine = __esm({
|
|
|
12852
12852
|
tag_filter: tagFilter
|
|
12853
12853
|
} : config;
|
|
12854
12854
|
try {
|
|
12855
|
-
const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-
|
|
12855
|
+
const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-LVLC4EPF.mjs");
|
|
12856
12856
|
const registry = CheckProviderRegistry2.getInstance();
|
|
12857
12857
|
registry.setCustomTools(configWithTagFilter.tools || {});
|
|
12858
12858
|
} catch (error) {
|
|
@@ -12916,7 +12916,7 @@ var init_state_machine_execution_engine = __esm({
|
|
|
12916
12916
|
try {
|
|
12917
12917
|
const webhookData = this.executionContext?.webhookContext?.webhookData;
|
|
12918
12918
|
if (webhookData instanceof Map) {
|
|
12919
|
-
const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-
|
|
12919
|
+
const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-KKN7XJYT.mjs");
|
|
12920
12920
|
const slackCtx = extractSlackContext2(webhookData);
|
|
12921
12921
|
if (slackCtx) {
|
|
12922
12922
|
const payload = Array.from(webhookData.values())[0];
|
|
@@ -40151,8 +40151,8 @@ function buildBuiltinGlobals(opts) {
|
|
|
40151
40151
|
const asyncFunctionNames = /* @__PURE__ */ new Set();
|
|
40152
40152
|
const scheduleFn = async (args = {}) => {
|
|
40153
40153
|
try {
|
|
40154
|
-
const { handleScheduleAction: handleScheduleAction2, buildScheduleToolContext: buildScheduleToolContext2 } = await import("./schedule-tool-
|
|
40155
|
-
const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-
|
|
40154
|
+
const { handleScheduleAction: handleScheduleAction2, buildScheduleToolContext: buildScheduleToolContext2 } = await import("./schedule-tool-NX75VKGA.mjs");
|
|
40155
|
+
const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-KKN7XJYT.mjs");
|
|
40156
40156
|
const parentCtx = opts.sessionInfo?._parentContext;
|
|
40157
40157
|
const webhookData = parentCtx?.prInfo?.eventContext?.webhookData;
|
|
40158
40158
|
const visorCfg = parentCtx?.config;
|
|
@@ -43156,4 +43156,4 @@ undici/lib/fetch/body.js:
|
|
|
43156
43156
|
undici/lib/websocket/frame.js:
|
|
43157
43157
|
(*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
|
|
43158
43158
|
*/
|
|
43159
|
-
//# sourceMappingURL=chunk-
|
|
43159
|
+
//# sourceMappingURL=chunk-V6GI4U2M.mjs.map
|
|
@@ -3681,7 +3681,7 @@ var init_config = __esm({
|
|
|
3681
3681
|
* When a workflow YAML is run standalone, register the workflow and use its tests as checks
|
|
3682
3682
|
*/
|
|
3683
3683
|
async convertWorkflowToConfig(workflowData, basePath) {
|
|
3684
|
-
const { WorkflowRegistry } = await import("./workflow-registry-
|
|
3684
|
+
const { WorkflowRegistry } = await import("./workflow-registry-MHUSKSD6.mjs");
|
|
3685
3685
|
const registry = WorkflowRegistry.getInstance();
|
|
3686
3686
|
const workflowId = workflowData.id;
|
|
3687
3687
|
logger.info(`Detected standalone workflow file: ${workflowId}`);
|
|
@@ -3761,7 +3761,7 @@ ${errors}`);
|
|
|
3761
3761
|
if (!config.imports || config.imports.length === 0) {
|
|
3762
3762
|
return;
|
|
3763
3763
|
}
|
|
3764
|
-
const { WorkflowRegistry } = await import("./workflow-registry-
|
|
3764
|
+
const { WorkflowRegistry } = await import("./workflow-registry-MHUSKSD6.mjs");
|
|
3765
3765
|
const registry = WorkflowRegistry.getInstance();
|
|
3766
3766
|
for (const source of config.imports) {
|
|
3767
3767
|
const results = await registry.import(source, { basePath, validate: true, override: true });
|
|
@@ -4961,4 +4961,4 @@ export {
|
|
|
4961
4961
|
config_exports,
|
|
4962
4962
|
init_config
|
|
4963
4963
|
};
|
|
4964
|
-
//# sourceMappingURL=chunk-
|
|
4964
|
+
//# sourceMappingURL=chunk-YYZAN5NK.mjs.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
ConfigManager,
|
|
3
3
|
VALID_EVENT_TRIGGERS,
|
|
4
4
|
init_config
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-YYZAN5NK.mjs";
|
|
6
6
|
import "./chunk-NCWIZVOT.mjs";
|
|
7
7
|
import "./chunk-LW3INISN.mjs";
|
|
8
8
|
import "./chunk-SZXICFQ3.mjs";
|
|
@@ -13,4 +13,4 @@ export {
|
|
|
13
13
|
ConfigManager,
|
|
14
14
|
VALID_EVENT_TRIGGERS
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=config-
|
|
16
|
+
//# sourceMappingURL=config-KQH254CA.mjs.map
|
|
@@ -21,7 +21,7 @@ var init_host = __esm({
|
|
|
21
21
|
const { NdjsonSink } = await import("./ndjson-sink-FD2PSXGD.mjs");
|
|
22
22
|
this.frontends.push(new NdjsonSink(spec.config));
|
|
23
23
|
} else if (spec.name === "github") {
|
|
24
|
-
const { GitHubFrontend } = await import("./github-frontend-
|
|
24
|
+
const { GitHubFrontend } = await import("./github-frontend-DFT5G32K.mjs");
|
|
25
25
|
this.frontends.push(new GitHubFrontend());
|
|
26
26
|
} else if (spec.name === "slack") {
|
|
27
27
|
const { SlackFrontend } = await import("./slack-frontend-TZU2HIK7.mjs");
|
|
@@ -60,4 +60,4 @@ init_host();
|
|
|
60
60
|
export {
|
|
61
61
|
FrontendsHost
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=host-
|
|
63
|
+
//# sourceMappingURL=host-NZXGBBJI.mjs.map
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_logger,
|
|
3
|
+
logger
|
|
4
|
+
} from "./chunk-SZXICFQ3.mjs";
|
|
5
|
+
import "./chunk-UCMJJ3IM.mjs";
|
|
6
|
+
import {
|
|
7
|
+
__esm,
|
|
8
|
+
__require
|
|
9
|
+
} from "./chunk-J7LXIPZS.mjs";
|
|
10
|
+
|
|
11
|
+
// src/enterprise/scheduler/knex-store.ts
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
import { v4 as uuidv4 } from "uuid";
|
|
15
|
+
function toNum(val) {
|
|
16
|
+
if (val === null || val === void 0) return void 0;
|
|
17
|
+
return typeof val === "string" ? parseInt(val, 10) : val;
|
|
18
|
+
}
|
|
19
|
+
function safeJsonParse(value) {
|
|
20
|
+
if (!value) return void 0;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(value);
|
|
23
|
+
} catch {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function fromDbRow(row) {
|
|
28
|
+
return {
|
|
29
|
+
id: row.id,
|
|
30
|
+
creatorId: row.creator_id,
|
|
31
|
+
creatorContext: row.creator_context ?? void 0,
|
|
32
|
+
creatorName: row.creator_name ?? void 0,
|
|
33
|
+
timezone: row.timezone,
|
|
34
|
+
schedule: row.schedule_expr,
|
|
35
|
+
runAt: toNum(row.run_at),
|
|
36
|
+
isRecurring: row.is_recurring === true || row.is_recurring === 1,
|
|
37
|
+
originalExpression: row.original_expression,
|
|
38
|
+
workflow: row.workflow ?? void 0,
|
|
39
|
+
workflowInputs: safeJsonParse(row.workflow_inputs),
|
|
40
|
+
outputContext: safeJsonParse(row.output_context),
|
|
41
|
+
status: row.status,
|
|
42
|
+
createdAt: toNum(row.created_at),
|
|
43
|
+
lastRunAt: toNum(row.last_run_at),
|
|
44
|
+
nextRunAt: toNum(row.next_run_at),
|
|
45
|
+
runCount: row.run_count,
|
|
46
|
+
failureCount: row.failure_count,
|
|
47
|
+
lastError: row.last_error ?? void 0,
|
|
48
|
+
previousResponse: row.previous_response ?? void 0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function toInsertRow(schedule) {
|
|
52
|
+
return {
|
|
53
|
+
id: schedule.id,
|
|
54
|
+
creator_id: schedule.creatorId,
|
|
55
|
+
creator_context: schedule.creatorContext ?? null,
|
|
56
|
+
creator_name: schedule.creatorName ?? null,
|
|
57
|
+
timezone: schedule.timezone,
|
|
58
|
+
schedule_expr: schedule.schedule,
|
|
59
|
+
run_at: schedule.runAt ?? null,
|
|
60
|
+
is_recurring: schedule.isRecurring,
|
|
61
|
+
original_expression: schedule.originalExpression,
|
|
62
|
+
workflow: schedule.workflow ?? null,
|
|
63
|
+
workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
|
|
64
|
+
output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
|
|
65
|
+
status: schedule.status,
|
|
66
|
+
created_at: schedule.createdAt,
|
|
67
|
+
last_run_at: schedule.lastRunAt ?? null,
|
|
68
|
+
next_run_at: schedule.nextRunAt ?? null,
|
|
69
|
+
run_count: schedule.runCount,
|
|
70
|
+
failure_count: schedule.failureCount,
|
|
71
|
+
last_error: schedule.lastError ?? null,
|
|
72
|
+
previous_response: schedule.previousResponse ?? null
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
var KnexStoreBackend;
|
|
76
|
+
var init_knex_store = __esm({
|
|
77
|
+
"src/enterprise/scheduler/knex-store.ts"() {
|
|
78
|
+
init_logger();
|
|
79
|
+
KnexStoreBackend = class {
|
|
80
|
+
knex = null;
|
|
81
|
+
driver;
|
|
82
|
+
connection;
|
|
83
|
+
constructor(driver, storageConfig, _haConfig) {
|
|
84
|
+
this.driver = driver;
|
|
85
|
+
this.connection = storageConfig.connection || {};
|
|
86
|
+
}
|
|
87
|
+
async initialize() {
|
|
88
|
+
const { createRequire } = __require("module");
|
|
89
|
+
const runtimeRequire = createRequire(__filename);
|
|
90
|
+
let knexFactory;
|
|
91
|
+
try {
|
|
92
|
+
knexFactory = runtimeRequire("knex");
|
|
93
|
+
} catch (err) {
|
|
94
|
+
const code = err?.code;
|
|
95
|
+
if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"knex is required for PostgreSQL/MySQL/MSSQL schedule storage. Install it with: npm install knex"
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
const clientMap = {
|
|
103
|
+
postgresql: "pg",
|
|
104
|
+
mysql: "mysql2",
|
|
105
|
+
mssql: "tedious"
|
|
106
|
+
};
|
|
107
|
+
const client = clientMap[this.driver];
|
|
108
|
+
let connection;
|
|
109
|
+
if (this.connection.connection_string) {
|
|
110
|
+
connection = this.connection.connection_string;
|
|
111
|
+
} else if (this.driver === "mssql") {
|
|
112
|
+
connection = this.buildMssqlConnection();
|
|
113
|
+
} else {
|
|
114
|
+
connection = this.buildStandardConnection();
|
|
115
|
+
}
|
|
116
|
+
this.knex = knexFactory({
|
|
117
|
+
client,
|
|
118
|
+
connection,
|
|
119
|
+
pool: {
|
|
120
|
+
min: this.connection.pool?.min ?? 0,
|
|
121
|
+
max: this.connection.pool?.max ?? 10
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
await this.migrateSchema();
|
|
125
|
+
logger.info(`[KnexStore] Initialized (${this.driver})`);
|
|
126
|
+
}
|
|
127
|
+
buildStandardConnection() {
|
|
128
|
+
return {
|
|
129
|
+
host: this.connection.host || "localhost",
|
|
130
|
+
port: this.connection.port,
|
|
131
|
+
database: this.connection.database || "visor",
|
|
132
|
+
user: this.connection.user,
|
|
133
|
+
password: this.connection.password,
|
|
134
|
+
ssl: this.resolveSslConfig()
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
buildMssqlConnection() {
|
|
138
|
+
const ssl = this.connection.ssl;
|
|
139
|
+
const sslEnabled = ssl === true || typeof ssl === "object" && ssl.enabled !== false;
|
|
140
|
+
return {
|
|
141
|
+
server: this.connection.host || "localhost",
|
|
142
|
+
port: this.connection.port,
|
|
143
|
+
database: this.connection.database || "visor",
|
|
144
|
+
user: this.connection.user,
|
|
145
|
+
password: this.connection.password,
|
|
146
|
+
options: {
|
|
147
|
+
encrypt: sslEnabled,
|
|
148
|
+
trustServerCertificate: typeof ssl === "object" ? ssl.reject_unauthorized === false : !sslEnabled
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
resolveSslConfig() {
|
|
153
|
+
const ssl = this.connection.ssl;
|
|
154
|
+
if (ssl === false || ssl === void 0) return false;
|
|
155
|
+
if (ssl === true) return { rejectUnauthorized: true };
|
|
156
|
+
if (ssl.enabled === false) return false;
|
|
157
|
+
const result = {
|
|
158
|
+
rejectUnauthorized: ssl.reject_unauthorized !== false
|
|
159
|
+
};
|
|
160
|
+
if (ssl.ca) {
|
|
161
|
+
const caPath = this.validateSslPath(ssl.ca, "CA certificate");
|
|
162
|
+
result.ca = fs.readFileSync(caPath, "utf8");
|
|
163
|
+
}
|
|
164
|
+
if (ssl.cert) {
|
|
165
|
+
const certPath = this.validateSslPath(ssl.cert, "client certificate");
|
|
166
|
+
result.cert = fs.readFileSync(certPath, "utf8");
|
|
167
|
+
}
|
|
168
|
+
if (ssl.key) {
|
|
169
|
+
const keyPath = this.validateSslPath(ssl.key, "client key");
|
|
170
|
+
result.key = fs.readFileSync(keyPath, "utf8");
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
validateSslPath(filePath, label) {
|
|
175
|
+
const resolved = path.resolve(filePath);
|
|
176
|
+
if (resolved !== path.normalize(resolved)) {
|
|
177
|
+
throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);
|
|
178
|
+
}
|
|
179
|
+
if (!fs.existsSync(resolved)) {
|
|
180
|
+
throw new Error(`SSL ${label} not found: ${filePath}`);
|
|
181
|
+
}
|
|
182
|
+
return resolved;
|
|
183
|
+
}
|
|
184
|
+
async shutdown() {
|
|
185
|
+
if (this.knex) {
|
|
186
|
+
await this.knex.destroy();
|
|
187
|
+
this.knex = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async migrateSchema() {
|
|
191
|
+
const knex = this.getKnex();
|
|
192
|
+
const exists = await knex.schema.hasTable("schedules");
|
|
193
|
+
if (!exists) {
|
|
194
|
+
await knex.schema.createTable("schedules", (table) => {
|
|
195
|
+
table.string("id", 36).primary();
|
|
196
|
+
table.string("creator_id", 255).notNullable().index();
|
|
197
|
+
table.string("creator_context", 255);
|
|
198
|
+
table.string("creator_name", 255);
|
|
199
|
+
table.string("timezone", 64).notNullable().defaultTo("UTC");
|
|
200
|
+
table.string("schedule_expr", 255);
|
|
201
|
+
table.bigInteger("run_at");
|
|
202
|
+
table.boolean("is_recurring").notNullable();
|
|
203
|
+
table.text("original_expression");
|
|
204
|
+
table.string("workflow", 255);
|
|
205
|
+
table.text("workflow_inputs");
|
|
206
|
+
table.text("output_context");
|
|
207
|
+
table.string("status", 20).notNullable().index();
|
|
208
|
+
table.bigInteger("created_at").notNullable();
|
|
209
|
+
table.bigInteger("last_run_at");
|
|
210
|
+
table.bigInteger("next_run_at");
|
|
211
|
+
table.integer("run_count").notNullable().defaultTo(0);
|
|
212
|
+
table.integer("failure_count").notNullable().defaultTo(0);
|
|
213
|
+
table.text("last_error");
|
|
214
|
+
table.text("previous_response");
|
|
215
|
+
table.index(["status", "next_run_at"]);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const locksExist = await knex.schema.hasTable("scheduler_locks");
|
|
219
|
+
if (!locksExist) {
|
|
220
|
+
await knex.schema.createTable("scheduler_locks", (table) => {
|
|
221
|
+
table.string("lock_id", 255).primary();
|
|
222
|
+
table.string("node_id", 255).notNullable();
|
|
223
|
+
table.string("lock_token", 36).notNullable();
|
|
224
|
+
table.bigInteger("acquired_at").notNullable();
|
|
225
|
+
table.bigInteger("expires_at").notNullable();
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
getKnex() {
|
|
230
|
+
if (!this.knex) {
|
|
231
|
+
throw new Error("[KnexStore] Not initialized. Call initialize() first.");
|
|
232
|
+
}
|
|
233
|
+
return this.knex;
|
|
234
|
+
}
|
|
235
|
+
// --- CRUD ---
|
|
236
|
+
async create(schedule) {
|
|
237
|
+
const knex = this.getKnex();
|
|
238
|
+
const newSchedule = {
|
|
239
|
+
...schedule,
|
|
240
|
+
id: uuidv4(),
|
|
241
|
+
createdAt: Date.now(),
|
|
242
|
+
runCount: 0,
|
|
243
|
+
failureCount: 0,
|
|
244
|
+
status: "active"
|
|
245
|
+
};
|
|
246
|
+
await knex("schedules").insert(toInsertRow(newSchedule));
|
|
247
|
+
logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);
|
|
248
|
+
return newSchedule;
|
|
249
|
+
}
|
|
250
|
+
async importSchedule(schedule) {
|
|
251
|
+
const knex = this.getKnex();
|
|
252
|
+
const existing = await knex("schedules").where("id", schedule.id).first();
|
|
253
|
+
if (existing) return;
|
|
254
|
+
await knex("schedules").insert(toInsertRow(schedule));
|
|
255
|
+
}
|
|
256
|
+
async get(id) {
|
|
257
|
+
const knex = this.getKnex();
|
|
258
|
+
const row = await knex("schedules").where("id", id).first();
|
|
259
|
+
return row ? fromDbRow(row) : void 0;
|
|
260
|
+
}
|
|
261
|
+
async update(id, patch) {
|
|
262
|
+
const knex = this.getKnex();
|
|
263
|
+
const existing = await knex("schedules").where("id", id).first();
|
|
264
|
+
if (!existing) return void 0;
|
|
265
|
+
const current = fromDbRow(existing);
|
|
266
|
+
const updated = { ...current, ...patch, id: current.id };
|
|
267
|
+
const row = toInsertRow(updated);
|
|
268
|
+
delete row.id;
|
|
269
|
+
await knex("schedules").where("id", id).update(row);
|
|
270
|
+
return updated;
|
|
271
|
+
}
|
|
272
|
+
async delete(id) {
|
|
273
|
+
const knex = this.getKnex();
|
|
274
|
+
const deleted = await knex("schedules").where("id", id).del();
|
|
275
|
+
if (deleted > 0) {
|
|
276
|
+
logger.info(`[KnexStore] Deleted schedule ${id}`);
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
// --- Queries ---
|
|
282
|
+
async getByCreator(creatorId) {
|
|
283
|
+
const knex = this.getKnex();
|
|
284
|
+
const rows = await knex("schedules").where("creator_id", creatorId);
|
|
285
|
+
return rows.map((r) => fromDbRow(r));
|
|
286
|
+
}
|
|
287
|
+
async getActiveSchedules() {
|
|
288
|
+
const knex = this.getKnex();
|
|
289
|
+
const rows = await knex("schedules").where("status", "active");
|
|
290
|
+
return rows.map((r) => fromDbRow(r));
|
|
291
|
+
}
|
|
292
|
+
async getDueSchedules(now) {
|
|
293
|
+
const ts = now ?? Date.now();
|
|
294
|
+
const knex = this.getKnex();
|
|
295
|
+
const bFalse = this.driver === "mssql" ? 0 : false;
|
|
296
|
+
const bTrue = this.driver === "mssql" ? 1 : true;
|
|
297
|
+
const rows = await knex("schedules").where("status", "active").andWhere(function() {
|
|
298
|
+
this.where(function() {
|
|
299
|
+
this.where("is_recurring", bFalse).whereNotNull("run_at").where("run_at", "<=", ts);
|
|
300
|
+
}).orWhere(function() {
|
|
301
|
+
this.where("is_recurring", bTrue).whereNotNull("next_run_at").where("next_run_at", "<=", ts);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
return rows.map((r) => fromDbRow(r));
|
|
305
|
+
}
|
|
306
|
+
async findByWorkflow(creatorId, workflowName) {
|
|
307
|
+
const knex = this.getKnex();
|
|
308
|
+
const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, "\\$&");
|
|
309
|
+
const pattern = `%${escaped}%`;
|
|
310
|
+
const rows = await knex("schedules").where("creator_id", creatorId).where("status", "active").whereRaw("LOWER(workflow) LIKE ? ESCAPE '\\'", [pattern]);
|
|
311
|
+
return rows.map((r) => fromDbRow(r));
|
|
312
|
+
}
|
|
313
|
+
async getAll() {
|
|
314
|
+
const knex = this.getKnex();
|
|
315
|
+
const rows = await knex("schedules");
|
|
316
|
+
return rows.map((r) => fromDbRow(r));
|
|
317
|
+
}
|
|
318
|
+
async getStats() {
|
|
319
|
+
const knex = this.getKnex();
|
|
320
|
+
const boolTrue = this.driver === "mssql" ? "1" : "true";
|
|
321
|
+
const boolFalse = this.driver === "mssql" ? "0" : "false";
|
|
322
|
+
const result = await knex("schedules").select(
|
|
323
|
+
knex.raw("COUNT(*) as total"),
|
|
324
|
+
knex.raw("SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active"),
|
|
325
|
+
knex.raw("SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused"),
|
|
326
|
+
knex.raw("SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed"),
|
|
327
|
+
knex.raw("SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed"),
|
|
328
|
+
knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`),
|
|
329
|
+
knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`)
|
|
330
|
+
).first();
|
|
331
|
+
return {
|
|
332
|
+
total: Number(result.total) || 0,
|
|
333
|
+
active: Number(result.active) || 0,
|
|
334
|
+
paused: Number(result.paused) || 0,
|
|
335
|
+
completed: Number(result.completed) || 0,
|
|
336
|
+
failed: Number(result.failed) || 0,
|
|
337
|
+
recurring: Number(result.recurring) || 0,
|
|
338
|
+
oneTime: Number(result.one_time) || 0
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async validateLimits(creatorId, isRecurring, limits) {
|
|
342
|
+
const knex = this.getKnex();
|
|
343
|
+
if (limits.maxGlobal) {
|
|
344
|
+
const result = await knex("schedules").count("* as cnt").first();
|
|
345
|
+
if (Number(result?.cnt) >= limits.maxGlobal) {
|
|
346
|
+
throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (limits.maxPerUser) {
|
|
350
|
+
const result = await knex("schedules").where("creator_id", creatorId).count("* as cnt").first();
|
|
351
|
+
if (Number(result?.cnt) >= limits.maxPerUser) {
|
|
352
|
+
throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (isRecurring && limits.maxRecurringPerUser) {
|
|
356
|
+
const bTrue = this.driver === "mssql" ? 1 : true;
|
|
357
|
+
const result = await knex("schedules").where("creator_id", creatorId).where("is_recurring", bTrue).count("* as cnt").first();
|
|
358
|
+
if (Number(result?.cnt) >= limits.maxRecurringPerUser) {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// --- HA Distributed Locking (via scheduler_locks table) ---
|
|
366
|
+
async tryAcquireLock(lockId, nodeId, ttlSeconds) {
|
|
367
|
+
const knex = this.getKnex();
|
|
368
|
+
const now = Date.now();
|
|
369
|
+
const expiresAt = now + ttlSeconds * 1e3;
|
|
370
|
+
const token = uuidv4();
|
|
371
|
+
const updated = await knex("scheduler_locks").where("lock_id", lockId).where("expires_at", "<", now).update({
|
|
372
|
+
node_id: nodeId,
|
|
373
|
+
lock_token: token,
|
|
374
|
+
acquired_at: now,
|
|
375
|
+
expires_at: expiresAt
|
|
376
|
+
});
|
|
377
|
+
if (updated > 0) return token;
|
|
378
|
+
try {
|
|
379
|
+
await knex("scheduler_locks").insert({
|
|
380
|
+
lock_id: lockId,
|
|
381
|
+
node_id: nodeId,
|
|
382
|
+
lock_token: token,
|
|
383
|
+
acquired_at: now,
|
|
384
|
+
expires_at: expiresAt
|
|
385
|
+
});
|
|
386
|
+
return token;
|
|
387
|
+
} catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async releaseLock(lockId, lockToken) {
|
|
392
|
+
const knex = this.getKnex();
|
|
393
|
+
await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).del();
|
|
394
|
+
}
|
|
395
|
+
async renewLock(lockId, lockToken, ttlSeconds) {
|
|
396
|
+
const knex = this.getKnex();
|
|
397
|
+
const now = Date.now();
|
|
398
|
+
const expiresAt = now + ttlSeconds * 1e3;
|
|
399
|
+
const updated = await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).update({ acquired_at: now, expires_at: expiresAt });
|
|
400
|
+
return updated > 0;
|
|
401
|
+
}
|
|
402
|
+
async flush() {
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
init_knex_store();
|
|
408
|
+
export {
|
|
409
|
+
KnexStoreBackend
|
|
410
|
+
};
|
|
411
|
+
//# sourceMappingURL=knex-store-HPXJILBL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/enterprise/scheduler/knex-store.ts"],"sourcesContent":["/**\n * Copyright (c) ProbeLabs. All rights reserved.\n * Licensed under the Elastic License 2.0; you may not use this file except\n * in compliance with the Elastic License 2.0.\n */\n\n/**\n * Knex-backed schedule store for PostgreSQL, MySQL, and MSSQL (Enterprise)\n *\n * Uses Knex query builder for database-agnostic SQL. Same schema as SQLite backend\n * but with real distributed locking via row-level claims (claimed_by/claimed_at/lock_token).\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../../logger';\nimport type { Schedule, ScheduleLimits } from '../../scheduler/schedule-store';\nimport type {\n ScheduleStoreBackend,\n ScheduleStoreStats,\n StorageConfig,\n HAConfig,\n ServerConnectionConfig,\n} from '../../scheduler/store/types';\n\n// Knex types — loaded dynamically to avoid ncc bundling\ntype Knex = import('knex').Knex;\n\n/**\n * Database row shape (snake_case)\n */\ninterface ScheduleRow {\n id: string;\n creator_id: string;\n creator_context: string | null;\n creator_name: string | null;\n timezone: string;\n schedule_expr: string;\n run_at: number | string | null;\n is_recurring: boolean | number;\n original_expression: string;\n workflow: string | null;\n workflow_inputs: string | null;\n output_context: string | null;\n status: string;\n created_at: number | string;\n last_run_at: number | string | null;\n next_run_at: number | string | null;\n run_count: number;\n failure_count: number;\n last_error: string | null;\n previous_response: string | null;\n}\n\nfunction toNum(val: number | string | null | undefined): number | undefined {\n if (val === null || val === undefined) return undefined;\n return typeof val === 'string' ? parseInt(val, 10) : val;\n}\n\nfunction safeJsonParse<T = unknown>(value: string | null): T | undefined {\n if (!value) return undefined;\n try {\n return JSON.parse(value) as T;\n } catch {\n return undefined;\n }\n}\n\nfunction fromDbRow(row: ScheduleRow): Schedule {\n return {\n id: row.id,\n creatorId: row.creator_id,\n creatorContext: row.creator_context ?? undefined,\n creatorName: row.creator_name ?? undefined,\n timezone: row.timezone,\n schedule: row.schedule_expr,\n runAt: toNum(row.run_at),\n isRecurring: row.is_recurring === true || row.is_recurring === 1,\n originalExpression: row.original_expression,\n workflow: row.workflow ?? undefined,\n workflowInputs: safeJsonParse(row.workflow_inputs),\n outputContext: safeJsonParse(row.output_context),\n status: row.status as Schedule['status'],\n createdAt: toNum(row.created_at)!,\n lastRunAt: toNum(row.last_run_at),\n nextRunAt: toNum(row.next_run_at),\n runCount: row.run_count,\n failureCount: row.failure_count,\n lastError: row.last_error ?? undefined,\n previousResponse: row.previous_response ?? undefined,\n };\n}\n\nfunction toInsertRow(schedule: Schedule): Record<string, unknown> {\n return {\n id: schedule.id,\n creator_id: schedule.creatorId,\n creator_context: schedule.creatorContext ?? null,\n creator_name: schedule.creatorName ?? null,\n timezone: schedule.timezone,\n schedule_expr: schedule.schedule,\n run_at: schedule.runAt ?? null,\n is_recurring: schedule.isRecurring,\n original_expression: schedule.originalExpression,\n workflow: schedule.workflow ?? null,\n workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,\n output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,\n status: schedule.status,\n created_at: schedule.createdAt,\n last_run_at: schedule.lastRunAt ?? null,\n next_run_at: schedule.nextRunAt ?? null,\n run_count: schedule.runCount,\n failure_count: schedule.failureCount,\n last_error: schedule.lastError ?? null,\n previous_response: schedule.previousResponse ?? null,\n };\n}\n\n/**\n * Enterprise Knex-backed store for PostgreSQL, MySQL, and MSSQL\n */\nexport class KnexStoreBackend implements ScheduleStoreBackend {\n private knex: Knex | null = null;\n private driver: 'postgresql' | 'mysql' | 'mssql';\n private connection: ServerConnectionConfig;\n\n constructor(\n driver: 'postgresql' | 'mysql' | 'mssql',\n storageConfig: StorageConfig,\n _haConfig?: HAConfig\n ) {\n this.driver = driver;\n this.connection = (storageConfig.connection || {}) as ServerConnectionConfig;\n }\n\n async initialize(): Promise<void> {\n // Load knex dynamically\n const { createRequire } = require('module') as typeof import('module');\n const runtimeRequire = createRequire(__filename);\n let knexFactory: typeof import('knex').default;\n try {\n knexFactory = runtimeRequire('knex');\n } catch (err: unknown) {\n const code = (err as { code?: string })?.code;\n if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {\n throw new Error(\n 'knex is required for PostgreSQL/MySQL/MSSQL schedule storage. ' +\n 'Install it with: npm install knex'\n );\n }\n throw err;\n }\n\n const clientMap: Record<string, string> = {\n postgresql: 'pg',\n mysql: 'mysql2',\n mssql: 'tedious',\n };\n const client = clientMap[this.driver];\n\n // Build connection config\n let connection: string | Record<string, unknown>;\n if (this.connection.connection_string) {\n connection = this.connection.connection_string;\n } else if (this.driver === 'mssql') {\n connection = this.buildMssqlConnection();\n } else {\n connection = this.buildStandardConnection();\n }\n\n this.knex = knexFactory({\n client,\n connection,\n pool: {\n min: this.connection.pool?.min ?? 0,\n max: this.connection.pool?.max ?? 10,\n },\n });\n\n // Run schema migration\n await this.migrateSchema();\n\n logger.info(`[KnexStore] Initialized (${this.driver})`);\n }\n\n private buildStandardConnection(): Record<string, unknown> {\n return {\n host: this.connection.host || 'localhost',\n port: this.connection.port,\n database: this.connection.database || 'visor',\n user: this.connection.user,\n password: this.connection.password,\n ssl: this.resolveSslConfig(),\n };\n }\n\n private buildMssqlConnection(): Record<string, unknown> {\n const ssl = this.connection.ssl;\n const sslEnabled = ssl === true || (typeof ssl === 'object' && ssl.enabled !== false);\n\n return {\n server: this.connection.host || 'localhost',\n port: this.connection.port,\n database: this.connection.database || 'visor',\n user: this.connection.user,\n password: this.connection.password,\n options: {\n encrypt: sslEnabled,\n trustServerCertificate:\n typeof ssl === 'object' ? ssl.reject_unauthorized === false : !sslEnabled,\n },\n };\n }\n\n private resolveSslConfig(): boolean | Record<string, unknown> {\n const ssl = this.connection.ssl;\n if (ssl === false || ssl === undefined) return false;\n if (ssl === true) return { rejectUnauthorized: true };\n\n // Object config\n if (ssl.enabled === false) return false;\n\n const result: Record<string, unknown> = {\n rejectUnauthorized: ssl.reject_unauthorized !== false,\n };\n\n if (ssl.ca) {\n const caPath = this.validateSslPath(ssl.ca, 'CA certificate');\n result.ca = fs.readFileSync(caPath, 'utf8');\n }\n if (ssl.cert) {\n const certPath = this.validateSslPath(ssl.cert, 'client certificate');\n result.cert = fs.readFileSync(certPath, 'utf8');\n }\n if (ssl.key) {\n const keyPath = this.validateSslPath(ssl.key, 'client key');\n result.key = fs.readFileSync(keyPath, 'utf8');\n }\n\n return result;\n }\n\n private validateSslPath(filePath: string, label: string): string {\n const resolved = path.resolve(filePath);\n if (resolved !== path.normalize(resolved)) {\n throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);\n }\n if (!fs.existsSync(resolved)) {\n throw new Error(`SSL ${label} not found: ${filePath}`);\n }\n return resolved;\n }\n\n async shutdown(): Promise<void> {\n if (this.knex) {\n await this.knex.destroy();\n this.knex = null;\n }\n }\n\n private async migrateSchema(): Promise<void> {\n const knex = this.getKnex();\n\n const exists = await knex.schema.hasTable('schedules');\n if (!exists) {\n await knex.schema.createTable('schedules', table => {\n table.string('id', 36).primary();\n table.string('creator_id', 255).notNullable().index();\n table.string('creator_context', 255);\n table.string('creator_name', 255);\n table.string('timezone', 64).notNullable().defaultTo('UTC');\n table.string('schedule_expr', 255);\n table.bigInteger('run_at');\n table.boolean('is_recurring').notNullable();\n table.text('original_expression');\n table.string('workflow', 255);\n table.text('workflow_inputs');\n table.text('output_context');\n table.string('status', 20).notNullable().index();\n table.bigInteger('created_at').notNullable();\n table.bigInteger('last_run_at');\n table.bigInteger('next_run_at');\n table.integer('run_count').notNullable().defaultTo(0);\n table.integer('failure_count').notNullable().defaultTo(0);\n table.text('last_error');\n table.text('previous_response');\n\n table.index(['status', 'next_run_at']);\n });\n }\n\n // Create scheduler_locks table for distributed locking\n const locksExist = await knex.schema.hasTable('scheduler_locks');\n if (!locksExist) {\n await knex.schema.createTable('scheduler_locks', table => {\n table.string('lock_id', 255).primary();\n table.string('node_id', 255).notNullable();\n table.string('lock_token', 36).notNullable();\n table.bigInteger('acquired_at').notNullable();\n table.bigInteger('expires_at').notNullable();\n });\n }\n }\n\n private getKnex(): Knex {\n if (!this.knex) {\n throw new Error('[KnexStore] Not initialized. Call initialize() first.');\n }\n return this.knex;\n }\n\n // --- CRUD ---\n\n async create(\n schedule: Omit<Schedule, 'id' | 'createdAt' | 'runCount' | 'failureCount' | 'status'>\n ): Promise<Schedule> {\n const knex = this.getKnex();\n\n const newSchedule: Schedule = {\n ...schedule,\n id: uuidv4(),\n createdAt: Date.now(),\n runCount: 0,\n failureCount: 0,\n status: 'active',\n };\n\n await knex('schedules').insert(toInsertRow(newSchedule));\n\n logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);\n return newSchedule;\n }\n\n async importSchedule(schedule: Schedule): Promise<void> {\n const knex = this.getKnex();\n const existing = await knex('schedules').where('id', schedule.id).first();\n if (existing) return; // Already imported (idempotent)\n await knex('schedules').insert(toInsertRow(schedule));\n }\n\n async get(id: string): Promise<Schedule | undefined> {\n const knex = this.getKnex();\n const row = await knex('schedules').where('id', id).first();\n return row ? fromDbRow(row as ScheduleRow) : undefined;\n }\n\n async update(id: string, patch: Partial<Schedule>): Promise<Schedule | undefined> {\n const knex = this.getKnex();\n\n const existing = await knex('schedules').where('id', id).first();\n if (!existing) return undefined;\n\n const current = fromDbRow(existing as ScheduleRow);\n const updated: Schedule = { ...current, ...patch, id: current.id };\n const row = toInsertRow(updated);\n // Remove id from update (PK cannot change)\n delete (row as Record<string, unknown>).id;\n\n await knex('schedules').where('id', id).update(row);\n return updated;\n }\n\n async delete(id: string): Promise<boolean> {\n const knex = this.getKnex();\n const deleted = await knex('schedules').where('id', id).del();\n if (deleted > 0) {\n logger.info(`[KnexStore] Deleted schedule ${id}`);\n return true;\n }\n return false;\n }\n\n // --- Queries ---\n\n async getByCreator(creatorId: string): Promise<Schedule[]> {\n const knex = this.getKnex();\n const rows = await knex('schedules').where('creator_id', creatorId);\n return rows.map((r: ScheduleRow) => fromDbRow(r));\n }\n\n async getActiveSchedules(): Promise<Schedule[]> {\n const knex = this.getKnex();\n const rows = await knex('schedules').where('status', 'active');\n return rows.map((r: ScheduleRow) => fromDbRow(r));\n }\n\n async getDueSchedules(now?: number): Promise<Schedule[]> {\n const ts = now ?? Date.now();\n const knex = this.getKnex();\n // MSSQL uses 1/0 for booleans\n const bFalse = this.driver === 'mssql' ? 0 : false;\n const bTrue = this.driver === 'mssql' ? 1 : true;\n const rows = await knex('schedules')\n .where('status', 'active')\n .andWhere(function () {\n this.where(function () {\n this.where('is_recurring', bFalse as unknown as boolean)\n .whereNotNull('run_at')\n .where('run_at', '<=', ts);\n }).orWhere(function () {\n this.where('is_recurring', bTrue as unknown as boolean)\n .whereNotNull('next_run_at')\n .where('next_run_at', '<=', ts);\n });\n });\n return rows.map((r: ScheduleRow) => fromDbRow(r));\n }\n\n async findByWorkflow(creatorId: string, workflowName: string): Promise<Schedule[]> {\n const knex = this.getKnex();\n const escaped = workflowName.toLowerCase().replace(/[%_\\\\]/g, '\\\\$&');\n const pattern = `%${escaped}%`;\n const rows = await knex('schedules')\n .where('creator_id', creatorId)\n .where('status', 'active')\n .whereRaw(\"LOWER(workflow) LIKE ? ESCAPE '\\\\'\", [pattern]);\n return rows.map((r: ScheduleRow) => fromDbRow(r));\n }\n\n async getAll(): Promise<Schedule[]> {\n const knex = this.getKnex();\n const rows = await knex('schedules');\n return rows.map((r: ScheduleRow) => fromDbRow(r));\n }\n\n async getStats(): Promise<ScheduleStoreStats> {\n const knex = this.getKnex();\n // MSSQL uses 1/0 for booleans; PostgreSQL/MySQL accept both true/1\n const boolTrue = this.driver === 'mssql' ? '1' : 'true';\n const boolFalse = this.driver === 'mssql' ? '0' : 'false';\n const result = await knex('schedules')\n .select(\n knex.raw('COUNT(*) as total'),\n knex.raw(\"SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active\"),\n knex.raw(\"SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused\"),\n knex.raw(\"SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed\"),\n knex.raw(\"SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed\"),\n knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`),\n knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`)\n )\n .first();\n\n return {\n total: Number(result.total) || 0,\n active: Number(result.active) || 0,\n paused: Number(result.paused) || 0,\n completed: Number(result.completed) || 0,\n failed: Number(result.failed) || 0,\n recurring: Number(result.recurring) || 0,\n oneTime: Number(result.one_time) || 0,\n };\n }\n\n async validateLimits(\n creatorId: string,\n isRecurring: boolean,\n limits: ScheduleLimits\n ): Promise<void> {\n const knex = this.getKnex();\n\n if (limits.maxGlobal) {\n const result = await knex('schedules').count('* as cnt').first();\n if (Number(result?.cnt) >= limits.maxGlobal) {\n throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);\n }\n }\n\n if (limits.maxPerUser) {\n const result = await knex('schedules')\n .where('creator_id', creatorId)\n .count('* as cnt')\n .first();\n if (Number(result?.cnt) >= limits.maxPerUser) {\n throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);\n }\n }\n\n if (isRecurring && limits.maxRecurringPerUser) {\n const bTrue = this.driver === 'mssql' ? 1 : true;\n const result = await knex('schedules')\n .where('creator_id', creatorId)\n .where('is_recurring', bTrue as unknown as boolean)\n .count('* as cnt')\n .first();\n if (Number(result?.cnt) >= limits.maxRecurringPerUser) {\n throw new Error(\n `You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`\n );\n }\n }\n }\n\n // --- HA Distributed Locking (via scheduler_locks table) ---\n\n async tryAcquireLock(lockId: string, nodeId: string, ttlSeconds: number): Promise<string | null> {\n const knex = this.getKnex();\n const now = Date.now();\n const expiresAt = now + ttlSeconds * 1000;\n const token = uuidv4();\n\n // Step 1: Try to claim an existing expired lock\n const updated = await knex('scheduler_locks')\n .where('lock_id', lockId)\n .where('expires_at', '<', now)\n .update({\n node_id: nodeId,\n lock_token: token,\n acquired_at: now,\n expires_at: expiresAt,\n });\n\n if (updated > 0) return token;\n\n // Step 2: Try to INSERT a new lock row\n try {\n await knex('scheduler_locks').insert({\n lock_id: lockId,\n node_id: nodeId,\n lock_token: token,\n acquired_at: now,\n expires_at: expiresAt,\n });\n return token;\n } catch {\n // Unique constraint violation — another node holds the lock\n return null;\n }\n }\n\n async releaseLock(lockId: string, lockToken: string): Promise<void> {\n const knex = this.getKnex();\n await knex('scheduler_locks').where('lock_id', lockId).where('lock_token', lockToken).del();\n }\n\n async renewLock(lockId: string, lockToken: string, ttlSeconds: number): Promise<boolean> {\n const knex = this.getKnex();\n const now = Date.now();\n const expiresAt = now + ttlSeconds * 1000;\n\n const updated = await knex('scheduler_locks')\n .where('lock_id', lockId)\n .where('lock_token', lockToken)\n .update({ acquired_at: now, expires_at: expiresAt });\n\n return updated > 0;\n }\n\n async flush(): Promise<void> {\n // No-op for server-based backends\n }\n}\n"],"mappings":"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","names":[]}
|