@probelabs/visor 0.1.176 → 0.1.177-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/dist/frontends/slack-frontend.d.ts.map +1 -1
- package/dist/index.js +1964 -44
- package/dist/sdk/{a2a-frontend-W54ZZ32L.mjs → a2a-frontend-BPWLYLCG.mjs} +2 -2
- package/dist/sdk/{check-provider-registry-MJYNLB37.mjs → check-provider-registry-G64PWDCZ.mjs} +5 -5
- package/dist/sdk/{check-provider-registry-7HSDAKHQ.mjs → check-provider-registry-HW4QPPSA.mjs} +2 -2
- package/dist/sdk/{chunk-Y2DYDGGY.mjs → chunk-GVTWESYN.mjs} +3 -3
- package/dist/sdk/chunk-GVTWESYN.mjs.map +1 -0
- package/dist/sdk/{chunk-4E34HRCW.mjs → chunk-IYXOLUDJ.mjs} +74 -29
- package/dist/sdk/chunk-IYXOLUDJ.mjs.map +1 -0
- package/dist/sdk/{chunk-66PTDQAO.mjs → chunk-OHOBWVPP.mjs} +3 -3
- package/dist/sdk/{chunk-SEA2FWEC.mjs → chunk-OPI632LK.mjs} +2 -2
- package/dist/sdk/{chunk-OK4MLC3R.mjs → chunk-Y6PVSFCS.mjs} +49 -9
- package/dist/sdk/chunk-Y6PVSFCS.mjs.map +1 -0
- package/dist/sdk/{failure-condition-evaluator-RTT5SLVL.mjs → failure-condition-evaluator-HL33X7MH.mjs} +3 -3
- package/dist/sdk/{github-frontend-C4GG62PI.mjs → github-frontend-U2U42CKV.mjs} +3 -3
- package/dist/sdk/{host-6GGO2BQE.mjs → host-HFOJQIOF.mjs} +4 -4
- package/dist/sdk/knex-store-QCEW4I4R.mjs +527 -0
- package/dist/sdk/knex-store-QCEW4I4R.mjs.map +1 -0
- package/dist/sdk/loader-Q7K76ZIY.mjs +89 -0
- package/dist/sdk/loader-Q7K76ZIY.mjs.map +1 -0
- package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs +655 -0
- package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs.map +1 -0
- package/dist/sdk/{routing-DXVYOXAS.mjs → routing-SFP4D6O3.mjs} +4 -4
- package/dist/sdk/{schedule-tool-R7NSHTPJ.mjs → schedule-tool-45NAALKS.mjs} +2 -2
- package/dist/sdk/{schedule-tool-LL7XDILD.mjs → schedule-tool-7O7SWSJ4.mjs} +5 -5
- package/dist/sdk/{schedule-tool-handler-5GTQ6SFI.mjs → schedule-tool-handler-6MPP5DXK.mjs} +2 -2
- package/dist/sdk/{schedule-tool-handler-O3L2R5OJ.mjs → schedule-tool-handler-KYDXJ2ZL.mjs} +5 -5
- package/dist/sdk/sdk.js +1729 -295
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +4 -4
- package/dist/sdk/slack-frontend-XKSIOUXB.mjs +910 -0
- package/dist/sdk/slack-frontend-XKSIOUXB.mjs.map +1 -0
- package/dist/sdk/{trace-helpers-CECHXDLI.mjs → trace-helpers-L3EOYW5P.mjs} +2 -2
- package/dist/sdk/validator-XTZJZZJH.mjs +134 -0
- package/dist/sdk/validator-XTZJZZJH.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-EY6VSMNG.mjs → workflow-check-provider-JIXZJNV5.mjs} +5 -5
- package/dist/sdk/{workflow-check-provider-AX7IRQEZ.mjs → workflow-check-provider-OA33MESM.mjs} +2 -2
- package/dist/utils/workspace-manager.d.ts +5 -1
- package/dist/utils/workspace-manager.d.ts.map +1 -1
- package/dist/utils/worktree-manager.d.ts +5 -1
- package/dist/utils/worktree-manager.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/output/traces/run-2026-03-10T15-37-04-236Z.ndjson +0 -138
- package/dist/output/traces/run-2026-03-10T15-37-44-748Z.ndjson +0 -2296
- package/dist/sdk/check-provider-registry-VE6LQPLY.mjs +0 -30
- package/dist/sdk/chunk-4E34HRCW.mjs.map +0 -1
- package/dist/sdk/chunk-OK4MLC3R.mjs.map +0 -1
- package/dist/sdk/chunk-R3FNZRE4.mjs +0 -45194
- package/dist/sdk/chunk-R3FNZRE4.mjs.map +0 -1
- package/dist/sdk/chunk-Y2DYDGGY.mjs.map +0 -1
- package/dist/sdk/schedule-tool-GKKVOQB7.mjs +0 -36
- package/dist/sdk/schedule-tool-handler-ZZGJ3UFR.mjs +0 -40
- package/dist/sdk/trace-helpers-CECHXDLI.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-AX7IRQEZ.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-EY6VSMNG.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-HZQGJFOU.mjs +0 -30
- package/dist/sdk/workflow-check-provider-HZQGJFOU.mjs.map +0 -1
- package/dist/traces/run-2026-03-10T15-37-04-236Z.ndjson +0 -138
- package/dist/traces/run-2026-03-10T15-37-44-748Z.ndjson +0 -2296
- /package/dist/sdk/{a2a-frontend-W54ZZ32L.mjs.map → a2a-frontend-BPWLYLCG.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-7HSDAKHQ.mjs.map → check-provider-registry-G64PWDCZ.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-MJYNLB37.mjs.map → check-provider-registry-HW4QPPSA.mjs.map} +0 -0
- /package/dist/sdk/{chunk-66PTDQAO.mjs.map → chunk-OHOBWVPP.mjs.map} +0 -0
- /package/dist/sdk/{chunk-SEA2FWEC.mjs.map → chunk-OPI632LK.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-VE6LQPLY.mjs.map → failure-condition-evaluator-HL33X7MH.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-C4GG62PI.mjs.map → github-frontend-U2U42CKV.mjs.map} +0 -0
- /package/dist/sdk/{host-6GGO2BQE.mjs.map → host-HFOJQIOF.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-RTT5SLVL.mjs.map → routing-SFP4D6O3.mjs.map} +0 -0
- /package/dist/sdk/{routing-DXVYOXAS.mjs.map → schedule-tool-45NAALKS.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-GKKVOQB7.mjs.map → schedule-tool-7O7SWSJ4.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-LL7XDILD.mjs.map → schedule-tool-handler-6MPP5DXK.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-R7NSHTPJ.mjs.map → schedule-tool-handler-KYDXJ2ZL.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-5GTQ6SFI.mjs.map → trace-helpers-L3EOYW5P.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-O3L2R5OJ.mjs.map → workflow-check-provider-JIXZJNV5.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-ZZGJ3UFR.mjs.map → workflow-check-provider-OA33MESM.mjs.map} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FailureConditionEvaluator,
|
|
3
3
|
init_failure_condition_evaluator
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-OPI632LK.mjs";
|
|
5
|
+
import "./chunk-GVTWESYN.mjs";
|
|
6
6
|
import "./chunk-6VVXKXTI.mjs";
|
|
7
7
|
import "./chunk-34QX63WK.mjs";
|
|
8
8
|
import "./chunk-25IC7KXZ.mjs";
|
|
@@ -15,4 +15,4 @@ init_failure_condition_evaluator();
|
|
|
15
15
|
export {
|
|
16
16
|
FailureConditionEvaluator
|
|
17
17
|
};
|
|
18
|
-
//# sourceMappingURL=failure-condition-evaluator-
|
|
18
|
+
//# sourceMappingURL=failure-condition-evaluator-HL33X7MH.mjs.map
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
failure_condition_evaluator_exports,
|
|
7
7
|
init_failure_condition_evaluator
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-OPI632LK.mjs";
|
|
9
|
+
import "./chunk-GVTWESYN.mjs";
|
|
10
10
|
import {
|
|
11
11
|
generateShortHumanId,
|
|
12
12
|
init_human_id
|
|
@@ -1383,4 +1383,4 @@ init_github_frontend();
|
|
|
1383
1383
|
export {
|
|
1384
1384
|
GitHubFrontend
|
|
1385
1385
|
};
|
|
1386
|
-
//# sourceMappingURL=github-frontend-
|
|
1386
|
+
//# sourceMappingURL=github-frontend-U2U42CKV.mjs.map
|
|
@@ -24,10 +24,10 @@ var init_host = __esm({
|
|
|
24
24
|
const { NdjsonSink } = await import("./ndjson-sink-FD2PSXGD.mjs");
|
|
25
25
|
this.frontends.push(new NdjsonSink(spec.config));
|
|
26
26
|
} else if (spec.name === "github") {
|
|
27
|
-
const { GitHubFrontend } = await import("./github-frontend-
|
|
27
|
+
const { GitHubFrontend } = await import("./github-frontend-U2U42CKV.mjs");
|
|
28
28
|
this.frontends.push(new GitHubFrontend());
|
|
29
29
|
} else if (spec.name === "slack") {
|
|
30
|
-
const { SlackFrontend } = await import("./slack-frontend-
|
|
30
|
+
const { SlackFrontend } = await import("./slack-frontend-XKSIOUXB.mjs");
|
|
31
31
|
this.frontends.push(new SlackFrontend(spec.config));
|
|
32
32
|
} else if (spec.name === "tui") {
|
|
33
33
|
const { TuiFrontend } = await import("./tui-frontend-T56PZB67.mjs");
|
|
@@ -45,7 +45,7 @@ var init_host = __esm({
|
|
|
45
45
|
const { TeamsFrontend } = await import("./teams-frontend-DNW5GZP3.mjs");
|
|
46
46
|
this.frontends.push(new TeamsFrontend(spec.config));
|
|
47
47
|
} else if (spec.name === "a2a") {
|
|
48
|
-
const { A2AFrontend } = await import("./a2a-frontend-
|
|
48
|
+
const { A2AFrontend } = await import("./a2a-frontend-BPWLYLCG.mjs");
|
|
49
49
|
this.frontends.push(new A2AFrontend(spec.config));
|
|
50
50
|
} else {
|
|
51
51
|
this.log.warn(`[FrontendsHost] Unknown frontend '${spec.name}', skipping`);
|
|
@@ -84,4 +84,4 @@ export {
|
|
|
84
84
|
FrontendsHost,
|
|
85
85
|
isActiveFrontend
|
|
86
86
|
};
|
|
87
|
-
//# sourceMappingURL=host-
|
|
87
|
+
//# sourceMappingURL=host-HFOJQIOF.mjs.map
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_logger,
|
|
3
|
+
logger
|
|
4
|
+
} from "./chunk-FT3I25QV.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 fromTriggerRow(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
|
+
description: row.description ?? void 0,
|
|
34
|
+
channels: safeJsonParse(row.channels),
|
|
35
|
+
fromUsers: safeJsonParse(row.from_users),
|
|
36
|
+
fromBots: row.from_bots === true || row.from_bots === 1,
|
|
37
|
+
contains: safeJsonParse(row.contains),
|
|
38
|
+
matchPattern: row.match_pattern ?? void 0,
|
|
39
|
+
threads: row.threads,
|
|
40
|
+
workflow: row.workflow,
|
|
41
|
+
inputs: safeJsonParse(row.inputs),
|
|
42
|
+
outputContext: safeJsonParse(row.output_context),
|
|
43
|
+
status: row.status,
|
|
44
|
+
enabled: row.enabled === true || row.enabled === 1,
|
|
45
|
+
createdAt: toNum(row.created_at)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function toTriggerInsertRow(trigger) {
|
|
49
|
+
return {
|
|
50
|
+
id: trigger.id,
|
|
51
|
+
creator_id: trigger.creatorId,
|
|
52
|
+
creator_context: trigger.creatorContext ?? null,
|
|
53
|
+
creator_name: trigger.creatorName ?? null,
|
|
54
|
+
description: trigger.description ?? null,
|
|
55
|
+
channels: trigger.channels ? JSON.stringify(trigger.channels) : null,
|
|
56
|
+
from_users: trigger.fromUsers ? JSON.stringify(trigger.fromUsers) : null,
|
|
57
|
+
from_bots: trigger.fromBots,
|
|
58
|
+
contains: trigger.contains ? JSON.stringify(trigger.contains) : null,
|
|
59
|
+
match_pattern: trigger.matchPattern ?? null,
|
|
60
|
+
threads: trigger.threads,
|
|
61
|
+
workflow: trigger.workflow,
|
|
62
|
+
inputs: trigger.inputs ? JSON.stringify(trigger.inputs) : null,
|
|
63
|
+
output_context: trigger.outputContext ? JSON.stringify(trigger.outputContext) : null,
|
|
64
|
+
status: trigger.status,
|
|
65
|
+
enabled: trigger.enabled,
|
|
66
|
+
created_at: trigger.createdAt
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function fromDbRow(row) {
|
|
70
|
+
return {
|
|
71
|
+
id: row.id,
|
|
72
|
+
creatorId: row.creator_id,
|
|
73
|
+
creatorContext: row.creator_context ?? void 0,
|
|
74
|
+
creatorName: row.creator_name ?? void 0,
|
|
75
|
+
timezone: row.timezone,
|
|
76
|
+
schedule: row.schedule_expr,
|
|
77
|
+
runAt: toNum(row.run_at),
|
|
78
|
+
isRecurring: row.is_recurring === true || row.is_recurring === 1,
|
|
79
|
+
originalExpression: row.original_expression,
|
|
80
|
+
workflow: row.workflow ?? void 0,
|
|
81
|
+
workflowInputs: safeJsonParse(row.workflow_inputs),
|
|
82
|
+
outputContext: safeJsonParse(row.output_context),
|
|
83
|
+
status: row.status,
|
|
84
|
+
createdAt: toNum(row.created_at),
|
|
85
|
+
lastRunAt: toNum(row.last_run_at),
|
|
86
|
+
nextRunAt: toNum(row.next_run_at),
|
|
87
|
+
runCount: row.run_count,
|
|
88
|
+
failureCount: row.failure_count,
|
|
89
|
+
lastError: row.last_error ?? void 0,
|
|
90
|
+
previousResponse: row.previous_response ?? void 0
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function toInsertRow(schedule) {
|
|
94
|
+
return {
|
|
95
|
+
id: schedule.id,
|
|
96
|
+
creator_id: schedule.creatorId,
|
|
97
|
+
creator_context: schedule.creatorContext ?? null,
|
|
98
|
+
creator_name: schedule.creatorName ?? null,
|
|
99
|
+
timezone: schedule.timezone,
|
|
100
|
+
schedule_expr: schedule.schedule,
|
|
101
|
+
run_at: schedule.runAt ?? null,
|
|
102
|
+
is_recurring: schedule.isRecurring,
|
|
103
|
+
original_expression: schedule.originalExpression,
|
|
104
|
+
workflow: schedule.workflow ?? null,
|
|
105
|
+
workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
|
|
106
|
+
output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
|
|
107
|
+
status: schedule.status,
|
|
108
|
+
created_at: schedule.createdAt,
|
|
109
|
+
last_run_at: schedule.lastRunAt ?? null,
|
|
110
|
+
next_run_at: schedule.nextRunAt ?? null,
|
|
111
|
+
run_count: schedule.runCount,
|
|
112
|
+
failure_count: schedule.failureCount,
|
|
113
|
+
last_error: schedule.lastError ?? null,
|
|
114
|
+
previous_response: schedule.previousResponse ?? null
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
var KnexStoreBackend;
|
|
118
|
+
var init_knex_store = __esm({
|
|
119
|
+
"src/enterprise/scheduler/knex-store.ts"() {
|
|
120
|
+
init_logger();
|
|
121
|
+
KnexStoreBackend = class {
|
|
122
|
+
knex = null;
|
|
123
|
+
driver;
|
|
124
|
+
connection;
|
|
125
|
+
constructor(driver, storageConfig, _haConfig) {
|
|
126
|
+
this.driver = driver;
|
|
127
|
+
this.connection = storageConfig.connection || {};
|
|
128
|
+
}
|
|
129
|
+
async initialize() {
|
|
130
|
+
const { createRequire } = __require("module");
|
|
131
|
+
const runtimeRequire = createRequire(__filename);
|
|
132
|
+
let knexFactory;
|
|
133
|
+
try {
|
|
134
|
+
knexFactory = runtimeRequire("knex");
|
|
135
|
+
} catch (err) {
|
|
136
|
+
const code = err?.code;
|
|
137
|
+
if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
|
|
138
|
+
throw new Error(
|
|
139
|
+
"knex is required for PostgreSQL/MySQL/MSSQL schedule storage. Install it with: npm install knex"
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
throw err;
|
|
143
|
+
}
|
|
144
|
+
const clientMap = {
|
|
145
|
+
postgresql: "pg",
|
|
146
|
+
mysql: "mysql2",
|
|
147
|
+
mssql: "tedious"
|
|
148
|
+
};
|
|
149
|
+
const client = clientMap[this.driver];
|
|
150
|
+
let connection;
|
|
151
|
+
if (this.connection.connection_string) {
|
|
152
|
+
connection = this.connection.connection_string;
|
|
153
|
+
} else if (this.driver === "mssql") {
|
|
154
|
+
connection = this.buildMssqlConnection();
|
|
155
|
+
} else {
|
|
156
|
+
connection = this.buildStandardConnection();
|
|
157
|
+
}
|
|
158
|
+
this.knex = knexFactory({
|
|
159
|
+
client,
|
|
160
|
+
connection,
|
|
161
|
+
pool: {
|
|
162
|
+
min: this.connection.pool?.min ?? 0,
|
|
163
|
+
max: this.connection.pool?.max ?? 10
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
await this.migrateSchema();
|
|
167
|
+
logger.info(`[KnexStore] Initialized (${this.driver})`);
|
|
168
|
+
}
|
|
169
|
+
buildStandardConnection() {
|
|
170
|
+
return {
|
|
171
|
+
host: this.connection.host || "localhost",
|
|
172
|
+
port: this.connection.port,
|
|
173
|
+
database: this.connection.database || "visor",
|
|
174
|
+
user: this.connection.user,
|
|
175
|
+
password: this.connection.password,
|
|
176
|
+
ssl: this.resolveSslConfig()
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
buildMssqlConnection() {
|
|
180
|
+
const ssl = this.connection.ssl;
|
|
181
|
+
const sslEnabled = ssl === true || typeof ssl === "object" && ssl.enabled !== false;
|
|
182
|
+
return {
|
|
183
|
+
server: this.connection.host || "localhost",
|
|
184
|
+
port: this.connection.port,
|
|
185
|
+
database: this.connection.database || "visor",
|
|
186
|
+
user: this.connection.user,
|
|
187
|
+
password: this.connection.password,
|
|
188
|
+
options: {
|
|
189
|
+
encrypt: sslEnabled,
|
|
190
|
+
trustServerCertificate: typeof ssl === "object" ? ssl.reject_unauthorized === false : !sslEnabled
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
resolveSslConfig() {
|
|
195
|
+
const ssl = this.connection.ssl;
|
|
196
|
+
if (ssl === false || ssl === void 0) return false;
|
|
197
|
+
if (ssl === true) return { rejectUnauthorized: true };
|
|
198
|
+
if (ssl.enabled === false) return false;
|
|
199
|
+
const result = {
|
|
200
|
+
rejectUnauthorized: ssl.reject_unauthorized !== false
|
|
201
|
+
};
|
|
202
|
+
if (ssl.ca) {
|
|
203
|
+
const caPath = this.validateSslPath(ssl.ca, "CA certificate");
|
|
204
|
+
result.ca = fs.readFileSync(caPath, "utf8");
|
|
205
|
+
}
|
|
206
|
+
if (ssl.cert) {
|
|
207
|
+
const certPath = this.validateSslPath(ssl.cert, "client certificate");
|
|
208
|
+
result.cert = fs.readFileSync(certPath, "utf8");
|
|
209
|
+
}
|
|
210
|
+
if (ssl.key) {
|
|
211
|
+
const keyPath = this.validateSslPath(ssl.key, "client key");
|
|
212
|
+
result.key = fs.readFileSync(keyPath, "utf8");
|
|
213
|
+
}
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
validateSslPath(filePath, label) {
|
|
217
|
+
const resolved = path.resolve(filePath);
|
|
218
|
+
if (resolved !== path.normalize(resolved)) {
|
|
219
|
+
throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);
|
|
220
|
+
}
|
|
221
|
+
if (!fs.existsSync(resolved)) {
|
|
222
|
+
throw new Error(`SSL ${label} not found: ${filePath}`);
|
|
223
|
+
}
|
|
224
|
+
return resolved;
|
|
225
|
+
}
|
|
226
|
+
async shutdown() {
|
|
227
|
+
if (this.knex) {
|
|
228
|
+
await this.knex.destroy();
|
|
229
|
+
this.knex = null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async migrateSchema() {
|
|
233
|
+
const knex = this.getKnex();
|
|
234
|
+
const exists = await knex.schema.hasTable("schedules");
|
|
235
|
+
if (!exists) {
|
|
236
|
+
await knex.schema.createTable("schedules", (table) => {
|
|
237
|
+
table.string("id", 36).primary();
|
|
238
|
+
table.string("creator_id", 255).notNullable().index();
|
|
239
|
+
table.string("creator_context", 255);
|
|
240
|
+
table.string("creator_name", 255);
|
|
241
|
+
table.string("timezone", 64).notNullable().defaultTo("UTC");
|
|
242
|
+
table.string("schedule_expr", 255);
|
|
243
|
+
table.bigInteger("run_at");
|
|
244
|
+
table.boolean("is_recurring").notNullable();
|
|
245
|
+
table.text("original_expression");
|
|
246
|
+
table.string("workflow", 255);
|
|
247
|
+
table.text("workflow_inputs");
|
|
248
|
+
table.text("output_context");
|
|
249
|
+
table.string("status", 20).notNullable().index();
|
|
250
|
+
table.bigInteger("created_at").notNullable();
|
|
251
|
+
table.bigInteger("last_run_at");
|
|
252
|
+
table.bigInteger("next_run_at");
|
|
253
|
+
table.integer("run_count").notNullable().defaultTo(0);
|
|
254
|
+
table.integer("failure_count").notNullable().defaultTo(0);
|
|
255
|
+
table.text("last_error");
|
|
256
|
+
table.text("previous_response");
|
|
257
|
+
table.index(["status", "next_run_at"]);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const triggersExist = await knex.schema.hasTable("message_triggers");
|
|
261
|
+
if (!triggersExist) {
|
|
262
|
+
await knex.schema.createTable("message_triggers", (table) => {
|
|
263
|
+
table.string("id", 36).primary();
|
|
264
|
+
table.string("creator_id", 255).notNullable().index();
|
|
265
|
+
table.string("creator_context", 255);
|
|
266
|
+
table.string("creator_name", 255);
|
|
267
|
+
table.text("description");
|
|
268
|
+
table.text("channels");
|
|
269
|
+
table.text("from_users");
|
|
270
|
+
table.boolean("from_bots").notNullable().defaultTo(false);
|
|
271
|
+
table.text("contains");
|
|
272
|
+
table.text("match_pattern");
|
|
273
|
+
table.string("threads", 20).notNullable().defaultTo("any");
|
|
274
|
+
table.string("workflow", 255).notNullable();
|
|
275
|
+
table.text("inputs");
|
|
276
|
+
table.text("output_context");
|
|
277
|
+
table.string("status", 20).notNullable().defaultTo("active").index();
|
|
278
|
+
table.boolean("enabled").notNullable().defaultTo(true);
|
|
279
|
+
table.bigInteger("created_at").notNullable();
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
const locksExist = await knex.schema.hasTable("scheduler_locks");
|
|
283
|
+
if (!locksExist) {
|
|
284
|
+
await knex.schema.createTable("scheduler_locks", (table) => {
|
|
285
|
+
table.string("lock_id", 255).primary();
|
|
286
|
+
table.string("node_id", 255).notNullable();
|
|
287
|
+
table.string("lock_token", 36).notNullable();
|
|
288
|
+
table.bigInteger("acquired_at").notNullable();
|
|
289
|
+
table.bigInteger("expires_at").notNullable();
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
getKnex() {
|
|
294
|
+
if (!this.knex) {
|
|
295
|
+
throw new Error("[KnexStore] Not initialized. Call initialize() first.");
|
|
296
|
+
}
|
|
297
|
+
return this.knex;
|
|
298
|
+
}
|
|
299
|
+
// --- CRUD ---
|
|
300
|
+
async create(schedule) {
|
|
301
|
+
const knex = this.getKnex();
|
|
302
|
+
const newSchedule = {
|
|
303
|
+
...schedule,
|
|
304
|
+
id: uuidv4(),
|
|
305
|
+
createdAt: Date.now(),
|
|
306
|
+
runCount: 0,
|
|
307
|
+
failureCount: 0,
|
|
308
|
+
status: "active"
|
|
309
|
+
};
|
|
310
|
+
await knex("schedules").insert(toInsertRow(newSchedule));
|
|
311
|
+
logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);
|
|
312
|
+
return newSchedule;
|
|
313
|
+
}
|
|
314
|
+
async importSchedule(schedule) {
|
|
315
|
+
const knex = this.getKnex();
|
|
316
|
+
const existing = await knex("schedules").where("id", schedule.id).first();
|
|
317
|
+
if (existing) return;
|
|
318
|
+
await knex("schedules").insert(toInsertRow(schedule));
|
|
319
|
+
}
|
|
320
|
+
async get(id) {
|
|
321
|
+
const knex = this.getKnex();
|
|
322
|
+
const row = await knex("schedules").where("id", id).first();
|
|
323
|
+
return row ? fromDbRow(row) : void 0;
|
|
324
|
+
}
|
|
325
|
+
async update(id, patch) {
|
|
326
|
+
const knex = this.getKnex();
|
|
327
|
+
const existing = await knex("schedules").where("id", id).first();
|
|
328
|
+
if (!existing) return void 0;
|
|
329
|
+
const current = fromDbRow(existing);
|
|
330
|
+
const updated = { ...current, ...patch, id: current.id };
|
|
331
|
+
const row = toInsertRow(updated);
|
|
332
|
+
delete row.id;
|
|
333
|
+
await knex("schedules").where("id", id).update(row);
|
|
334
|
+
return updated;
|
|
335
|
+
}
|
|
336
|
+
async delete(id) {
|
|
337
|
+
const knex = this.getKnex();
|
|
338
|
+
const deleted = await knex("schedules").where("id", id).del();
|
|
339
|
+
if (deleted > 0) {
|
|
340
|
+
logger.info(`[KnexStore] Deleted schedule ${id}`);
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
// --- Queries ---
|
|
346
|
+
async getByCreator(creatorId) {
|
|
347
|
+
const knex = this.getKnex();
|
|
348
|
+
const rows = await knex("schedules").where("creator_id", creatorId);
|
|
349
|
+
return rows.map((r) => fromDbRow(r));
|
|
350
|
+
}
|
|
351
|
+
async getActiveSchedules() {
|
|
352
|
+
const knex = this.getKnex();
|
|
353
|
+
const rows = await knex("schedules").where("status", "active");
|
|
354
|
+
return rows.map((r) => fromDbRow(r));
|
|
355
|
+
}
|
|
356
|
+
async getDueSchedules(now) {
|
|
357
|
+
const ts = now ?? Date.now();
|
|
358
|
+
const knex = this.getKnex();
|
|
359
|
+
const bFalse = this.driver === "mssql" ? 0 : false;
|
|
360
|
+
const bTrue = this.driver === "mssql" ? 1 : true;
|
|
361
|
+
const rows = await knex("schedules").where("status", "active").andWhere(function() {
|
|
362
|
+
this.where(function() {
|
|
363
|
+
this.where("is_recurring", bFalse).whereNotNull("run_at").where("run_at", "<=", ts);
|
|
364
|
+
}).orWhere(function() {
|
|
365
|
+
this.where("is_recurring", bTrue).whereNotNull("next_run_at").where("next_run_at", "<=", ts);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
return rows.map((r) => fromDbRow(r));
|
|
369
|
+
}
|
|
370
|
+
async findByWorkflow(creatorId, workflowName) {
|
|
371
|
+
const knex = this.getKnex();
|
|
372
|
+
const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, "\\$&");
|
|
373
|
+
const pattern = `%${escaped}%`;
|
|
374
|
+
const rows = await knex("schedules").where("creator_id", creatorId).where("status", "active").whereRaw("LOWER(workflow) LIKE ? ESCAPE '\\'", [pattern]);
|
|
375
|
+
return rows.map((r) => fromDbRow(r));
|
|
376
|
+
}
|
|
377
|
+
async getAll() {
|
|
378
|
+
const knex = this.getKnex();
|
|
379
|
+
const rows = await knex("schedules");
|
|
380
|
+
return rows.map((r) => fromDbRow(r));
|
|
381
|
+
}
|
|
382
|
+
async getStats() {
|
|
383
|
+
const knex = this.getKnex();
|
|
384
|
+
const boolTrue = this.driver === "mssql" ? "1" : "true";
|
|
385
|
+
const boolFalse = this.driver === "mssql" ? "0" : "false";
|
|
386
|
+
const result = await knex("schedules").select(
|
|
387
|
+
knex.raw("COUNT(*) as total"),
|
|
388
|
+
knex.raw("SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active"),
|
|
389
|
+
knex.raw("SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused"),
|
|
390
|
+
knex.raw("SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed"),
|
|
391
|
+
knex.raw("SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed"),
|
|
392
|
+
knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`),
|
|
393
|
+
knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`)
|
|
394
|
+
).first();
|
|
395
|
+
return {
|
|
396
|
+
total: Number(result.total) || 0,
|
|
397
|
+
active: Number(result.active) || 0,
|
|
398
|
+
paused: Number(result.paused) || 0,
|
|
399
|
+
completed: Number(result.completed) || 0,
|
|
400
|
+
failed: Number(result.failed) || 0,
|
|
401
|
+
recurring: Number(result.recurring) || 0,
|
|
402
|
+
oneTime: Number(result.one_time) || 0
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
async validateLimits(creatorId, isRecurring, limits) {
|
|
406
|
+
const knex = this.getKnex();
|
|
407
|
+
if (limits.maxGlobal) {
|
|
408
|
+
const result = await knex("schedules").count("* as cnt").first();
|
|
409
|
+
if (Number(result?.cnt) >= limits.maxGlobal) {
|
|
410
|
+
throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (limits.maxPerUser) {
|
|
414
|
+
const result = await knex("schedules").where("creator_id", creatorId).count("* as cnt").first();
|
|
415
|
+
if (Number(result?.cnt) >= limits.maxPerUser) {
|
|
416
|
+
throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (isRecurring && limits.maxRecurringPerUser) {
|
|
420
|
+
const bTrue = this.driver === "mssql" ? 1 : true;
|
|
421
|
+
const result = await knex("schedules").where("creator_id", creatorId).where("is_recurring", bTrue).count("* as cnt").first();
|
|
422
|
+
if (Number(result?.cnt) >= limits.maxRecurringPerUser) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
`You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// --- HA Distributed Locking (via scheduler_locks table) ---
|
|
430
|
+
async tryAcquireLock(lockId, nodeId, ttlSeconds) {
|
|
431
|
+
const knex = this.getKnex();
|
|
432
|
+
const now = Date.now();
|
|
433
|
+
const expiresAt = now + ttlSeconds * 1e3;
|
|
434
|
+
const token = uuidv4();
|
|
435
|
+
const updated = await knex("scheduler_locks").where("lock_id", lockId).where("expires_at", "<", now).update({
|
|
436
|
+
node_id: nodeId,
|
|
437
|
+
lock_token: token,
|
|
438
|
+
acquired_at: now,
|
|
439
|
+
expires_at: expiresAt
|
|
440
|
+
});
|
|
441
|
+
if (updated > 0) return token;
|
|
442
|
+
try {
|
|
443
|
+
await knex("scheduler_locks").insert({
|
|
444
|
+
lock_id: lockId,
|
|
445
|
+
node_id: nodeId,
|
|
446
|
+
lock_token: token,
|
|
447
|
+
acquired_at: now,
|
|
448
|
+
expires_at: expiresAt
|
|
449
|
+
});
|
|
450
|
+
return token;
|
|
451
|
+
} catch {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async releaseLock(lockId, lockToken) {
|
|
456
|
+
const knex = this.getKnex();
|
|
457
|
+
await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).del();
|
|
458
|
+
}
|
|
459
|
+
async renewLock(lockId, lockToken, ttlSeconds) {
|
|
460
|
+
const knex = this.getKnex();
|
|
461
|
+
const now = Date.now();
|
|
462
|
+
const expiresAt = now + ttlSeconds * 1e3;
|
|
463
|
+
const updated = await knex("scheduler_locks").where("lock_id", lockId).where("lock_token", lockToken).update({ acquired_at: now, expires_at: expiresAt });
|
|
464
|
+
return updated > 0;
|
|
465
|
+
}
|
|
466
|
+
async flush() {
|
|
467
|
+
}
|
|
468
|
+
// --- Message Trigger CRUD ---
|
|
469
|
+
async createTrigger(trigger) {
|
|
470
|
+
const knex = this.getKnex();
|
|
471
|
+
const newTrigger = {
|
|
472
|
+
...trigger,
|
|
473
|
+
id: uuidv4(),
|
|
474
|
+
createdAt: Date.now()
|
|
475
|
+
};
|
|
476
|
+
await knex("message_triggers").insert(toTriggerInsertRow(newTrigger));
|
|
477
|
+
logger.info(`[KnexStore] Created trigger ${newTrigger.id} for user ${newTrigger.creatorId}`);
|
|
478
|
+
return newTrigger;
|
|
479
|
+
}
|
|
480
|
+
async getTrigger(id) {
|
|
481
|
+
const knex = this.getKnex();
|
|
482
|
+
const row = await knex("message_triggers").where("id", id).first();
|
|
483
|
+
return row ? fromTriggerRow(row) : void 0;
|
|
484
|
+
}
|
|
485
|
+
async updateTrigger(id, patch) {
|
|
486
|
+
const knex = this.getKnex();
|
|
487
|
+
const existing = await knex("message_triggers").where("id", id).first();
|
|
488
|
+
if (!existing) return void 0;
|
|
489
|
+
const current = fromTriggerRow(existing);
|
|
490
|
+
const updated = {
|
|
491
|
+
...current,
|
|
492
|
+
...patch,
|
|
493
|
+
id: current.id,
|
|
494
|
+
createdAt: current.createdAt
|
|
495
|
+
};
|
|
496
|
+
const row = toTriggerInsertRow(updated);
|
|
497
|
+
delete row.id;
|
|
498
|
+
await knex("message_triggers").where("id", id).update(row);
|
|
499
|
+
return updated;
|
|
500
|
+
}
|
|
501
|
+
async deleteTrigger(id) {
|
|
502
|
+
const knex = this.getKnex();
|
|
503
|
+
const deleted = await knex("message_triggers").where("id", id).del();
|
|
504
|
+
if (deleted > 0) {
|
|
505
|
+
logger.info(`[KnexStore] Deleted trigger ${id}`);
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
async getTriggersByCreator(creatorId) {
|
|
511
|
+
const knex = this.getKnex();
|
|
512
|
+
const rows = await knex("message_triggers").where("creator_id", creatorId);
|
|
513
|
+
return rows.map((r) => fromTriggerRow(r));
|
|
514
|
+
}
|
|
515
|
+
async getActiveTriggers() {
|
|
516
|
+
const knex = this.getKnex();
|
|
517
|
+
const rows = await knex("message_triggers").where("status", "active").where("enabled", this.driver === "mssql" ? 1 : true);
|
|
518
|
+
return rows.map((r) => fromTriggerRow(r));
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
init_knex_store();
|
|
524
|
+
export {
|
|
525
|
+
KnexStoreBackend
|
|
526
|
+
};
|
|
527
|
+
//# sourceMappingURL=knex-store-QCEW4I4R.mjs.map
|