@automagik/omni 2.260906.2 → 2.260906.4
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/db/drizzle/0057_connector_lifecycle_contract.sql +40 -0
- package/db/drizzle/0058_omni_events_causation_id.sql +24 -0
- package/db/drizzle/meta/_journal.json +14 -0
- package/dist/commands/events.d.ts +14 -0
- package/dist/commands/events.d.ts.map +1 -1
- package/dist/commands/webhooks.d.ts.map +1 -1
- package/dist/index.js +410 -65
- package/dist/sdk/client.d.ts +21 -0
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +7 -0
- package/dist/sdk/types.generated.d.ts +376 -10
- package/dist/sdk/types.generated.d.ts.map +1 -1
- package/dist/server/index.js +760 -223
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12345,6 +12345,19 @@ var init_types3 = __esm(() => {
|
|
|
12345
12345
|
"flow.data_exchange"
|
|
12346
12346
|
];
|
|
12347
12347
|
});
|
|
12348
|
+
// ../core/src/events/causality.ts
|
|
12349
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
12350
|
+
function runWithEventCausality(context, fn) {
|
|
12351
|
+
return storage.run(context, fn);
|
|
12352
|
+
}
|
|
12353
|
+
function currentEventCausality() {
|
|
12354
|
+
return storage.getStore();
|
|
12355
|
+
}
|
|
12356
|
+
var storage;
|
|
12357
|
+
var init_causality = __esm(() => {
|
|
12358
|
+
storage = new AsyncLocalStorage;
|
|
12359
|
+
});
|
|
12360
|
+
|
|
12348
12361
|
// ../core/src/events/envelope.ts
|
|
12349
12362
|
function classifyEnvelope(metadata) {
|
|
12350
12363
|
if (metadata === null || metadata === undefined)
|
|
@@ -30370,6 +30383,38 @@ var init_logger = __esm(() => {
|
|
|
30370
30383
|
rootLogger = createLogger("system");
|
|
30371
30384
|
});
|
|
30372
30385
|
|
|
30386
|
+
// ../core/src/events/factory.ts
|
|
30387
|
+
function createOmniEvent(type, payload, metadata, serviceName) {
|
|
30388
|
+
const eventId = crypto.randomUUID();
|
|
30389
|
+
const timestamp = Date.now();
|
|
30390
|
+
const tenantId = resolvePublishTenantId(metadata?.tenantId, metadata?.instanceId);
|
|
30391
|
+
const ambient = currentEventCausality();
|
|
30392
|
+
const causationId = metadata?.causationId ?? ambient?.causationId;
|
|
30393
|
+
return {
|
|
30394
|
+
id: eventId,
|
|
30395
|
+
type,
|
|
30396
|
+
payload,
|
|
30397
|
+
timestamp,
|
|
30398
|
+
metadata: {
|
|
30399
|
+
correlationId: metadata?.correlationId ?? ambient?.correlationId ?? eventId,
|
|
30400
|
+
...causationId ? { causationId } : {},
|
|
30401
|
+
instanceId: metadata?.instanceId,
|
|
30402
|
+
channelType: metadata?.channelType,
|
|
30403
|
+
personId: metadata?.personId,
|
|
30404
|
+
platformIdentityId: metadata?.platformIdentityId,
|
|
30405
|
+
traceId: metadata?.traceId ?? eventId,
|
|
30406
|
+
source: metadata?.source ?? serviceName,
|
|
30407
|
+
ingestMode: metadata?.ingestMode,
|
|
30408
|
+
timings: metadata?.timings,
|
|
30409
|
+
...tenantId ? { envelopeVersion: CURRENT_ENVELOPE_VERSION, tenantId } : {}
|
|
30410
|
+
}
|
|
30411
|
+
};
|
|
30412
|
+
}
|
|
30413
|
+
var init_factory = __esm(() => {
|
|
30414
|
+
init_causality();
|
|
30415
|
+
init_envelope();
|
|
30416
|
+
});
|
|
30417
|
+
|
|
30373
30418
|
// ../core/src/events/nats/streams.ts
|
|
30374
30419
|
function getStreamForEventType(eventType) {
|
|
30375
30420
|
const prefix = eventType.split(".")[0] ?? "";
|
|
@@ -30739,7 +30784,24 @@ var init_registry = __esm(() => {
|
|
|
30739
30784
|
component: exports_external.string(),
|
|
30740
30785
|
reason: exports_external.string(),
|
|
30741
30786
|
severity: exports_external.enum(["warning", "critical"])
|
|
30742
|
-
}), { description: "System health degradation detected" })
|
|
30787
|
+
}), { description: "System health degradation detected" }),
|
|
30788
|
+
connectorStalled: createEventSchema("system.connector.stalled", exports_external.object({
|
|
30789
|
+
sourceId: exports_external.string(),
|
|
30790
|
+
sourceName: exports_external.string(),
|
|
30791
|
+
expectedIntervalSeconds: exports_external.number(),
|
|
30792
|
+
lastReceivedAt: exports_external.number().nullable(),
|
|
30793
|
+
lastHeartbeatAt: exports_external.number().nullable(),
|
|
30794
|
+
silentForSeconds: exports_external.number(),
|
|
30795
|
+
stalledAt: exports_external.number()
|
|
30796
|
+
}), { description: "A supervised connector went silent beyond its declared cadence" }),
|
|
30797
|
+
connectorRecovered: createEventSchema("system.connector.recovered", exports_external.object({
|
|
30798
|
+
sourceId: exports_external.string(),
|
|
30799
|
+
sourceName: exports_external.string(),
|
|
30800
|
+
expectedIntervalSeconds: exports_external.number(),
|
|
30801
|
+
stalledForSeconds: exports_external.number(),
|
|
30802
|
+
recoveredBy: exports_external.enum(["event", "heartbeat", "rearmed"]),
|
|
30803
|
+
recoveredAt: exports_external.number()
|
|
30804
|
+
}), { description: "A stalled connector signalled again (event, heartbeat, or re-declared cadence)" })
|
|
30743
30805
|
};
|
|
30744
30806
|
CustomEventSchemas = {
|
|
30745
30807
|
chatUnreadUpdated: createEventSchema("custom.chat.unread-updated", exports_external.object({
|
|
@@ -31159,27 +31221,8 @@ class NatsEventBus {
|
|
|
31159
31221
|
}
|
|
31160
31222
|
async publishInternal(type, payload, metadata) {
|
|
31161
31223
|
await this.ensureConnected();
|
|
31162
|
-
const
|
|
31163
|
-
const
|
|
31164
|
-
const tenantId = resolvePublishTenantId(metadata?.tenantId, metadata?.instanceId);
|
|
31165
|
-
const event = {
|
|
31166
|
-
id: eventId,
|
|
31167
|
-
type,
|
|
31168
|
-
payload,
|
|
31169
|
-
timestamp,
|
|
31170
|
-
metadata: {
|
|
31171
|
-
correlationId: metadata?.correlationId ?? eventId,
|
|
31172
|
-
instanceId: metadata?.instanceId,
|
|
31173
|
-
channelType: metadata?.channelType,
|
|
31174
|
-
personId: metadata?.personId,
|
|
31175
|
-
platformIdentityId: metadata?.platformIdentityId,
|
|
31176
|
-
traceId: metadata?.traceId ?? eventId,
|
|
31177
|
-
source: metadata?.source ?? this.config.serviceName,
|
|
31178
|
-
ingestMode: metadata?.ingestMode,
|
|
31179
|
-
timings: metadata?.timings,
|
|
31180
|
-
...tenantId ? { envelopeVersion: CURRENT_ENVELOPE_VERSION, tenantId } : {}
|
|
31181
|
-
}
|
|
31182
|
-
};
|
|
31224
|
+
const event = createOmniEvent(type, payload, metadata, this.config.serviceName);
|
|
31225
|
+
const eventId = event.id;
|
|
31183
31226
|
let subject;
|
|
31184
31227
|
if (metadata?.channelType && metadata?.instanceId) {
|
|
31185
31228
|
subject = buildSubject(type, metadata.channelType, metadata.instanceId);
|
|
@@ -31455,7 +31498,7 @@ async function connectEventBus(config2) {
|
|
|
31455
31498
|
var import_api2, import_nats, log4, DEFAULTS, ENSURE_CONNECTED_WAIT_MS = 5000;
|
|
31456
31499
|
var init_client = __esm(() => {
|
|
31457
31500
|
init_logger();
|
|
31458
|
-
|
|
31501
|
+
init_factory();
|
|
31459
31502
|
init_consumer();
|
|
31460
31503
|
init_registry();
|
|
31461
31504
|
init_streams();
|
|
@@ -39448,6 +39491,7 @@ function estimateCompletion(progress) {
|
|
|
39448
39491
|
// ../core/src/events/index.ts
|
|
39449
39492
|
var init_events = __esm(() => {
|
|
39450
39493
|
init_types3();
|
|
39494
|
+
init_causality();
|
|
39451
39495
|
init_envelope();
|
|
39452
39496
|
init_nats();
|
|
39453
39497
|
init_dead_letter();
|
|
@@ -45127,13 +45171,7 @@ function resolveFollowUpValue(trimmed, followUp) {
|
|
|
45127
45171
|
return;
|
|
45128
45172
|
}
|
|
45129
45173
|
}
|
|
45130
|
-
function
|
|
45131
|
-
const trimmed = path.trim();
|
|
45132
|
-
if (!trimmed)
|
|
45133
|
-
return;
|
|
45134
|
-
const parts = trimmed.split(".");
|
|
45135
|
-
const root = parts[0] ?? "";
|
|
45136
|
-
const rest = parts.slice(1).join(".");
|
|
45174
|
+
function resolveSpecialValue(trimmed, root, rest, context) {
|
|
45137
45175
|
if (context.debounce) {
|
|
45138
45176
|
const debounceValue = resolveDebounceValue(trimmed, rest, context.debounce);
|
|
45139
45177
|
if (debounceValue !== undefined)
|
|
@@ -45144,6 +45182,21 @@ function resolveTemplatePath(path, context) {
|
|
|
45144
45182
|
if (followUpValue !== undefined)
|
|
45145
45183
|
return followUpValue;
|
|
45146
45184
|
}
|
|
45185
|
+
if (root === "event" && context.event) {
|
|
45186
|
+
return rest ? getNestedValue(context.event, rest) : context.event;
|
|
45187
|
+
}
|
|
45188
|
+
return;
|
|
45189
|
+
}
|
|
45190
|
+
function resolveTemplatePath(path, context) {
|
|
45191
|
+
const trimmed = path.trim();
|
|
45192
|
+
if (!trimmed)
|
|
45193
|
+
return;
|
|
45194
|
+
const parts = trimmed.split(".");
|
|
45195
|
+
const root = parts[0] ?? "";
|
|
45196
|
+
const rest = parts.slice(1).join(".");
|
|
45197
|
+
const specialValue = resolveSpecialValue(trimmed, root, rest, context);
|
|
45198
|
+
if (specialValue !== undefined)
|
|
45199
|
+
return specialValue;
|
|
45147
45200
|
if (root === "payload")
|
|
45148
45201
|
return rest ? getNestedValue(context.payload, rest) : context.payload;
|
|
45149
45202
|
if (root === "env")
|
|
@@ -45225,7 +45278,9 @@ function createTemplateContext(payload, options = {}) {
|
|
|
45225
45278
|
variables: options.variables ?? {},
|
|
45226
45279
|
env: process.env,
|
|
45227
45280
|
debounce: options.debounce,
|
|
45228
|
-
followUp
|
|
45281
|
+
followUp,
|
|
45282
|
+
event: options.event,
|
|
45283
|
+
automation: options.automation
|
|
45229
45284
|
};
|
|
45230
45285
|
}
|
|
45231
45286
|
var TEMPLATE_REGEX;
|
|
@@ -45797,8 +45852,12 @@ var init_egress = __esm(() => {
|
|
|
45797
45852
|
});
|
|
45798
45853
|
|
|
45799
45854
|
// ../core/src/automations/actions.ts
|
|
45800
|
-
function buildWebhookHeaders(config2, context) {
|
|
45855
|
+
function buildWebhookHeaders(config2, context, actionIndex) {
|
|
45801
45856
|
const headers = { "Content-Type": "application/json" };
|
|
45857
|
+
if (context.event) {
|
|
45858
|
+
headers["X-Omni-Event-Id"] = context.event.id;
|
|
45859
|
+
headers["X-Omni-Delivery-Id"] = `${context.event.id}:${context.automation?.id ?? "manual"}:${actionIndex}`;
|
|
45860
|
+
}
|
|
45802
45861
|
if (config2.headers) {
|
|
45803
45862
|
for (const [key, value] of Object.entries(config2.headers)) {
|
|
45804
45863
|
headers[key] = substituteTemplate(value, context);
|
|
@@ -45806,16 +45865,28 @@ function buildWebhookHeaders(config2, context) {
|
|
|
45806
45865
|
}
|
|
45807
45866
|
return headers;
|
|
45808
45867
|
}
|
|
45868
|
+
function buildDefaultWebhookBody(config2, context) {
|
|
45869
|
+
if (context.event && config2.includeEnvelope !== false) {
|
|
45870
|
+
return JSON.stringify({
|
|
45871
|
+
id: context.event.id,
|
|
45872
|
+
type: context.event.type,
|
|
45873
|
+
payload: context.payload,
|
|
45874
|
+
metadata: context.event.metadata,
|
|
45875
|
+
timestamp: context.event.timestamp
|
|
45876
|
+
});
|
|
45877
|
+
}
|
|
45878
|
+
return JSON.stringify(context.payload);
|
|
45879
|
+
}
|
|
45809
45880
|
async function parseWebhookResponse(response) {
|
|
45810
45881
|
const contentType = response.headers.get("content-type") ?? "";
|
|
45811
45882
|
return contentType.includes("application/json") ? response.json() : response.text();
|
|
45812
45883
|
}
|
|
45813
|
-
async function executeWebhookAction(config2, context, _deps, trustedTenantId) {
|
|
45884
|
+
async function executeWebhookAction(config2, context, _deps, trustedTenantId, actionIndex = 0) {
|
|
45814
45885
|
try {
|
|
45815
45886
|
const url = substituteTemplate(config2.url, context);
|
|
45816
45887
|
const method = config2.method ?? "POST";
|
|
45817
|
-
const headers = buildWebhookHeaders(config2, context);
|
|
45818
|
-
const body = config2.bodyTemplate ? substituteTemplate(config2.bodyTemplate, context) :
|
|
45888
|
+
const headers = buildWebhookHeaders(config2, context, actionIndex);
|
|
45889
|
+
const body = config2.bodyTemplate ? substituteTemplate(config2.bodyTemplate, context) : buildDefaultWebhookBody(config2, context);
|
|
45819
45890
|
logger2.debug(`Webhook ${method} ${url}`, { method, url, waitForResponse: config2.waitForResponse });
|
|
45820
45891
|
const response = await brokeredFetch(url, {
|
|
45821
45892
|
method,
|
|
@@ -45905,8 +45976,10 @@ async function executeEmitEventAction(config2, context, deps, trustedTenantId) {
|
|
|
45905
45976
|
}
|
|
45906
45977
|
}
|
|
45907
45978
|
logger2.debug("Emitting event", { eventType });
|
|
45979
|
+
const correlationId = context.event?.metadata.correlationId ?? context.payload.correlationId ?? undefined;
|
|
45908
45980
|
const result = await deps.eventBus.publishGeneric(eventType, payload, {
|
|
45909
|
-
correlationId
|
|
45981
|
+
correlationId,
|
|
45982
|
+
causationId: context.event?.id,
|
|
45910
45983
|
source: "automation",
|
|
45911
45984
|
...trustedTenantId ? { tenantId: trustedTenantId } : {}
|
|
45912
45985
|
});
|
|
@@ -45999,7 +46072,12 @@ function extractAgentCallContext(config2, context) {
|
|
|
45999
46072
|
threadId,
|
|
46000
46073
|
senderId,
|
|
46001
46074
|
senderName,
|
|
46002
|
-
messages: messagesResult
|
|
46075
|
+
messages: messagesResult,
|
|
46076
|
+
event: context.event ? {
|
|
46077
|
+
id: context.event.id,
|
|
46078
|
+
type: context.event.type,
|
|
46079
|
+
correlationId: context.event.metadata.correlationId
|
|
46080
|
+
} : undefined
|
|
46003
46081
|
}
|
|
46004
46082
|
};
|
|
46005
46083
|
}
|
|
@@ -46040,12 +46118,12 @@ async function executeCallAgentAction(config2, context, deps, trustedTenantId) {
|
|
|
46040
46118
|
return { success: false, error: errorMessage };
|
|
46041
46119
|
}
|
|
46042
46120
|
}
|
|
46043
|
-
async function executeAction(action, context, deps, trustedTenantId) {
|
|
46121
|
+
async function executeAction(action, context, deps, trustedTenantId, actionIndex = 0) {
|
|
46044
46122
|
const start = Date.now();
|
|
46045
46123
|
let result;
|
|
46046
46124
|
switch (action.type) {
|
|
46047
46125
|
case "webhook":
|
|
46048
|
-
result = await executeWebhookAction(action.config, context, deps, trustedTenantId);
|
|
46126
|
+
result = await executeWebhookAction(action.config, context, deps, trustedTenantId, actionIndex);
|
|
46049
46127
|
break;
|
|
46050
46128
|
case "send_message":
|
|
46051
46129
|
result = await executeSendMessageAction(action.config, context, deps, trustedTenantId);
|
|
@@ -46074,12 +46152,12 @@ async function executeAction(action, context, deps, trustedTenantId) {
|
|
|
46074
46152
|
async function executeActions(actions, context, deps, trustedTenantId) {
|
|
46075
46153
|
const results = [];
|
|
46076
46154
|
const variables = { ...context.variables };
|
|
46077
|
-
for (const action of actions) {
|
|
46155
|
+
for (const [actionIndex, action] of actions.entries()) {
|
|
46078
46156
|
const actionContext = {
|
|
46079
46157
|
...context,
|
|
46080
46158
|
variables
|
|
46081
46159
|
};
|
|
46082
|
-
const result = await executeAction(action, actionContext, deps, trustedTenantId);
|
|
46160
|
+
const result = await executeAction(action, actionContext, deps, trustedTenantId, actionIndex);
|
|
46083
46161
|
results.push(result);
|
|
46084
46162
|
if (action.type === "webhook" && action.config.responseAs && result.status === "success" && result.result) {
|
|
46085
46163
|
variables[action.config.responseAs] = result.result;
|
|
@@ -46509,13 +46587,18 @@ class AutomationEngine {
|
|
|
46509
46587
|
type: content?.type ?? "unknown",
|
|
46510
46588
|
text: content?.text,
|
|
46511
46589
|
timestamp: event.timestamp,
|
|
46512
|
-
payload
|
|
46590
|
+
payload,
|
|
46591
|
+
eventId: event.id,
|
|
46592
|
+
correlationId: event.metadata.correlationId
|
|
46513
46593
|
};
|
|
46514
46594
|
manager.addMessage(key, message2, from, instanceId, stamp);
|
|
46515
46595
|
}
|
|
46516
46596
|
async handleImmediate(automation, event) {
|
|
46517
46597
|
const instanceId = event.metadata.instanceId ?? "global";
|
|
46518
|
-
const context = createTemplateContext(event.payload
|
|
46598
|
+
const context = createTemplateContext(event.payload, {
|
|
46599
|
+
event: { id: event.id, type: event.type, timestamp: event.timestamp, metadata: event.metadata },
|
|
46600
|
+
automation: { id: automation.id }
|
|
46601
|
+
});
|
|
46519
46602
|
await this.queueExecution(automation, event, context, instanceId);
|
|
46520
46603
|
}
|
|
46521
46604
|
setupDebounceManager(automation) {
|
|
@@ -46525,28 +46608,35 @@ class AutomationEngine {
|
|
|
46525
46608
|
logger4.warn("Debounce callback fired with empty messages array", { key });
|
|
46526
46609
|
return;
|
|
46527
46610
|
}
|
|
46528
|
-
const context = createTemplateContext(lastMessage.payload, {
|
|
46529
|
-
debounce: {
|
|
46530
|
-
messages: messages2.map((m2) => ({
|
|
46531
|
-
type: m2.type,
|
|
46532
|
-
text: m2.text,
|
|
46533
|
-
timestamp: m2.timestamp
|
|
46534
|
-
})),
|
|
46535
|
-
from,
|
|
46536
|
-
instanceId
|
|
46537
|
-
}
|
|
46538
|
-
});
|
|
46539
46611
|
const syntheticEvent = {
|
|
46540
46612
|
id: generateId(),
|
|
46541
46613
|
type: automation.triggerEventType,
|
|
46542
46614
|
payload: lastMessage.payload,
|
|
46543
46615
|
metadata: {
|
|
46544
|
-
correlationId: generateId(),
|
|
46616
|
+
correlationId: lastMessage.correlationId ?? generateId(),
|
|
46545
46617
|
instanceId,
|
|
46546
46618
|
...stamp ? { envelopeVersion: stamp.envelopeVersion, tenantId: stamp.tenantId } : {}
|
|
46547
46619
|
},
|
|
46548
46620
|
timestamp: Date.now()
|
|
46549
46621
|
};
|
|
46622
|
+
const context = createTemplateContext(lastMessage.payload, {
|
|
46623
|
+
debounce: {
|
|
46624
|
+
messages: messages2.map((m2) => ({
|
|
46625
|
+
type: m2.type,
|
|
46626
|
+
text: m2.text,
|
|
46627
|
+
timestamp: m2.timestamp
|
|
46628
|
+
})),
|
|
46629
|
+
from,
|
|
46630
|
+
instanceId
|
|
46631
|
+
},
|
|
46632
|
+
event: {
|
|
46633
|
+
id: lastMessage.eventId ?? syntheticEvent.id,
|
|
46634
|
+
type: syntheticEvent.type,
|
|
46635
|
+
timestamp: syntheticEvent.timestamp,
|
|
46636
|
+
metadata: syntheticEvent.metadata
|
|
46637
|
+
},
|
|
46638
|
+
automation: { id: automation.id }
|
|
46639
|
+
});
|
|
46550
46640
|
await this.queueExecution(automation, syntheticEvent, context, instanceId);
|
|
46551
46641
|
};
|
|
46552
46642
|
const manager = new DebounceManager(automation.debounce, callback);
|
|
@@ -46634,7 +46724,10 @@ class AutomationEngine {
|
|
|
46634
46724
|
await this.logExecution(result2, trustedTenantId);
|
|
46635
46725
|
return result2;
|
|
46636
46726
|
}
|
|
46637
|
-
const actionsExecuted = await
|
|
46727
|
+
const actionsExecuted = await runWithEventCausality({
|
|
46728
|
+
correlationId: context.event?.metadata.correlationId ?? event.metadata.correlationId,
|
|
46729
|
+
causationId: context.event?.id ?? event.id
|
|
46730
|
+
}, () => executeActions(automation.actions, context, this.deps, trustedTenantId));
|
|
46638
46731
|
const allSucceeded = actionsExecuted.every((a) => a.status === "success");
|
|
46639
46732
|
const status = allSucceeded ? "success" : "failed";
|
|
46640
46733
|
const result = {
|
|
@@ -46730,6 +46823,7 @@ function createAutomationEngine(config2) {
|
|
|
46730
46823
|
}
|
|
46731
46824
|
var logger4, QueueFullError;
|
|
46732
46825
|
var init_engine = __esm(() => {
|
|
46826
|
+
init_causality();
|
|
46733
46827
|
init_envelope();
|
|
46734
46828
|
init_ids();
|
|
46735
46829
|
init_logger();
|
|
@@ -47118,6 +47212,113 @@ var init_automations = __esm(() => {
|
|
|
47118
47212
|
init_sweeper();
|
|
47119
47213
|
});
|
|
47120
47214
|
|
|
47215
|
+
// ../core/src/connectors/liveness.ts
|
|
47216
|
+
function latestConnectorSignal(row) {
|
|
47217
|
+
let best = { at: row.createdAt, kind: "rearmed" };
|
|
47218
|
+
const candidates = [
|
|
47219
|
+
{ at: row.livenessArmedAt, kind: "rearmed" },
|
|
47220
|
+
{ at: row.lastReceivedAt, kind: "event" },
|
|
47221
|
+
{ at: row.lastHeartbeatAt, kind: "heartbeat" }
|
|
47222
|
+
];
|
|
47223
|
+
for (const candidate of candidates) {
|
|
47224
|
+
if (candidate.at && candidate.at.getTime() >= best.at.getTime()) {
|
|
47225
|
+
best = { at: candidate.at, kind: candidate.kind };
|
|
47226
|
+
}
|
|
47227
|
+
}
|
|
47228
|
+
return best;
|
|
47229
|
+
}
|
|
47230
|
+
async function sweepConnectorLiveness(deps) {
|
|
47231
|
+
const clock = deps.now ?? (() => new Date);
|
|
47232
|
+
const now = clock();
|
|
47233
|
+
const rows = await deps.repo.findSupervised();
|
|
47234
|
+
const stats = { scanned: rows.length, stalled: 0, recovered: 0, errors: 0 };
|
|
47235
|
+
for (const row of rows) {
|
|
47236
|
+
try {
|
|
47237
|
+
await processRow2(row, now, deps, stats);
|
|
47238
|
+
} catch (err2) {
|
|
47239
|
+
stats.errors += 1;
|
|
47240
|
+
deps.logger.error("connector liveness: failed to process source", {
|
|
47241
|
+
sourceId: row.id,
|
|
47242
|
+
sourceName: row.name,
|
|
47243
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
47244
|
+
});
|
|
47245
|
+
}
|
|
47246
|
+
}
|
|
47247
|
+
if (stats.stalled > 0 || stats.recovered > 0) {
|
|
47248
|
+
deps.logger.info("connector liveness sweep tick", { ...stats });
|
|
47249
|
+
}
|
|
47250
|
+
return stats;
|
|
47251
|
+
}
|
|
47252
|
+
async function processRow2(row, now, deps, stats) {
|
|
47253
|
+
const signal = latestConnectorSignal(row);
|
|
47254
|
+
const silentMs = Math.max(0, now.getTime() - signal.at.getTime());
|
|
47255
|
+
const overdue = silentMs > row.expectedIntervalSeconds * 1000;
|
|
47256
|
+
const silentForSeconds = Math.round(silentMs / 1000);
|
|
47257
|
+
if (overdue) {
|
|
47258
|
+
if (row.livenessStatus === "stalled")
|
|
47259
|
+
return;
|
|
47260
|
+
if (!await deps.repo.markStalled(row.id, now))
|
|
47261
|
+
return;
|
|
47262
|
+
const payload = {
|
|
47263
|
+
sourceId: row.id,
|
|
47264
|
+
sourceName: row.name,
|
|
47265
|
+
expectedIntervalSeconds: row.expectedIntervalSeconds,
|
|
47266
|
+
lastReceivedAt: row.lastReceivedAt?.getTime() ?? null,
|
|
47267
|
+
lastHeartbeatAt: row.lastHeartbeatAt?.getTime() ?? null,
|
|
47268
|
+
silentForSeconds,
|
|
47269
|
+
stalledAt: now.getTime()
|
|
47270
|
+
};
|
|
47271
|
+
const eventId = await publishTransition(deps, "system.connector.stalled", { ...payload }, row);
|
|
47272
|
+
stats.stalled += 1;
|
|
47273
|
+
await runHook(deps.logger, "onStalled", row, () => deps.onStalled?.(row, payload, eventId));
|
|
47274
|
+
return;
|
|
47275
|
+
}
|
|
47276
|
+
if (row.livenessStatus === "stalled") {
|
|
47277
|
+
if (!await deps.repo.markRecovered(row.id, now))
|
|
47278
|
+
return;
|
|
47279
|
+
const stalledSince = row.stalledAt ?? signal.at;
|
|
47280
|
+
const payload = {
|
|
47281
|
+
sourceId: row.id,
|
|
47282
|
+
sourceName: row.name,
|
|
47283
|
+
expectedIntervalSeconds: row.expectedIntervalSeconds,
|
|
47284
|
+
stalledForSeconds: Math.max(0, Math.round((now.getTime() - stalledSince.getTime()) / 1000)),
|
|
47285
|
+
recoveredBy: signal.kind,
|
|
47286
|
+
recoveredAt: now.getTime()
|
|
47287
|
+
};
|
|
47288
|
+
await publishTransition(deps, "system.connector.recovered", { ...payload }, row);
|
|
47289
|
+
stats.recovered += 1;
|
|
47290
|
+
await runHook(deps.logger, "onRecovered", row, () => deps.onRecovered?.(row, payload));
|
|
47291
|
+
}
|
|
47292
|
+
}
|
|
47293
|
+
async function publishTransition(deps, type, payload, row) {
|
|
47294
|
+
if (!deps.eventBus) {
|
|
47295
|
+
deps.logger.warn("connector liveness: no event bus, transition persisted without event", {
|
|
47296
|
+
type,
|
|
47297
|
+
sourceName: row.name
|
|
47298
|
+
});
|
|
47299
|
+
return null;
|
|
47300
|
+
}
|
|
47301
|
+
const result = await deps.eventBus.publishGeneric(type, payload, {
|
|
47302
|
+
source: "connector-liveness",
|
|
47303
|
+
...row.tenantId ? { tenantId: row.tenantId } : {}
|
|
47304
|
+
});
|
|
47305
|
+
return result.id;
|
|
47306
|
+
}
|
|
47307
|
+
async function runHook(logger5, name, row, hook) {
|
|
47308
|
+
try {
|
|
47309
|
+
await hook();
|
|
47310
|
+
} catch (err2) {
|
|
47311
|
+
logger5.error(`connector liveness: ${name} hook failed`, {
|
|
47312
|
+
sourceId: row.id,
|
|
47313
|
+
sourceName: row.name,
|
|
47314
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
47315
|
+
});
|
|
47316
|
+
}
|
|
47317
|
+
}
|
|
47318
|
+
|
|
47319
|
+
// ../core/src/connectors/index.ts
|
|
47320
|
+
var init_connectors = () => {};
|
|
47321
|
+
|
|
47121
47322
|
// ../core/src/sessions/reset.ts
|
|
47122
47323
|
class InMemorySessionActivityStore {
|
|
47123
47324
|
activities = new Map;
|
|
@@ -74531,7 +74732,7 @@ function isProviderSchemaSupported(schema) {
|
|
|
74531
74732
|
function getSupportedProviderSchemas() {
|
|
74532
74733
|
return ["agno", "webhook", "openclaw", "claude-code", "ag-ui", "a2a", "nats-genie"];
|
|
74533
74734
|
}
|
|
74534
|
-
var
|
|
74735
|
+
var init_factory2 = __esm(() => {
|
|
74535
74736
|
init_a2a_client();
|
|
74536
74737
|
init_ag_ui_client();
|
|
74537
74738
|
init_agno_client();
|
|
@@ -74551,7 +74752,7 @@ var init_providers = __esm(() => {
|
|
|
74551
74752
|
init_ag_ui_provider();
|
|
74552
74753
|
init_a2a_provider();
|
|
74553
74754
|
init_nats_genie_provider();
|
|
74554
|
-
|
|
74755
|
+
init_factory2();
|
|
74555
74756
|
});
|
|
74556
74757
|
|
|
74557
74758
|
// ../core/src/cache/types.ts
|
|
@@ -75220,6 +75421,7 @@ __export(exports_src, {
|
|
|
75220
75421
|
tenantLabelBucketCount: () => tenantLabelBucketCount,
|
|
75221
75422
|
tenantEventsProcessed: () => tenantEventsProcessed,
|
|
75222
75423
|
sweepFollowUps: () => sweepFollowUps,
|
|
75424
|
+
sweepConnectorLiveness: () => sweepConnectorLiveness,
|
|
75223
75425
|
substituteTemplateObject: () => substituteTemplateObject,
|
|
75224
75426
|
substituteTemplate: () => substituteTemplate,
|
|
75225
75427
|
stampsEqual: () => stampsEqual,
|
|
@@ -75234,6 +75436,7 @@ __export(exports_src, {
|
|
|
75234
75436
|
scheduledJobRuns: () => scheduledJobRuns,
|
|
75235
75437
|
scheduledJobNextRun: () => scheduledJobNextRun,
|
|
75236
75438
|
scheduledJobDuration: () => scheduledJobDuration,
|
|
75439
|
+
runWithEventCausality: () => runWithEventCausality,
|
|
75237
75440
|
rootLogger: () => rootLogger,
|
|
75238
75441
|
resolveResetConfig: () => resolveResetConfig,
|
|
75239
75442
|
resolvePublishTenantId: () => resolvePublishTenantId,
|
|
@@ -75282,6 +75485,7 @@ __export(exports_src, {
|
|
|
75282
75485
|
natsConnectionStatus: () => natsConnectionStatus,
|
|
75283
75486
|
matchesPattern: () => matchesPattern,
|
|
75284
75487
|
markdownToWhatsApp: () => markdownToWhatsApp,
|
|
75488
|
+
latestConnectorSignal: () => latestConnectorSignal,
|
|
75285
75489
|
jsonEquals: () => jsonEquals,
|
|
75286
75490
|
isValidUuid: () => isValidUuid,
|
|
75287
75491
|
isValidJsonSchema: () => isValidJsonSchema,
|
|
@@ -75345,6 +75549,7 @@ __export(exports_src, {
|
|
|
75345
75549
|
dbQueries: () => dbQueries,
|
|
75346
75550
|
dbPoolSize: () => dbPoolSize,
|
|
75347
75551
|
dbErrors: () => dbErrors,
|
|
75552
|
+
currentEventCausality: () => currentEventCausality,
|
|
75348
75553
|
createValidatedSubscription: () => createValidatedSubscription,
|
|
75349
75554
|
createTemplateContext: () => createTemplateContext,
|
|
75350
75555
|
createSubscription: () => createSubscription,
|
|
@@ -75607,6 +75812,7 @@ var init_src2 = __esm(() => {
|
|
|
75607
75812
|
init_observability();
|
|
75608
75813
|
init_secrets();
|
|
75609
75814
|
init_automations();
|
|
75815
|
+
init_connectors();
|
|
75610
75816
|
init_reset();
|
|
75611
75817
|
init_providers();
|
|
75612
75818
|
init_cache();
|
|
@@ -80968,6 +81174,9 @@ __export(exports_schema, {
|
|
|
80968
81174
|
conversations: () => conversations,
|
|
80969
81175
|
contentTypes: () => contentTypes,
|
|
80970
81176
|
consumerOffsets: () => consumerOffsets,
|
|
81177
|
+
connectorWindowSemanticsValues: () => connectorWindowSemanticsValues,
|
|
81178
|
+
connectorMutationPolicies: () => connectorMutationPolicies,
|
|
81179
|
+
connectorLivenessStatuses: () => connectorLivenessStatuses,
|
|
80971
81180
|
conditionOperators: () => conditionOperators,
|
|
80972
81181
|
closeContactOutcomes: () => closeContactOutcomes,
|
|
80973
81182
|
closeContactLogs: () => closeContactLogs,
|
|
@@ -81016,7 +81225,7 @@ __export(exports_schema, {
|
|
|
81016
81225
|
accessRules: () => accessRules,
|
|
81017
81226
|
accessModes: () => accessModes
|
|
81018
81227
|
});
|
|
81019
|
-
var channelTypes, agentTypes, agentSystems, agentEntityTypes, debounceMode, splitDelayMode, supersedeMode, replyFilterMode, agentSessionStrategies, ruleTypes, accessModes, settingValueTypes, apiKeyStatuses, apiKeyProfiles, eventTypes, contentTypes, chatTypes, messageSources, messageTypes, messageStatuses, deliveryStatuses, scheduledMessageDeliveryModes, scheduledMessageStatuses, jobStatuses, providerSchemas, agentProviders, agents, agentRoutes, agentSessions, apiKeys, apiKeyAuditLogs, apiKeysRelations, apiKeyAuditLogsRelations, instances, whatsappTemplates, whatsappFlowKeys, scheduledMessages, persons, platformIdentities, conversations, chats, chatParticipants, omniGroups, messages2, omniEvents, handoffLogs, closeContactOutcomes, closeContactLogs, accessRules, globalSettings, settingChangeHistory, batchJobs, syncJobTypes, syncJobs, mediaContent, chatIdMappings, pluginStorage, agentProvidersRelations, agentsRelations, instancesRelations, syncJobsRelations, personsRelations, platformIdentitiesRelations, conversationsRelations, chatsRelations, chatParticipantsRelations, messagesRelations, omniEventsRelations, accessRulesRelations, globalSettingsRelations, settingChangeHistoryRelations, batchJobsRelations, mediaContentRelations, chatIdMappingsRelations, deadLetterStatuses, deadLetterEvents, payloadStorageConfig, payloadStages, eventPayloads, webhookSignatureAlgorithms, webhookSources, eventSchemas, conditionOperators, actionTypes, automationDebounceModes, automations2, automationLogStatuses, automationLogs, consumerOffsets, automationsRelations, automationLogsRelations, triggerLogs, triggerLogsRelations, agentRoutesRelations, agentTaskStatuses, agentTasks, agentTasksRelations, turnStatuses, turnActions, turns, turnsRelations, followUpDisarmReasons, chatFollowUpState, chatFollowUpStateRelations, processedEvents, genieHosts, tenantStatuses, principalTypes, principalStatuses, tenantRoles, membershipStatuses, credentialClasses, authCredentialStatuses, platformApiKeyStatuses, tenants, principals, tenantMemberships, tenantRolePolicies, platformApiKeys, tenantKeyLineage, authCredentials, tenantAuditLogs, platformAuditLogs, platformProviderCatalog, tenantProviderConfig, platformSettings, tenantSettings, platformSettingChangeHistory, tenantSettingChangeHistory, platformPluginStorage, tenantPluginStorage, platformPayloadStorageConfig, tenantPayloadStorageOverrides, tenantMigrationLedger, tenantMigrationLedgerHistory;
|
|
81228
|
+
var channelTypes, agentTypes, agentSystems, agentEntityTypes, debounceMode, splitDelayMode, supersedeMode, replyFilterMode, agentSessionStrategies, ruleTypes, accessModes, settingValueTypes, apiKeyStatuses, apiKeyProfiles, eventTypes, contentTypes, chatTypes, messageSources, messageTypes, messageStatuses, deliveryStatuses, scheduledMessageDeliveryModes, scheduledMessageStatuses, jobStatuses, providerSchemas, agentProviders, agents, agentRoutes, agentSessions, apiKeys, apiKeyAuditLogs, apiKeysRelations, apiKeyAuditLogsRelations, instances, whatsappTemplates, whatsappFlowKeys, scheduledMessages, persons, platformIdentities, conversations, chats, chatParticipants, omniGroups, messages2, omniEvents, handoffLogs, closeContactOutcomes, closeContactLogs, accessRules, globalSettings, settingChangeHistory, batchJobs, syncJobTypes, syncJobs, mediaContent, chatIdMappings, pluginStorage, agentProvidersRelations, agentsRelations, instancesRelations, syncJobsRelations, personsRelations, platformIdentitiesRelations, conversationsRelations, chatsRelations, chatParticipantsRelations, messagesRelations, omniEventsRelations, accessRulesRelations, globalSettingsRelations, settingChangeHistoryRelations, batchJobsRelations, mediaContentRelations, chatIdMappingsRelations, deadLetterStatuses, deadLetterEvents, payloadStorageConfig, payloadStages, eventPayloads, webhookSignatureAlgorithms, connectorLivenessStatuses, connectorWindowSemanticsValues, connectorMutationPolicies, webhookSources, eventSchemas, conditionOperators, actionTypes, automationDebounceModes, automations2, automationLogStatuses, automationLogs, consumerOffsets, automationsRelations, automationLogsRelations, triggerLogs, triggerLogsRelations, agentRoutesRelations, agentTaskStatuses, agentTasks, agentTasksRelations, turnStatuses, turnActions, turns, turnsRelations, followUpDisarmReasons, chatFollowUpState, chatFollowUpStateRelations, processedEvents, genieHosts, tenantStatuses, principalTypes, principalStatuses, tenantRoles, membershipStatuses, credentialClasses, authCredentialStatuses, platformApiKeyStatuses, tenants, principals, tenantMemberships, tenantRolePolicies, platformApiKeys, tenantKeyLineage, authCredentials, tenantAuditLogs, platformAuditLogs, platformProviderCatalog, tenantProviderConfig, platformSettings, tenantSettings, platformSettingChangeHistory, tenantSettingChangeHistory, platformPluginStorage, tenantPluginStorage, platformPayloadStorageConfig, tenantPayloadStorageOverrides, tenantMigrationLedger, tenantMigrationLedgerHistory;
|
|
81020
81229
|
var init_schema2 = __esm(() => {
|
|
81021
81230
|
init_events();
|
|
81022
81231
|
init_types5();
|
|
@@ -81748,9 +81957,11 @@ var init_schema2 = __esm(() => {
|
|
|
81748
81957
|
agentRequest: jsonb("agent_request").$type(),
|
|
81749
81958
|
agentResponse: jsonb("agent_response").$type(),
|
|
81750
81959
|
metadata: jsonb("metadata").$type(),
|
|
81960
|
+
causationId: uuid("causation_id"),
|
|
81751
81961
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
81752
81962
|
tenantId: uuid("tenant_id").references(() => tenants.id, { onDelete: "restrict" })
|
|
81753
81963
|
}, (table3) => ({
|
|
81964
|
+
causationIdx: index("omni_events_causation_idx").on(table3.causationId),
|
|
81754
81965
|
tenantIdx: index("omni_events_tenant_idx").on(table3.tenantId),
|
|
81755
81966
|
tenantIdUq: uniqueIndex("omni_events_tenant_id_uq").on(table3.tenantId, table3.id),
|
|
81756
81967
|
externalIdIdx: index("omni_events_external_id_idx").on(table3.externalId),
|
|
@@ -82229,6 +82440,9 @@ var init_schema2 = __esm(() => {
|
|
|
82229
82440
|
eventStageIdx: index("event_payloads_event_stage_idx").on(table3.eventId, table3.stage)
|
|
82230
82441
|
}));
|
|
82231
82442
|
webhookSignatureAlgorithms = ["hmac-sha256", "hmac-sha1", "token-match"];
|
|
82443
|
+
connectorLivenessStatuses = ["healthy", "stalled"];
|
|
82444
|
+
connectorWindowSemanticsValues = ["future_only", "includes_in_progress"];
|
|
82445
|
+
connectorMutationPolicies = ["same_id", "new_id"];
|
|
82232
82446
|
webhookSources = pgTable("webhook_sources", {
|
|
82233
82447
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
82234
82448
|
name: varchar("name", { length: 100 }).notNull().unique(),
|
|
@@ -82240,6 +82454,14 @@ var init_schema2 = __esm(() => {
|
|
|
82240
82454
|
enabled: boolean2("enabled").notNull().default(true),
|
|
82241
82455
|
lastReceivedAt: timestamp("last_received_at", { withTimezone: true }),
|
|
82242
82456
|
totalReceived: integer("total_received").notNull().default(0),
|
|
82457
|
+
expectedIntervalSeconds: integer("expected_interval_seconds"),
|
|
82458
|
+
lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }),
|
|
82459
|
+
heartbeatCount: integer("heartbeat_count").notNull().default(0),
|
|
82460
|
+
livenessStatus: varchar("liveness_status", { length: 20 }).$type(),
|
|
82461
|
+
livenessArmedAt: timestamp("liveness_armed_at", { withTimezone: true }),
|
|
82462
|
+
stalledAt: timestamp("stalled_at", { withTimezone: true }),
|
|
82463
|
+
windowSemantics: varchar("window_semantics", { length: 40 }).$type(),
|
|
82464
|
+
mutationPolicy: varchar("mutation_policy", { length: 20 }).$type(),
|
|
82243
82465
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
82244
82466
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
82245
82467
|
tenantId: uuid("tenant_id").references(() => tenants.id, { onDelete: "restrict" })
|
|
@@ -82247,7 +82469,8 @@ var init_schema2 = __esm(() => {
|
|
|
82247
82469
|
tenantIdx: index("webhook_sources_tenant_idx").on(table3.tenantId),
|
|
82248
82470
|
tenantNameUq: uniqueIndex("webhook_sources_tenant_name_uq").on(table3.tenantId, table3.name).where(sql`${table3.tenantId} IS NOT NULL`),
|
|
82249
82471
|
nameIdx: uniqueIndex("webhook_sources_name_idx").on(table3.name),
|
|
82250
|
-
enabledIdx: index("webhook_sources_enabled_idx").on(table3.enabled)
|
|
82472
|
+
enabledIdx: index("webhook_sources_enabled_idx").on(table3.enabled),
|
|
82473
|
+
supervisedIdx: index("webhook_sources_supervised_idx").on(table3.enabled).where(sql`${table3.expectedIntervalSeconds} IS NOT NULL`)
|
|
82251
82474
|
}));
|
|
82252
82475
|
eventSchemas = pgTable("event_schemas", {
|
|
82253
82476
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
@@ -135302,6 +135525,13 @@ function createOmniClient(config) {
|
|
|
135302
135525
|
const { data, error, response } = await client.POST("/events/trigger", { body });
|
|
135303
135526
|
throwIfError(response, error);
|
|
135304
135527
|
return data ?? { eventId: "", eventType: body.eventType };
|
|
135528
|
+
},
|
|
135529
|
+
async heartbeat(source) {
|
|
135530
|
+
const { data, error, response } = await client.POST("/webhooks/{source}/heartbeat", {
|
|
135531
|
+
params: { path: { source } }
|
|
135532
|
+
});
|
|
135533
|
+
throwIfError(response, error);
|
|
135534
|
+
return data;
|
|
135305
135535
|
}
|
|
135306
135536
|
},
|
|
135307
135537
|
payloads: {
|
|
@@ -136109,7 +136339,7 @@ import { fileURLToPath } from "url";
|
|
|
136109
136339
|
// package.json
|
|
136110
136340
|
var package_default = {
|
|
136111
136341
|
name: "@automagik/omni",
|
|
136112
|
-
version: "2.260906.
|
|
136342
|
+
version: "2.260906.4",
|
|
136113
136343
|
repository: {
|
|
136114
136344
|
type: "git",
|
|
136115
136345
|
url: "git+https://github.com/automagik-dev/omni.git",
|
|
@@ -142734,6 +142964,46 @@ ${title}:`);
|
|
|
142734
142964
|
const items = Object.entries(record).sort(([, a], [, b2]) => b2 - a).map(([key, count]) => ({ [keyName]: key, count }));
|
|
142735
142965
|
list(items);
|
|
142736
142966
|
}
|
|
142967
|
+
async function fetchTrace(id) {
|
|
142968
|
+
const config = loadConfig();
|
|
142969
|
+
const baseUrl = config.apiUrl ?? "http://localhost:8882";
|
|
142970
|
+
const resp = await fetch(`${baseUrl}/api/v2/events/${encodeURIComponent(id)}/trace`, {
|
|
142971
|
+
headers: { "x-api-key": config.apiKey ?? "" }
|
|
142972
|
+
});
|
|
142973
|
+
if (!resp.ok) {
|
|
142974
|
+
throw new Error(`API returned ${resp.status}: ${await resp.text()}`);
|
|
142975
|
+
}
|
|
142976
|
+
return (await resp.json()).data;
|
|
142977
|
+
}
|
|
142978
|
+
function formatTraceLine(event, marker) {
|
|
142979
|
+
const time = new Date(event.receivedAt).toISOString().replace("T", " ").slice(0, 19);
|
|
142980
|
+
const corr = event.metadata?.correlationId?.slice(0, 8) ?? "--------";
|
|
142981
|
+
const text = event.textContent ? ` "${event.textContent.slice(0, 40)}"` : "";
|
|
142982
|
+
return `${marker}${event.eventType} ${event.id.slice(0, 8)} ${time} corr=${corr}${text}`;
|
|
142983
|
+
}
|
|
142984
|
+
function displayTrace(data2) {
|
|
142985
|
+
if (getOutputFormat() === "json") {
|
|
142986
|
+
data(data2);
|
|
142987
|
+
return;
|
|
142988
|
+
}
|
|
142989
|
+
let indent = 0;
|
|
142990
|
+
for (const ancestor of data2.ancestors) {
|
|
142991
|
+
const label = indent === 0 && !ancestor.causationId ? " (root)" : "";
|
|
142992
|
+
raw(`${" ".repeat(indent)}${formatTraceLine(ancestor, indent === 0 ? "\u25CF " : "\u2514\u2500 ")}${label}`);
|
|
142993
|
+
indent++;
|
|
142994
|
+
}
|
|
142995
|
+
const focusIsRoot = data2.ancestors.length === 0 && !data2.event.causationId;
|
|
142996
|
+
raw(`${" ".repeat(indent)}${formatTraceLine(data2.event, indent === 0 ? "\u25CF " : "\u2514\u2500 ")}${focusIsRoot ? " (root)" : ""} \u2190 trace target`);
|
|
142997
|
+
for (const { event, depth } of data2.descendants) {
|
|
142998
|
+
raw(`${" ".repeat(indent + depth)}${formatTraceLine(event, "\u2514\u2500 ")}`);
|
|
142999
|
+
}
|
|
143000
|
+
if (data2.descendants.length === 0) {
|
|
143001
|
+
dim("(no descendants \u2014 nothing was caused by this event)");
|
|
143002
|
+
}
|
|
143003
|
+
if (data2.truncated) {
|
|
143004
|
+
warn("Trace truncated (depth/node cap reached)");
|
|
143005
|
+
}
|
|
143006
|
+
}
|
|
142737
143007
|
async function schemaApiRequest(path, init = {}) {
|
|
142738
143008
|
const config = loadConfig();
|
|
142739
143009
|
const baseUrl = config.apiUrl ?? "http://localhost:8882";
|
|
@@ -142980,6 +143250,15 @@ function createEventsCommand() {
|
|
|
142980
143250
|
error(`Failed to get event: ${message}`);
|
|
142981
143251
|
}
|
|
142982
143252
|
});
|
|
143253
|
+
events.command("trace <id>").description("Walk the causality chain around an event: root \u2192 parents \u2192 this event \u2192 everything it caused").action(async (id) => {
|
|
143254
|
+
try {
|
|
143255
|
+
const data2 = await fetchTrace(id);
|
|
143256
|
+
displayTrace(data2);
|
|
143257
|
+
} catch (err) {
|
|
143258
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
143259
|
+
error(`Failed to trace event: ${message}`);
|
|
143260
|
+
}
|
|
143261
|
+
});
|
|
142983
143262
|
events.command("search <query>").description("Search events by content").option("--since <time>", "Events since (e.g., 24h, 7d)").option("--limit <n>", "Limit results", (v) => Number.parseInt(v, 10), 50).action(async (query, options) => {
|
|
142984
143263
|
const client = getClient();
|
|
142985
143264
|
try {
|
|
@@ -150609,6 +150888,53 @@ function assertPairedSignatureOnCreate(signatureConfig, signatureSecret) {
|
|
|
150609
150888
|
}
|
|
150610
150889
|
throw new Error(`--signature-algorithm and --signature-header require a signature secret (${SECRET_SOURCE_FLAGS})`);
|
|
150611
150890
|
}
|
|
150891
|
+
var WINDOW_SEMANTICS = ["future_only", "includes_in_progress"];
|
|
150892
|
+
var MUTATION_POLICIES = ["same_id", "new_id"];
|
|
150893
|
+
function parseExpectedInterval(raw2) {
|
|
150894
|
+
if (raw2 === undefined)
|
|
150895
|
+
return;
|
|
150896
|
+
const seconds = Number(raw2);
|
|
150897
|
+
if (!Number.isInteger(seconds) || seconds < 1) {
|
|
150898
|
+
error("--expected-interval must be a positive integer number of seconds");
|
|
150899
|
+
}
|
|
150900
|
+
return seconds;
|
|
150901
|
+
}
|
|
150902
|
+
function parseWindowSemantics(raw2) {
|
|
150903
|
+
if (raw2 === undefined)
|
|
150904
|
+
return;
|
|
150905
|
+
const value = WINDOW_SEMANTICS.find((v4) => v4 === raw2);
|
|
150906
|
+
if (!value) {
|
|
150907
|
+
error(`Invalid --window-semantics; expected one of: ${WINDOW_SEMANTICS.join(", ")}`);
|
|
150908
|
+
}
|
|
150909
|
+
return value;
|
|
150910
|
+
}
|
|
150911
|
+
function parseMutationPolicy(raw2) {
|
|
150912
|
+
if (raw2 === undefined)
|
|
150913
|
+
return;
|
|
150914
|
+
const value = MUTATION_POLICIES.find((v4) => v4 === raw2);
|
|
150915
|
+
if (!value) {
|
|
150916
|
+
error(`Invalid --mutation-policy; expected one of: ${MUTATION_POLICIES.join(", ")}`);
|
|
150917
|
+
}
|
|
150918
|
+
return value;
|
|
150919
|
+
}
|
|
150920
|
+
function buildLifecycleUpdates(options3) {
|
|
150921
|
+
if (options3.clearCadence && options3.expectedInterval !== undefined) {
|
|
150922
|
+
error("Use only one of --expected-interval and --clear-cadence");
|
|
150923
|
+
}
|
|
150924
|
+
const updates = {};
|
|
150925
|
+
if (options3.clearCadence)
|
|
150926
|
+
updates.expectedIntervalSeconds = null;
|
|
150927
|
+
const expectedIntervalSeconds = parseExpectedInterval(options3.expectedInterval);
|
|
150928
|
+
if (expectedIntervalSeconds !== undefined)
|
|
150929
|
+
updates.expectedIntervalSeconds = expectedIntervalSeconds;
|
|
150930
|
+
const windowSemantics = parseWindowSemantics(options3.windowSemantics);
|
|
150931
|
+
if (windowSemantics !== undefined)
|
|
150932
|
+
updates.windowSemantics = windowSemantics;
|
|
150933
|
+
const mutationPolicy = parseMutationPolicy(options3.mutationPolicy);
|
|
150934
|
+
if (mutationPolicy !== undefined)
|
|
150935
|
+
updates.mutationPolicy = mutationPolicy;
|
|
150936
|
+
return updates;
|
|
150937
|
+
}
|
|
150612
150938
|
function createWebhooksCommand() {
|
|
150613
150939
|
const webhooks = new Command("webhooks").description("Manage webhook sources");
|
|
150614
150940
|
webhooks.command("list").description("List webhook sources").option("--enabled", "Show only enabled sources").option("--disabled", "Show only disabled sources").action(async (options3) => {
|
|
@@ -150626,6 +150952,8 @@ function createWebhooksCommand() {
|
|
|
150626
150952
|
id: w.id,
|
|
150627
150953
|
name: w.name,
|
|
150628
150954
|
enabled: w.enabled ? "yes" : "no",
|
|
150955
|
+
health: w.livenessStatus ?? "-",
|
|
150956
|
+
cadence: w.expectedIntervalSeconds != null ? `${w.expectedIntervalSeconds}s` : "-",
|
|
150629
150957
|
createdAt: w.createdAt
|
|
150630
150958
|
}));
|
|
150631
150959
|
list(items, { emptyMessage: "No webhook sources found." });
|
|
@@ -150645,7 +150973,7 @@ function createWebhooksCommand() {
|
|
|
150645
150973
|
error(`Failed to get webhook source: ${message2}`);
|
|
150646
150974
|
}
|
|
150647
150975
|
});
|
|
150648
|
-
webhooks.command("create").description("Create a webhook source").requiredOption("--name <name>", "Webhook source name").option("--description <desc>", "Description").option("--disabled", "Create in disabled state").option("--headers <json>", `Expected headers as JSON (e.g., '{"X-Secret": true}')`).option("--signature-algorithm <alg>", "Signature verification: hmac-sha256, hmac-sha1, or token-match").option("--signature-header <name>", "Header carrying the signature/token (e.g., X-Hub-Signature-256)").option("--signature-prefix <prefix>", "Prefix before the hex digest (e.g., 'sha256=')").option("--signature-secret <secret>", "Shared secret for signature verification (write-only). Visible in shell history and process lists \u2014 prefer --signature-secret-env or --signature-secret-stdin").option("--signature-secret-env <VAR>", "Read the shared secret from environment variable VAR").option("--signature-secret-stdin", "Read the shared secret from stdin (trailing newline stripped)").action(async (options3) => {
|
|
150976
|
+
webhooks.command("create").description("Create a webhook source").requiredOption("--name <name>", "Webhook source name").option("--description <desc>", "Description").option("--disabled", "Create in disabled state").option("--headers <json>", `Expected headers as JSON (e.g., '{"X-Secret": true}')`).option("--signature-algorithm <alg>", "Signature verification: hmac-sha256, hmac-sha1, or token-match").option("--signature-header <name>", "Header carrying the signature/token (e.g., X-Hub-Signature-256)").option("--signature-prefix <prefix>", "Prefix before the hex digest (e.g., 'sha256=')").option("--signature-secret <secret>", "Shared secret for signature verification (write-only). Visible in shell history and process lists \u2014 prefer --signature-secret-env or --signature-secret-stdin").option("--signature-secret-env <VAR>", "Read the shared secret from environment variable VAR").option("--signature-secret-stdin", "Read the shared secret from stdin (trailing newline stripped)").option("--expected-interval <seconds>", "Declared cadence: >=1 event or heartbeat per N seconds. Arms liveness supervision (#961)").option("--window-semantics <value>", `Declared window semantics: ${WINDOW_SEMANTICS.join(" or ")}`).option("--mutation-policy <value>", `Declared mutation re-emit policy: ${MUTATION_POLICIES.join(" or ")}`).action(async (options3) => {
|
|
150649
150977
|
const client = getClient();
|
|
150650
150978
|
try {
|
|
150651
150979
|
let expectedHeaders;
|
|
@@ -150665,7 +150993,10 @@ function createWebhooksCommand() {
|
|
|
150665
150993
|
enabled: !options3.disabled,
|
|
150666
150994
|
expectedHeaders,
|
|
150667
150995
|
signatureConfig,
|
|
150668
|
-
signatureSecret
|
|
150996
|
+
signatureSecret,
|
|
150997
|
+
expectedIntervalSeconds: parseExpectedInterval(options3.expectedInterval),
|
|
150998
|
+
windowSemantics: parseWindowSemantics(options3.windowSemantics),
|
|
150999
|
+
mutationPolicy: parseMutationPolicy(options3.mutationPolicy)
|
|
150669
151000
|
});
|
|
150670
151001
|
const details = {
|
|
150671
151002
|
id: source.id,
|
|
@@ -150681,11 +151012,11 @@ function createWebhooksCommand() {
|
|
|
150681
151012
|
error(`Failed to create webhook source: ${message2}`);
|
|
150682
151013
|
}
|
|
150683
151014
|
});
|
|
150684
|
-
webhooks.command("update <id>").description("Update a webhook source").option("--name <name>", "New name").option("--description <desc>", "New description").option("--enable", "Enable the webhook").option("--disable", "Disable the webhook").option("--signature-algorithm <alg>", "Signature verification: hmac-sha256, hmac-sha1, or token-match").option("--signature-header <name>", "Header carrying the signature/token (e.g., X-Hub-Signature-256)").option("--signature-prefix <prefix>", "Prefix before the hex digest (e.g., 'sha256=')").option("--signature-secret <secret>", "Shared secret for signature verification (write-only). Visible in shell history and process lists \u2014 prefer --signature-secret-env or --signature-secret-stdin").option("--signature-secret-env <VAR>", "Read the shared secret from environment variable VAR").option("--signature-secret-stdin", "Read the shared secret from stdin (trailing newline stripped)").option("--clear-signature", "Remove the signature config and stored secret").action(async (id, options3) => {
|
|
151015
|
+
webhooks.command("update <id>").description("Update a webhook source").option("--name <name>", "New name").option("--description <desc>", "New description").option("--enable", "Enable the webhook").option("--disable", "Disable the webhook").option("--signature-algorithm <alg>", "Signature verification: hmac-sha256, hmac-sha1, or token-match").option("--signature-header <name>", "Header carrying the signature/token (e.g., X-Hub-Signature-256)").option("--signature-prefix <prefix>", "Prefix before the hex digest (e.g., 'sha256=')").option("--signature-secret <secret>", "Shared secret for signature verification (write-only). Visible in shell history and process lists \u2014 prefer --signature-secret-env or --signature-secret-stdin").option("--signature-secret-env <VAR>", "Read the shared secret from environment variable VAR").option("--signature-secret-stdin", "Read the shared secret from stdin (trailing newline stripped)").option("--clear-signature", "Remove the signature config and stored secret").option("--expected-interval <seconds>", "Declared cadence: >=1 event or heartbeat per N seconds. (Re)arms liveness supervision (#961)").option("--clear-cadence", "Remove the declared cadence (disarms liveness supervision)").option("--window-semantics <value>", `Declared window semantics: ${WINDOW_SEMANTICS.join(" or ")}`).option("--mutation-policy <value>", `Declared mutation re-emit policy: ${MUTATION_POLICIES.join(" or ")}`).action(async (id, options3) => {
|
|
150685
151016
|
const resolvedId = await resolveWebhookId(id);
|
|
150686
151017
|
const client = getClient();
|
|
150687
151018
|
try {
|
|
150688
|
-
const updates =
|
|
151019
|
+
const updates = buildLifecycleUpdates(options3);
|
|
150689
151020
|
if (options3.name)
|
|
150690
151021
|
updates.name = options3.name;
|
|
150691
151022
|
if (options3.description)
|
|
@@ -150751,6 +151082,20 @@ function createWebhooksCommand() {
|
|
|
150751
151082
|
error(`Failed to trigger event: ${message2}`);
|
|
150752
151083
|
}
|
|
150753
151084
|
});
|
|
151085
|
+
webhooks.command("heartbeat <source>").description('Record a connector heartbeat ("ran, zero events found") \u2014 resets the liveness window (#961)').action(async (source) => {
|
|
151086
|
+
const client = getClient();
|
|
151087
|
+
try {
|
|
151088
|
+
const result = await client.webhooks.heartbeat(source);
|
|
151089
|
+
success(`Heartbeat recorded for '${result.source}'`, {
|
|
151090
|
+
heartbeatAt: result.heartbeatAt,
|
|
151091
|
+
livenessStatus: result.livenessStatus ?? "unsupervised",
|
|
151092
|
+
expectedIntervalSeconds: result.expectedIntervalSeconds
|
|
151093
|
+
});
|
|
151094
|
+
} catch (err2) {
|
|
151095
|
+
const message2 = err2 instanceof Error ? err2.message : "Unknown error";
|
|
151096
|
+
error(`Failed to record heartbeat: ${message2}`);
|
|
151097
|
+
}
|
|
151098
|
+
});
|
|
150754
151099
|
return webhooks;
|
|
150755
151100
|
}
|
|
150756
151101
|
|