@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.
@@ -207,6 +207,19 @@ var init_types2 = __esm(() => {
207
207
  "flow.data_exchange"
208
208
  ];
209
209
  });
210
+ // ../core/src/events/causality.ts
211
+ import { AsyncLocalStorage } from "async_hooks";
212
+ function runWithEventCausality(context2, fn) {
213
+ return storage.run(context2, fn);
214
+ }
215
+ function currentEventCausality() {
216
+ return storage.getStore();
217
+ }
218
+ var storage;
219
+ var init_causality = __esm(() => {
220
+ storage = new AsyncLocalStorage;
221
+ });
222
+
210
223
  // ../core/src/events/envelope.ts
211
224
  function classifyEnvelope(metadata) {
212
225
  if (metadata === null || metadata === undefined)
@@ -18232,6 +18245,38 @@ var init_logger = __esm(() => {
18232
18245
  rootLogger = createLogger("system");
18233
18246
  });
18234
18247
 
18248
+ // ../core/src/events/factory.ts
18249
+ function createOmniEvent(type, payload, metadata, serviceName) {
18250
+ const eventId = crypto.randomUUID();
18251
+ const timestamp = Date.now();
18252
+ const tenantId = resolvePublishTenantId(metadata?.tenantId, metadata?.instanceId);
18253
+ const ambient = currentEventCausality();
18254
+ const causationId = metadata?.causationId ?? ambient?.causationId;
18255
+ return {
18256
+ id: eventId,
18257
+ type,
18258
+ payload,
18259
+ timestamp,
18260
+ metadata: {
18261
+ correlationId: metadata?.correlationId ?? ambient?.correlationId ?? eventId,
18262
+ ...causationId ? { causationId } : {},
18263
+ instanceId: metadata?.instanceId,
18264
+ channelType: metadata?.channelType,
18265
+ personId: metadata?.personId,
18266
+ platformIdentityId: metadata?.platformIdentityId,
18267
+ traceId: metadata?.traceId ?? eventId,
18268
+ source: metadata?.source ?? serviceName,
18269
+ ingestMode: metadata?.ingestMode,
18270
+ timings: metadata?.timings,
18271
+ ...tenantId ? { envelopeVersion: CURRENT_ENVELOPE_VERSION, tenantId } : {}
18272
+ }
18273
+ };
18274
+ }
18275
+ var init_factory = __esm(() => {
18276
+ init_causality();
18277
+ init_envelope();
18278
+ });
18279
+
18235
18280
  // ../core/src/events/nats/streams.ts
18236
18281
  function getStreamForEventType(eventType) {
18237
18282
  const prefix = eventType.split(".")[0] ?? "";
@@ -22567,7 +22612,24 @@ var init_registry = __esm(() => {
22567
22612
  component: exports_external.string(),
22568
22613
  reason: exports_external.string(),
22569
22614
  severity: exports_external.enum(["warning", "critical"])
22570
- }), { description: "System health degradation detected" })
22615
+ }), { description: "System health degradation detected" }),
22616
+ connectorStalled: createEventSchema("system.connector.stalled", exports_external.object({
22617
+ sourceId: exports_external.string(),
22618
+ sourceName: exports_external.string(),
22619
+ expectedIntervalSeconds: exports_external.number(),
22620
+ lastReceivedAt: exports_external.number().nullable(),
22621
+ lastHeartbeatAt: exports_external.number().nullable(),
22622
+ silentForSeconds: exports_external.number(),
22623
+ stalledAt: exports_external.number()
22624
+ }), { description: "A supervised connector went silent beyond its declared cadence" }),
22625
+ connectorRecovered: createEventSchema("system.connector.recovered", exports_external.object({
22626
+ sourceId: exports_external.string(),
22627
+ sourceName: exports_external.string(),
22628
+ expectedIntervalSeconds: exports_external.number(),
22629
+ stalledForSeconds: exports_external.number(),
22630
+ recoveredBy: exports_external.enum(["event", "heartbeat", "rearmed"]),
22631
+ recoveredAt: exports_external.number()
22632
+ }), { description: "A stalled connector signalled again (event, heartbeat, or re-declared cadence)" })
22571
22633
  };
22572
22634
  CustomEventSchemas = {
22573
22635
  chatUnreadUpdated: createEventSchema("custom.chat.unread-updated", exports_external.object({
@@ -22987,27 +23049,8 @@ class NatsEventBus {
22987
23049
  }
22988
23050
  async publishInternal(type, payload, metadata) {
22989
23051
  await this.ensureConnected();
22990
- const eventId = crypto.randomUUID();
22991
- const timestamp = Date.now();
22992
- const tenantId = resolvePublishTenantId(metadata?.tenantId, metadata?.instanceId);
22993
- const event = {
22994
- id: eventId,
22995
- type,
22996
- payload,
22997
- timestamp,
22998
- metadata: {
22999
- correlationId: metadata?.correlationId ?? eventId,
23000
- instanceId: metadata?.instanceId,
23001
- channelType: metadata?.channelType,
23002
- personId: metadata?.personId,
23003
- platformIdentityId: metadata?.platformIdentityId,
23004
- traceId: metadata?.traceId ?? eventId,
23005
- source: metadata?.source ?? this.config.serviceName,
23006
- ingestMode: metadata?.ingestMode,
23007
- timings: metadata?.timings,
23008
- ...tenantId ? { envelopeVersion: CURRENT_ENVELOPE_VERSION, tenantId } : {}
23009
- }
23010
- };
23052
+ const event = createOmniEvent(type, payload, metadata, this.config.serviceName);
23053
+ const eventId = event.id;
23011
23054
  let subject;
23012
23055
  if (metadata?.channelType && metadata?.instanceId) {
23013
23056
  subject = buildSubject(type, metadata.channelType, metadata.instanceId);
@@ -23283,7 +23326,7 @@ async function connectEventBus(config2) {
23283
23326
  var import_api2, import_nats, log4, DEFAULTS, ENSURE_CONNECTED_WAIT_MS = 5000;
23284
23327
  var init_client = __esm(() => {
23285
23328
  init_logger();
23286
- init_envelope();
23329
+ init_factory();
23287
23330
  init_consumer();
23288
23331
  init_registry();
23289
23332
  init_streams();
@@ -31276,6 +31319,7 @@ function estimateCompletion(progress) {
31276
31319
  // ../core/src/events/index.ts
31277
31320
  var init_events = __esm(() => {
31278
31321
  init_types2();
31322
+ init_causality();
31279
31323
  init_envelope();
31280
31324
  init_nats();
31281
31325
  init_dead_letter();
@@ -36955,13 +36999,7 @@ function resolveFollowUpValue(trimmed, followUp) {
36955
36999
  return;
36956
37000
  }
36957
37001
  }
36958
- function resolveTemplatePath(path, context2) {
36959
- const trimmed = path.trim();
36960
- if (!trimmed)
36961
- return;
36962
- const parts = trimmed.split(".");
36963
- const root = parts[0] ?? "";
36964
- const rest = parts.slice(1).join(".");
37002
+ function resolveSpecialValue(trimmed, root, rest, context2) {
36965
37003
  if (context2.debounce) {
36966
37004
  const debounceValue = resolveDebounceValue(trimmed, rest, context2.debounce);
36967
37005
  if (debounceValue !== undefined)
@@ -36972,6 +37010,21 @@ function resolveTemplatePath(path, context2) {
36972
37010
  if (followUpValue !== undefined)
36973
37011
  return followUpValue;
36974
37012
  }
37013
+ if (root === "event" && context2.event) {
37014
+ return rest ? getNestedValue(context2.event, rest) : context2.event;
37015
+ }
37016
+ return;
37017
+ }
37018
+ function resolveTemplatePath(path, context2) {
37019
+ const trimmed = path.trim();
37020
+ if (!trimmed)
37021
+ return;
37022
+ const parts = trimmed.split(".");
37023
+ const root = parts[0] ?? "";
37024
+ const rest = parts.slice(1).join(".");
37025
+ const specialValue = resolveSpecialValue(trimmed, root, rest, context2);
37026
+ if (specialValue !== undefined)
37027
+ return specialValue;
36975
37028
  if (root === "payload")
36976
37029
  return rest ? getNestedValue(context2.payload, rest) : context2.payload;
36977
37030
  if (root === "env")
@@ -37053,7 +37106,9 @@ function createTemplateContext(payload, options = {}) {
37053
37106
  variables: options.variables ?? {},
37054
37107
  env: process.env,
37055
37108
  debounce: options.debounce,
37056
- followUp
37109
+ followUp,
37110
+ event: options.event,
37111
+ automation: options.automation
37057
37112
  };
37058
37113
  }
37059
37114
  var TEMPLATE_REGEX;
@@ -37625,8 +37680,12 @@ var init_egress = __esm(() => {
37625
37680
  });
37626
37681
 
37627
37682
  // ../core/src/automations/actions.ts
37628
- function buildWebhookHeaders(config2, context2) {
37683
+ function buildWebhookHeaders(config2, context2, actionIndex) {
37629
37684
  const headers = { "Content-Type": "application/json" };
37685
+ if (context2.event) {
37686
+ headers["X-Omni-Event-Id"] = context2.event.id;
37687
+ headers["X-Omni-Delivery-Id"] = `${context2.event.id}:${context2.automation?.id ?? "manual"}:${actionIndex}`;
37688
+ }
37630
37689
  if (config2.headers) {
37631
37690
  for (const [key, value] of Object.entries(config2.headers)) {
37632
37691
  headers[key] = substituteTemplate(value, context2);
@@ -37634,16 +37693,28 @@ function buildWebhookHeaders(config2, context2) {
37634
37693
  }
37635
37694
  return headers;
37636
37695
  }
37696
+ function buildDefaultWebhookBody(config2, context2) {
37697
+ if (context2.event && config2.includeEnvelope !== false) {
37698
+ return JSON.stringify({
37699
+ id: context2.event.id,
37700
+ type: context2.event.type,
37701
+ payload: context2.payload,
37702
+ metadata: context2.event.metadata,
37703
+ timestamp: context2.event.timestamp
37704
+ });
37705
+ }
37706
+ return JSON.stringify(context2.payload);
37707
+ }
37637
37708
  async function parseWebhookResponse(response) {
37638
37709
  const contentType = response.headers.get("content-type") ?? "";
37639
37710
  return contentType.includes("application/json") ? response.json() : response.text();
37640
37711
  }
37641
- async function executeWebhookAction(config2, context2, _deps, trustedTenantId) {
37712
+ async function executeWebhookAction(config2, context2, _deps, trustedTenantId, actionIndex = 0) {
37642
37713
  try {
37643
37714
  const url = substituteTemplate(config2.url, context2);
37644
37715
  const method = config2.method ?? "POST";
37645
- const headers = buildWebhookHeaders(config2, context2);
37646
- const body = config2.bodyTemplate ? substituteTemplate(config2.bodyTemplate, context2) : JSON.stringify(context2.payload);
37716
+ const headers = buildWebhookHeaders(config2, context2, actionIndex);
37717
+ const body = config2.bodyTemplate ? substituteTemplate(config2.bodyTemplate, context2) : buildDefaultWebhookBody(config2, context2);
37647
37718
  logger2.debug(`Webhook ${method} ${url}`, { method, url, waitForResponse: config2.waitForResponse });
37648
37719
  const response = await brokeredFetch(url, {
37649
37720
  method,
@@ -37733,8 +37804,10 @@ async function executeEmitEventAction(config2, context2, deps, trustedTenantId)
37733
37804
  }
37734
37805
  }
37735
37806
  logger2.debug("Emitting event", { eventType });
37807
+ const correlationId = context2.event?.metadata.correlationId ?? context2.payload.correlationId ?? undefined;
37736
37808
  const result = await deps.eventBus.publishGeneric(eventType, payload, {
37737
- correlationId: context2.payload.correlationId ?? undefined,
37809
+ correlationId,
37810
+ causationId: context2.event?.id,
37738
37811
  source: "automation",
37739
37812
  ...trustedTenantId ? { tenantId: trustedTenantId } : {}
37740
37813
  });
@@ -37827,7 +37900,12 @@ function extractAgentCallContext(config2, context2) {
37827
37900
  threadId,
37828
37901
  senderId,
37829
37902
  senderName,
37830
- messages: messagesResult
37903
+ messages: messagesResult,
37904
+ event: context2.event ? {
37905
+ id: context2.event.id,
37906
+ type: context2.event.type,
37907
+ correlationId: context2.event.metadata.correlationId
37908
+ } : undefined
37831
37909
  }
37832
37910
  };
37833
37911
  }
@@ -37868,12 +37946,12 @@ async function executeCallAgentAction(config2, context2, deps, trustedTenantId)
37868
37946
  return { success: false, error: errorMessage };
37869
37947
  }
37870
37948
  }
37871
- async function executeAction(action, context2, deps, trustedTenantId) {
37949
+ async function executeAction(action, context2, deps, trustedTenantId, actionIndex = 0) {
37872
37950
  const start = Date.now();
37873
37951
  let result;
37874
37952
  switch (action.type) {
37875
37953
  case "webhook":
37876
- result = await executeWebhookAction(action.config, context2, deps, trustedTenantId);
37954
+ result = await executeWebhookAction(action.config, context2, deps, trustedTenantId, actionIndex);
37877
37955
  break;
37878
37956
  case "send_message":
37879
37957
  result = await executeSendMessageAction(action.config, context2, deps, trustedTenantId);
@@ -37902,12 +37980,12 @@ async function executeAction(action, context2, deps, trustedTenantId) {
37902
37980
  async function executeActions(actions, context2, deps, trustedTenantId) {
37903
37981
  const results = [];
37904
37982
  const variables = { ...context2.variables };
37905
- for (const action of actions) {
37983
+ for (const [actionIndex, action] of actions.entries()) {
37906
37984
  const actionContext = {
37907
37985
  ...context2,
37908
37986
  variables
37909
37987
  };
37910
- const result = await executeAction(action, actionContext, deps, trustedTenantId);
37988
+ const result = await executeAction(action, actionContext, deps, trustedTenantId, actionIndex);
37911
37989
  results.push(result);
37912
37990
  if (action.type === "webhook" && action.config.responseAs && result.status === "success" && result.result) {
37913
37991
  variables[action.config.responseAs] = result.result;
@@ -38337,13 +38415,18 @@ class AutomationEngine {
38337
38415
  type: content?.type ?? "unknown",
38338
38416
  text: content?.text,
38339
38417
  timestamp: event.timestamp,
38340
- payload
38418
+ payload,
38419
+ eventId: event.id,
38420
+ correlationId: event.metadata.correlationId
38341
38421
  };
38342
38422
  manager.addMessage(key, message2, from, instanceId, stamp);
38343
38423
  }
38344
38424
  async handleImmediate(automation, event) {
38345
38425
  const instanceId = event.metadata.instanceId ?? "global";
38346
- const context2 = createTemplateContext(event.payload);
38426
+ const context2 = createTemplateContext(event.payload, {
38427
+ event: { id: event.id, type: event.type, timestamp: event.timestamp, metadata: event.metadata },
38428
+ automation: { id: automation.id }
38429
+ });
38347
38430
  await this.queueExecution(automation, event, context2, instanceId);
38348
38431
  }
38349
38432
  setupDebounceManager(automation) {
@@ -38353,28 +38436,35 @@ class AutomationEngine {
38353
38436
  logger4.warn("Debounce callback fired with empty messages array", { key });
38354
38437
  return;
38355
38438
  }
38356
- const context2 = createTemplateContext(lastMessage.payload, {
38357
- debounce: {
38358
- messages: messages.map((m2) => ({
38359
- type: m2.type,
38360
- text: m2.text,
38361
- timestamp: m2.timestamp
38362
- })),
38363
- from,
38364
- instanceId
38365
- }
38366
- });
38367
38439
  const syntheticEvent = {
38368
38440
  id: generateId(),
38369
38441
  type: automation.triggerEventType,
38370
38442
  payload: lastMessage.payload,
38371
38443
  metadata: {
38372
- correlationId: generateId(),
38444
+ correlationId: lastMessage.correlationId ?? generateId(),
38373
38445
  instanceId,
38374
38446
  ...stamp ? { envelopeVersion: stamp.envelopeVersion, tenantId: stamp.tenantId } : {}
38375
38447
  },
38376
38448
  timestamp: Date.now()
38377
38449
  };
38450
+ const context2 = createTemplateContext(lastMessage.payload, {
38451
+ debounce: {
38452
+ messages: messages.map((m2) => ({
38453
+ type: m2.type,
38454
+ text: m2.text,
38455
+ timestamp: m2.timestamp
38456
+ })),
38457
+ from,
38458
+ instanceId
38459
+ },
38460
+ event: {
38461
+ id: lastMessage.eventId ?? syntheticEvent.id,
38462
+ type: syntheticEvent.type,
38463
+ timestamp: syntheticEvent.timestamp,
38464
+ metadata: syntheticEvent.metadata
38465
+ },
38466
+ automation: { id: automation.id }
38467
+ });
38378
38468
  await this.queueExecution(automation, syntheticEvent, context2, instanceId);
38379
38469
  };
38380
38470
  const manager = new DebounceManager(automation.debounce, callback);
@@ -38462,7 +38552,10 @@ class AutomationEngine {
38462
38552
  await this.logExecution(result2, trustedTenantId);
38463
38553
  return result2;
38464
38554
  }
38465
- const actionsExecuted = await executeActions(automation.actions, context2, this.deps, trustedTenantId);
38555
+ const actionsExecuted = await runWithEventCausality({
38556
+ correlationId: context2.event?.metadata.correlationId ?? event.metadata.correlationId,
38557
+ causationId: context2.event?.id ?? event.id
38558
+ }, () => executeActions(automation.actions, context2, this.deps, trustedTenantId));
38466
38559
  const allSucceeded = actionsExecuted.every((a) => a.status === "success");
38467
38560
  const status = allSucceeded ? "success" : "failed";
38468
38561
  const result = {
@@ -38558,6 +38651,7 @@ function createAutomationEngine(config2) {
38558
38651
  }
38559
38652
  var logger4, QueueFullError;
38560
38653
  var init_engine = __esm(() => {
38654
+ init_causality();
38561
38655
  init_envelope();
38562
38656
  init_ids();
38563
38657
  init_logger();
@@ -38946,6 +39040,113 @@ var init_automations = __esm(() => {
38946
39040
  init_sweeper();
38947
39041
  });
38948
39042
 
39043
+ // ../core/src/connectors/liveness.ts
39044
+ function latestConnectorSignal(row) {
39045
+ let best = { at: row.createdAt, kind: "rearmed" };
39046
+ const candidates = [
39047
+ { at: row.livenessArmedAt, kind: "rearmed" },
39048
+ { at: row.lastReceivedAt, kind: "event" },
39049
+ { at: row.lastHeartbeatAt, kind: "heartbeat" }
39050
+ ];
39051
+ for (const candidate of candidates) {
39052
+ if (candidate.at && candidate.at.getTime() >= best.at.getTime()) {
39053
+ best = { at: candidate.at, kind: candidate.kind };
39054
+ }
39055
+ }
39056
+ return best;
39057
+ }
39058
+ async function sweepConnectorLiveness(deps) {
39059
+ const clock = deps.now ?? (() => new Date);
39060
+ const now = clock();
39061
+ const rows = await deps.repo.findSupervised();
39062
+ const stats = { scanned: rows.length, stalled: 0, recovered: 0, errors: 0 };
39063
+ for (const row of rows) {
39064
+ try {
39065
+ await processRow2(row, now, deps, stats);
39066
+ } catch (err2) {
39067
+ stats.errors += 1;
39068
+ deps.logger.error("connector liveness: failed to process source", {
39069
+ sourceId: row.id,
39070
+ sourceName: row.name,
39071
+ error: err2 instanceof Error ? err2.message : String(err2)
39072
+ });
39073
+ }
39074
+ }
39075
+ if (stats.stalled > 0 || stats.recovered > 0) {
39076
+ deps.logger.info("connector liveness sweep tick", { ...stats });
39077
+ }
39078
+ return stats;
39079
+ }
39080
+ async function processRow2(row, now, deps, stats) {
39081
+ const signal = latestConnectorSignal(row);
39082
+ const silentMs = Math.max(0, now.getTime() - signal.at.getTime());
39083
+ const overdue = silentMs > row.expectedIntervalSeconds * 1000;
39084
+ const silentForSeconds = Math.round(silentMs / 1000);
39085
+ if (overdue) {
39086
+ if (row.livenessStatus === "stalled")
39087
+ return;
39088
+ if (!await deps.repo.markStalled(row.id, now))
39089
+ return;
39090
+ const payload = {
39091
+ sourceId: row.id,
39092
+ sourceName: row.name,
39093
+ expectedIntervalSeconds: row.expectedIntervalSeconds,
39094
+ lastReceivedAt: row.lastReceivedAt?.getTime() ?? null,
39095
+ lastHeartbeatAt: row.lastHeartbeatAt?.getTime() ?? null,
39096
+ silentForSeconds,
39097
+ stalledAt: now.getTime()
39098
+ };
39099
+ const eventId = await publishTransition(deps, "system.connector.stalled", { ...payload }, row);
39100
+ stats.stalled += 1;
39101
+ await runHook(deps.logger, "onStalled", row, () => deps.onStalled?.(row, payload, eventId));
39102
+ return;
39103
+ }
39104
+ if (row.livenessStatus === "stalled") {
39105
+ if (!await deps.repo.markRecovered(row.id, now))
39106
+ return;
39107
+ const stalledSince = row.stalledAt ?? signal.at;
39108
+ const payload = {
39109
+ sourceId: row.id,
39110
+ sourceName: row.name,
39111
+ expectedIntervalSeconds: row.expectedIntervalSeconds,
39112
+ stalledForSeconds: Math.max(0, Math.round((now.getTime() - stalledSince.getTime()) / 1000)),
39113
+ recoveredBy: signal.kind,
39114
+ recoveredAt: now.getTime()
39115
+ };
39116
+ await publishTransition(deps, "system.connector.recovered", { ...payload }, row);
39117
+ stats.recovered += 1;
39118
+ await runHook(deps.logger, "onRecovered", row, () => deps.onRecovered?.(row, payload));
39119
+ }
39120
+ }
39121
+ async function publishTransition(deps, type, payload, row) {
39122
+ if (!deps.eventBus) {
39123
+ deps.logger.warn("connector liveness: no event bus, transition persisted without event", {
39124
+ type,
39125
+ sourceName: row.name
39126
+ });
39127
+ return null;
39128
+ }
39129
+ const result = await deps.eventBus.publishGeneric(type, payload, {
39130
+ source: "connector-liveness",
39131
+ ...row.tenantId ? { tenantId: row.tenantId } : {}
39132
+ });
39133
+ return result.id;
39134
+ }
39135
+ async function runHook(logger5, name, row, hook) {
39136
+ try {
39137
+ await hook();
39138
+ } catch (err2) {
39139
+ logger5.error(`connector liveness: ${name} hook failed`, {
39140
+ sourceId: row.id,
39141
+ sourceName: row.name,
39142
+ error: err2 instanceof Error ? err2.message : String(err2)
39143
+ });
39144
+ }
39145
+ }
39146
+
39147
+ // ../core/src/connectors/index.ts
39148
+ var init_connectors = () => {};
39149
+
38949
39150
  // ../core/src/sessions/reset.ts
38950
39151
  class InMemorySessionActivityStore {
38951
39152
  activities = new Map;
@@ -42989,7 +43190,7 @@ function isProviderSchemaSupported(schema) {
42989
43190
  function getSupportedProviderSchemas() {
42990
43191
  return ["agno", "webhook", "openclaw", "claude-code", "ag-ui", "a2a", "nats-genie"];
42991
43192
  }
42992
- var init_factory = __esm(() => {
43193
+ var init_factory2 = __esm(() => {
42993
43194
  init_a2a_client();
42994
43195
  init_ag_ui_client();
42995
43196
  init_agno_client();
@@ -43009,7 +43210,7 @@ var init_providers = __esm(() => {
43009
43210
  init_ag_ui_provider();
43010
43211
  init_a2a_provider();
43011
43212
  init_nats_genie_provider();
43012
- init_factory();
43213
+ init_factory2();
43013
43214
  });
43014
43215
 
43015
43216
  // ../core/src/cache/types.ts
@@ -43678,6 +43879,7 @@ __export(exports_src, {
43678
43879
  tenantLabelBucketCount: () => tenantLabelBucketCount,
43679
43880
  tenantEventsProcessed: () => tenantEventsProcessed,
43680
43881
  sweepFollowUps: () => sweepFollowUps,
43882
+ sweepConnectorLiveness: () => sweepConnectorLiveness,
43681
43883
  substituteTemplateObject: () => substituteTemplateObject,
43682
43884
  substituteTemplate: () => substituteTemplate,
43683
43885
  stampsEqual: () => stampsEqual,
@@ -43692,6 +43894,7 @@ __export(exports_src, {
43692
43894
  scheduledJobRuns: () => scheduledJobRuns,
43693
43895
  scheduledJobNextRun: () => scheduledJobNextRun,
43694
43896
  scheduledJobDuration: () => scheduledJobDuration,
43897
+ runWithEventCausality: () => runWithEventCausality,
43695
43898
  rootLogger: () => rootLogger,
43696
43899
  resolveResetConfig: () => resolveResetConfig,
43697
43900
  resolvePublishTenantId: () => resolvePublishTenantId,
@@ -43740,6 +43943,7 @@ __export(exports_src, {
43740
43943
  natsConnectionStatus: () => natsConnectionStatus,
43741
43944
  matchesPattern: () => matchesPattern,
43742
43945
  markdownToWhatsApp: () => markdownToWhatsApp,
43946
+ latestConnectorSignal: () => latestConnectorSignal,
43743
43947
  jsonEquals: () => jsonEquals,
43744
43948
  isValidUuid: () => isValidUuid,
43745
43949
  isValidJsonSchema: () => isValidJsonSchema,
@@ -43803,6 +44007,7 @@ __export(exports_src, {
43803
44007
  dbQueries: () => dbQueries,
43804
44008
  dbPoolSize: () => dbPoolSize,
43805
44009
  dbErrors: () => dbErrors,
44010
+ currentEventCausality: () => currentEventCausality,
43806
44011
  createValidatedSubscription: () => createValidatedSubscription,
43807
44012
  createTemplateContext: () => createTemplateContext,
43808
44013
  createSubscription: () => createSubscription,
@@ -44065,6 +44270,7 @@ var init_src = __esm(() => {
44065
44270
  init_observability();
44066
44271
  init_secrets();
44067
44272
  init_automations();
44273
+ init_connectors();
44068
44274
  init_reset();
44069
44275
  init_providers();
44070
44276
  init_cache();
@@ -138899,9 +139105,9 @@ var require_session = __commonJS((exports) => {
138899
139105
  return options.type === "multi" ? strictMultiSession(options) : strictSingleSession(options);
138900
139106
  }
138901
139107
  function strictSingleSession(options) {
138902
- const { initial, storage, getSessionKey, custom: custom2 } = fillDefaults(options);
139108
+ const { initial, storage: storage2, getSessionKey, custom: custom2 } = fillDefaults(options);
138903
139109
  return async (ctx, next) => {
138904
- const propSession = new PropertySession(storage, ctx, "session", initial);
139110
+ const propSession = new PropertySession(storage2, ctx, "session", initial);
138905
139111
  const key = await getSessionKey(ctx);
138906
139112
  await propSession.init(key, { custom: custom2, lazy: false });
138907
139113
  await next();
@@ -138914,8 +139120,8 @@ var require_session = __commonJS((exports) => {
138914
139120
  return async (ctx, next) => {
138915
139121
  ctx.session = {};
138916
139122
  const propSessions = await Promise.all(props.map(async (prop) => {
138917
- const { initial, storage, getSessionKey, custom: custom2 } = defaults[prop];
138918
- const s = new PropertySession(storage, ctx.session, prop, initial);
139123
+ const { initial, storage: storage2, getSessionKey, custom: custom2 } = defaults[prop];
139124
+ const s = new PropertySession(storage2, ctx.session, prop, initial);
138919
139125
  const key = await getSessionKey(ctx);
138920
139126
  await s.init(key, { custom: custom2, lazy: false });
138921
139127
  return s;
@@ -138930,9 +139136,9 @@ var require_session = __commonJS((exports) => {
138930
139136
  if (options.type !== undefined && options.type !== "single") {
138931
139137
  throw new Error("Cannot use lazy multi sessions!");
138932
139138
  }
138933
- const { initial, storage, getSessionKey, custom: custom2 } = fillDefaults(options);
139139
+ const { initial, storage: storage2, getSessionKey, custom: custom2 } = fillDefaults(options);
138934
139140
  return async (ctx, next) => {
138935
- const propSession = new PropertySession(storage, ctx, "session", initial);
139141
+ const propSession = new PropertySession(storage2, ctx, "session", initial);
138936
139142
  const key = await getSessionKey(ctx);
138937
139143
  await propSession.init(key, { custom: custom2, lazy: true });
138938
139144
  await next();
@@ -138941,8 +139147,8 @@ var require_session = __commonJS((exports) => {
138941
139147
  }
138942
139148
 
138943
139149
  class PropertySession {
138944
- constructor(storage, obj, prop, initial) {
138945
- this.storage = storage;
139150
+ constructor(storage2, obj, prop, initial) {
139151
+ this.storage = storage2;
138946
139152
  this.obj = obj;
138947
139153
  this.prop = prop;
138948
139154
  this.initial = initial;
@@ -139025,15 +139231,15 @@ var require_session = __commonJS((exports) => {
139025
139231
  }
139026
139232
  }
139027
139233
  function fillDefaults(opts = {}) {
139028
- let { prefix = "", getSessionKey = defaultGetSessionKey, initial, storage } = opts;
139029
- if (storage == null) {
139234
+ let { prefix = "", getSessionKey = defaultGetSessionKey, initial, storage: storage2 } = opts;
139235
+ if (storage2 == null) {
139030
139236
  debug2("Storing session data in memory, all data will be lost when the bot restarts.");
139031
- storage = new MemorySessionStorage;
139237
+ storage2 = new MemorySessionStorage;
139032
139238
  }
139033
139239
  const custom2 = getSessionKey !== defaultGetSessionKey;
139034
139240
  return {
139035
139241
  initial,
139036
- storage,
139242
+ storage: storage2,
139037
139243
  getSessionKey: async (ctx) => {
139038
139244
  const key = await getSessionKey(ctx);
139039
139245
  return key === undefined ? undefined : prefix + key;
@@ -139054,30 +139260,30 @@ var require_session = __commonJS((exports) => {
139054
139260
  return value === undefined || typeof value === "object" && value !== null && "__d" in value;
139055
139261
  }
139056
139262
  function enhanceStorage(options) {
139057
- let { storage, millisecondsToLive, migrations } = options;
139058
- storage = compatStorage(storage);
139263
+ let { storage: storage2, millisecondsToLive, migrations } = options;
139264
+ storage2 = compatStorage(storage2);
139059
139265
  if (millisecondsToLive !== undefined) {
139060
- storage = timeoutStorage(storage, millisecondsToLive);
139266
+ storage2 = timeoutStorage(storage2, millisecondsToLive);
139061
139267
  }
139062
139268
  if (migrations !== undefined) {
139063
- storage = migrationStorage(storage, migrations);
139269
+ storage2 = migrationStorage(storage2, migrations);
139064
139270
  }
139065
- return wrapStorage(storage);
139271
+ return wrapStorage(storage2);
139066
139272
  }
139067
- function compatStorage(storage) {
139273
+ function compatStorage(storage2) {
139068
139274
  return {
139069
139275
  read: async (k2) => {
139070
- const v2 = await storage.read(k2);
139276
+ const v2 = await storage2.read(k2);
139071
139277
  return isEnhance(v2) ? v2 : { __d: v2 };
139072
139278
  },
139073
- write: (k2, v2) => storage.write(k2, v2),
139074
- delete: (k2) => storage.delete(k2)
139279
+ write: (k2, v2) => storage2.write(k2, v2),
139280
+ delete: (k2) => storage2.delete(k2)
139075
139281
  };
139076
139282
  }
139077
- function timeoutStorage(storage, millisecondsToLive) {
139283
+ function timeoutStorage(storage2, millisecondsToLive) {
139078
139284
  const ttlStorage = {
139079
139285
  read: async (k2) => {
139080
- const value = await storage.read(k2);
139286
+ const value = await storage2.read(k2);
139081
139287
  if (value === undefined)
139082
139288
  return;
139083
139289
  if (value.e === undefined) {
@@ -139092,13 +139298,13 @@ var require_session = __commonJS((exports) => {
139092
139298
  },
139093
139299
  write: async (k2, v2) => {
139094
139300
  v2.e = addExpiryDate(v2, millisecondsToLive).expires;
139095
- await storage.write(k2, v2);
139301
+ await storage2.write(k2, v2);
139096
139302
  },
139097
- delete: (k2) => storage.delete(k2)
139303
+ delete: (k2) => storage2.delete(k2)
139098
139304
  };
139099
139305
  return ttlStorage;
139100
139306
  }
139101
- function migrationStorage(storage, migrations) {
139307
+ function migrationStorage(storage2, migrations) {
139102
139308
  const versions = Object.keys(migrations).map((v2) => parseInt(v2)).sort((a, b2) => a - b2);
139103
139309
  const count = versions.length;
139104
139310
  if (count === 0)
@@ -139117,7 +139323,7 @@ var require_session = __commonJS((exports) => {
139117
139323
  return {
139118
139324
  read: async (k2) => {
139119
139325
  var _a;
139120
- const val = await storage.read(k2);
139326
+ const val = await storage2.read(k2);
139121
139327
  if (val === undefined)
139122
139328
  return val;
139123
139329
  let { __d: value, v: current = earliest - 1 } = val;
@@ -139126,15 +139332,15 @@ var require_session = __commonJS((exports) => {
139126
139332
  value = migrations[versions[i]](value);
139127
139333
  return { ...val, v: latest, __d: value };
139128
139334
  },
139129
- write: (k2, v2) => storage.write(k2, { v: latest, ...v2 }),
139130
- delete: (k2) => storage.delete(k2)
139335
+ write: (k2, v2) => storage2.write(k2, { v: latest, ...v2 }),
139336
+ delete: (k2) => storage2.delete(k2)
139131
139337
  };
139132
139338
  }
139133
- function wrapStorage(storage) {
139339
+ function wrapStorage(storage2) {
139134
139340
  return {
139135
- read: (k2) => Promise.resolve(storage.read(k2)).then((v2) => v2 === null || v2 === undefined ? undefined : v2.__d),
139136
- write: (k2, v2) => storage.write(k2, { __d: v2 }),
139137
- delete: (k2) => storage.delete(k2)
139341
+ read: (k2) => Promise.resolve(storage2.read(k2)).then((v2) => v2 === null || v2 === undefined ? undefined : v2.__d),
139342
+ write: (k2, v2) => storage2.write(k2, { __d: v2 }),
139343
+ delete: (k2) => storage2.delete(k2)
139138
139344
  };
139139
139345
  }
139140
139346
 
@@ -143264,9 +143470,9 @@ var require_session_builder = __commonJS((exports, module) => {
143264
143470
  var queueJob = require_queue_job();
143265
143471
 
143266
143472
  class SessionBuilder {
143267
- constructor(storage, protocolAddress) {
143473
+ constructor(storage2, protocolAddress) {
143268
143474
  this.addr = protocolAddress;
143269
- this.storage = storage;
143475
+ this.storage = storage2;
143270
143476
  }
143271
143477
  async initOutgoing(device) {
143272
143478
  const fqAddr = this.addr.toString();
@@ -144712,12 +144918,12 @@ var require_session_cipher = __commonJS((exports, module) => {
144712
144918
  }
144713
144919
 
144714
144920
  class SessionCipher {
144715
- constructor(storage, protocolAddress) {
144921
+ constructor(storage2, protocolAddress) {
144716
144922
  if (!(protocolAddress instanceof ProtocolAddress)) {
144717
144923
  throw new TypeError("protocolAddress must be a ProtocolAddress");
144718
144924
  }
144719
144925
  this.addr = protocolAddress;
144720
- this.storage = storage;
144926
+ this.storage = storage2;
144721
144927
  }
144722
144928
  _encodeTupleByte(number1, number2) {
144723
144929
  if (number1 > 15 || number2 > 15) {
@@ -172164,6 +172370,9 @@ __export(exports_schema, {
172164
172370
  conversations: () => conversations,
172165
172371
  contentTypes: () => contentTypes,
172166
172372
  consumerOffsets: () => consumerOffsets,
172373
+ connectorWindowSemanticsValues: () => connectorWindowSemanticsValues,
172374
+ connectorMutationPolicies: () => connectorMutationPolicies,
172375
+ connectorLivenessStatuses: () => connectorLivenessStatuses,
172167
172376
  conditionOperators: () => conditionOperators,
172168
172377
  closeContactOutcomes: () => closeContactOutcomes,
172169
172378
  closeContactLogs: () => closeContactLogs,
@@ -172212,7 +172421,7 @@ __export(exports_schema, {
172212
172421
  accessRules: () => accessRules,
172213
172422
  accessModes: () => accessModes
172214
172423
  });
172215
- 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;
172424
+ 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;
172216
172425
  var init_schema2 = __esm(() => {
172217
172426
  init_events();
172218
172427
  init_types5();
@@ -172944,9 +173153,11 @@ var init_schema2 = __esm(() => {
172944
173153
  agentRequest: jsonb("agent_request").$type(),
172945
173154
  agentResponse: jsonb("agent_response").$type(),
172946
173155
  metadata: jsonb("metadata").$type(),
173156
+ causationId: uuid("causation_id"),
172947
173157
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
172948
173158
  tenantId: uuid("tenant_id").references(() => tenants.id, { onDelete: "restrict" })
172949
173159
  }, (table3) => ({
173160
+ causationIdx: index("omni_events_causation_idx").on(table3.causationId),
172950
173161
  tenantIdx: index("omni_events_tenant_idx").on(table3.tenantId),
172951
173162
  tenantIdUq: uniqueIndex("omni_events_tenant_id_uq").on(table3.tenantId, table3.id),
172952
173163
  externalIdIdx: index("omni_events_external_id_idx").on(table3.externalId),
@@ -173425,6 +173636,9 @@ var init_schema2 = __esm(() => {
173425
173636
  eventStageIdx: index("event_payloads_event_stage_idx").on(table3.eventId, table3.stage)
173426
173637
  }));
173427
173638
  webhookSignatureAlgorithms = ["hmac-sha256", "hmac-sha1", "token-match"];
173639
+ connectorLivenessStatuses = ["healthy", "stalled"];
173640
+ connectorWindowSemanticsValues = ["future_only", "includes_in_progress"];
173641
+ connectorMutationPolicies = ["same_id", "new_id"];
173428
173642
  webhookSources = pgTable("webhook_sources", {
173429
173643
  id: uuid("id").primaryKey().defaultRandom(),
173430
173644
  name: varchar("name", { length: 100 }).notNull().unique(),
@@ -173436,6 +173650,14 @@ var init_schema2 = __esm(() => {
173436
173650
  enabled: boolean2("enabled").notNull().default(true),
173437
173651
  lastReceivedAt: timestamp("last_received_at", { withTimezone: true }),
173438
173652
  totalReceived: integer("total_received").notNull().default(0),
173653
+ expectedIntervalSeconds: integer("expected_interval_seconds"),
173654
+ lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }),
173655
+ heartbeatCount: integer("heartbeat_count").notNull().default(0),
173656
+ livenessStatus: varchar("liveness_status", { length: 20 }).$type(),
173657
+ livenessArmedAt: timestamp("liveness_armed_at", { withTimezone: true }),
173658
+ stalledAt: timestamp("stalled_at", { withTimezone: true }),
173659
+ windowSemantics: varchar("window_semantics", { length: 40 }).$type(),
173660
+ mutationPolicy: varchar("mutation_policy", { length: 20 }).$type(),
173439
173661
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
173440
173662
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
173441
173663
  tenantId: uuid("tenant_id").references(() => tenants.id, { onDelete: "restrict" })
@@ -173443,7 +173665,8 @@ var init_schema2 = __esm(() => {
173443
173665
  tenantIdx: index("webhook_sources_tenant_idx").on(table3.tenantId),
173444
173666
  tenantNameUq: uniqueIndex("webhook_sources_tenant_name_uq").on(table3.tenantId, table3.name).where(sql`${table3.tenantId} IS NOT NULL`),
173445
173667
  nameIdx: uniqueIndex("webhook_sources_name_idx").on(table3.name),
173446
- enabledIdx: index("webhook_sources_enabled_idx").on(table3.enabled)
173668
+ enabledIdx: index("webhook_sources_enabled_idx").on(table3.enabled),
173669
+ supervisedIdx: index("webhook_sources_supervised_idx").on(table3.enabled).where(sql`${table3.expectedIntervalSeconds} IS NOT NULL`)
173447
173670
  }));
173448
173671
  eventSchemas = pgTable("event_schemas", {
173449
173672
  id: uuid("id").primaryKey().defaultRandom(),
@@ -177895,6 +178118,9 @@ __export(exports_src3, {
177895
178118
  conversations: () => conversations,
177896
178119
  contentTypes: () => contentTypes,
177897
178120
  consumerOffsets: () => consumerOffsets,
178121
+ connectorWindowSemanticsValues: () => connectorWindowSemanticsValues,
178122
+ connectorMutationPolicies: () => connectorMutationPolicies,
178123
+ connectorLivenessStatuses: () => connectorLivenessStatuses,
177898
178124
  conditionOperators: () => conditionOperators,
177899
178125
  closeDb: () => closeDb,
177900
178126
  closeContactOutcomes: () => closeContactOutcomes,
@@ -179690,11 +179916,11 @@ function isTerminal(state) {
179690
179916
  class A2ATaskStore {
179691
179917
  memory = new Map;
179692
179918
  storage;
179693
- constructor(storage) {
179694
- this.storage = storage;
179919
+ constructor(storage2) {
179920
+ this.storage = storage2;
179695
179921
  }
179696
- setStorage(storage) {
179697
- this.storage = storage;
179922
+ setStorage(storage2) {
179923
+ this.storage = storage2;
179698
179924
  }
179699
179925
  async createTask(params) {
179700
179926
  const now = new Date().toISOString();
@@ -201742,12 +201968,12 @@ var init_resource_Bhpm2sLf = __esm(() => {
201742
201968
  });
201743
201969
 
201744
201970
  // ../../node_modules/.bun/@sentry+opentelemetry@10.52.0+54dbe0b6443040f8/node_modules/@sentry/opentelemetry/build/esm/index.js
201745
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
201971
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
201746
201972
  import { EventEmitter as EventEmitter4 } from "events";
201747
201973
 
201748
201974
  class SentryAsyncLocalStorageContextManager {
201749
201975
  __init() {
201750
- this._asyncLocalStorage = new AsyncLocalStorage2;
201976
+ this._asyncLocalStorage = new AsyncLocalStorage3;
201751
201977
  }
201752
201978
  __init2() {
201753
201979
  this._kOtListeners = Symbol("OtListeners");
@@ -250680,7 +250906,7 @@ var init_sentry_scrub = __esm(() => {
250680
250906
  var require_package7 = __commonJS((exports, module) => {
250681
250907
  module.exports = {
250682
250908
  name: "@omni/api",
250683
- version: "2.260906.2",
250909
+ version: "2.260906.4",
250684
250910
  private: true,
250685
250911
  type: "module",
250686
250912
  exports: {
@@ -257665,23 +257891,23 @@ var require_Meter = __commonJS((exports) => {
257665
257891
  }
257666
257892
  createGauge(name, options) {
257667
257893
  const descriptor = (0, InstrumentDescriptor_1.createInstrumentDescriptor)(name, InstrumentDescriptor_1.InstrumentType.GAUGE, options);
257668
- const storage = this._meterSharedState.registerMetricStorage(descriptor);
257669
- return new Instruments_1.GaugeInstrument(storage, descriptor);
257894
+ const storage2 = this._meterSharedState.registerMetricStorage(descriptor);
257895
+ return new Instruments_1.GaugeInstrument(storage2, descriptor);
257670
257896
  }
257671
257897
  createHistogram(name, options) {
257672
257898
  const descriptor = (0, InstrumentDescriptor_1.createInstrumentDescriptor)(name, InstrumentDescriptor_1.InstrumentType.HISTOGRAM, options);
257673
- const storage = this._meterSharedState.registerMetricStorage(descriptor);
257674
- return new Instruments_1.HistogramInstrument(storage, descriptor);
257899
+ const storage2 = this._meterSharedState.registerMetricStorage(descriptor);
257900
+ return new Instruments_1.HistogramInstrument(storage2, descriptor);
257675
257901
  }
257676
257902
  createCounter(name, options) {
257677
257903
  const descriptor = (0, InstrumentDescriptor_1.createInstrumentDescriptor)(name, InstrumentDescriptor_1.InstrumentType.COUNTER, options);
257678
- const storage = this._meterSharedState.registerMetricStorage(descriptor);
257679
- return new Instruments_1.CounterInstrument(storage, descriptor);
257904
+ const storage2 = this._meterSharedState.registerMetricStorage(descriptor);
257905
+ return new Instruments_1.CounterInstrument(storage2, descriptor);
257680
257906
  }
257681
257907
  createUpDownCounter(name, options) {
257682
257908
  const descriptor = (0, InstrumentDescriptor_1.createInstrumentDescriptor)(name, InstrumentDescriptor_1.InstrumentType.UP_DOWN_COUNTER, options);
257683
- const storage = this._meterSharedState.registerMetricStorage(descriptor);
257684
- return new Instruments_1.UpDownCounterInstrument(storage, descriptor);
257909
+ const storage2 = this._meterSharedState.registerMetricStorage(descriptor);
257910
+ return new Instruments_1.UpDownCounterInstrument(storage2, descriptor);
257685
257911
  }
257686
257912
  createObservableGauge(name, options) {
257687
257913
  const descriptor = (0, InstrumentDescriptor_1.createInstrumentDescriptor)(name, InstrumentDescriptor_1.InstrumentType.OBSERVABLE_GAUGE, options);
@@ -258075,16 +258301,16 @@ var require_MetricStorageRegistry = __commonJS((exports) => {
258075
258301
  }
258076
258302
  return storages;
258077
258303
  }
258078
- register(storage) {
258079
- this._registerStorage(storage, this._sharedRegistry);
258304
+ register(storage2) {
258305
+ this._registerStorage(storage2, this._sharedRegistry);
258080
258306
  }
258081
- registerForCollector(collector, storage) {
258307
+ registerForCollector(collector, storage2) {
258082
258308
  let storageMap = this._perCollectorRegistry.get(collector);
258083
258309
  if (storageMap == null) {
258084
258310
  storageMap = new Map;
258085
258311
  this._perCollectorRegistry.set(collector, storageMap);
258086
258312
  }
258087
- this._registerStorage(storage, storageMap);
258313
+ this._registerStorage(storage2, storageMap);
258088
258314
  }
258089
258315
  findOrUpdateCompatibleStorage(expectedDescriptor) {
258090
258316
  const storages = this._sharedRegistry.get(expectedDescriptor.name);
@@ -258104,14 +258330,14 @@ var require_MetricStorageRegistry = __commonJS((exports) => {
258104
258330
  }
258105
258331
  return this._findOrUpdateCompatibleStorage(expectedDescriptor, storages);
258106
258332
  }
258107
- _registerStorage(storage, storageMap) {
258108
- const descriptor = storage.getInstrumentDescriptor();
258333
+ _registerStorage(storage2, storageMap) {
258334
+ const descriptor = storage2.getInstrumentDescriptor();
258109
258335
  const storages = storageMap.get(descriptor.name);
258110
258336
  if (storages === undefined) {
258111
- storageMap.set(descriptor.name, [storage]);
258337
+ storageMap.set(descriptor.name, [storage2]);
258112
258338
  return;
258113
258339
  }
258114
- storages.push(storage);
258340
+ storages.push(storage2);
258115
258341
  }
258116
258342
  _findOrUpdateCompatibleStorage(expectedDescriptor, existingStorages) {
258117
258343
  let compatibleStorage = null;
@@ -258459,9 +258685,9 @@ var require_MeterSharedState = __commonJS((exports) => {
258459
258685
  return compatibleStorage;
258460
258686
  }
258461
258687
  const aggregator = aggregation.createAggregator(descriptor);
258462
- const storage = new MetricStorageType(descriptor, aggregator, AttributesProcessor_1.AttributesProcessor.Noop(), [collector]);
258463
- this.metricStorageRegistry.registerForCollector(collector, storage);
258464
- return storage;
258688
+ const storage2 = new MetricStorageType(descriptor, aggregator, AttributesProcessor_1.AttributesProcessor.Noop(), [collector]);
258689
+ this.metricStorageRegistry.registerForCollector(collector, storage2);
258690
+ return storage2;
258465
258691
  });
258466
258692
  storages = storages.concat(collectorStorages);
258467
258693
  }
@@ -300023,7 +300249,7 @@ var Factory = class {
300023
300249
  return handlers2.filter((handler) => handler !== undefined);
300024
300250
  };
300025
300251
  }, createMiddleware = (middleware) => middleware;
300026
- var init_factory2 = __esm(() => {
300252
+ var init_factory3 = __esm(() => {
300027
300253
  init_hono2();
300028
300254
  });
300029
300255
 
@@ -300552,20 +300778,20 @@ var init_tenant_transaction = __esm(() => {
300552
300778
  });
300553
300779
 
300554
300780
  // ../api/src/tenancy/tenant-scope.ts
300555
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
300781
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
300556
300782
  function currentTenantScope() {
300557
- return storage.getStore() ?? null;
300783
+ return storage2.getStore() ?? null;
300558
300784
  }
300559
300785
  function scopedHandle(db2) {
300560
- const scope = storage.getStore();
300786
+ const scope = storage2.getStore();
300561
300787
  return scope ? scope.tx : db2;
300562
300788
  }
300563
300789
  async function runInTenantScope(db2, context20, fn) {
300564
- if (storage.getStore()) {
300790
+ if (storage2.getStore()) {
300565
300791
  throw new Error("tenant-scope: a tenant scope is already active for this request");
300566
300792
  }
300567
300793
  const postCommit = [];
300568
- const result = await withTenantTransaction(db2, context20, async (tx, tenantId) => storage.run({ tx, tenantId, postCommit }, fn));
300794
+ const result = await withTenantTransaction(db2, context20, async (tx, tenantId) => storage2.run({ tx, tenantId, postCommit }, fn));
300569
300795
  for (const cb of postCommit) {
300570
300796
  try {
300571
300797
  cb();
@@ -300574,7 +300800,7 @@ async function runInTenantScope(db2, context20, fn) {
300574
300800
  return result;
300575
300801
  }
300576
300802
  function runAfterTenantCommit(fn) {
300577
- const scope = storage.getStore();
300803
+ const scope = storage2.getStore();
300578
300804
  if (scope) {
300579
300805
  scope.postCommit.push(fn);
300580
300806
  } else {
@@ -300582,12 +300808,12 @@ function runAfterTenantCommit(fn) {
300582
300808
  }
300583
300809
  }
300584
300810
  function runDetachedFromTenantScope(fn) {
300585
- return storage.exit(fn);
300811
+ return storage2.exit(fn);
300586
300812
  }
300587
- var storage;
300813
+ var storage2;
300588
300814
  var init_tenant_scope = __esm(() => {
300589
300815
  init_tenant_transaction();
300590
- storage = new AsyncLocalStorage3;
300816
+ storage2 = new AsyncLocalStorage4;
300591
300817
  });
300592
300818
 
300593
300819
  // ../api/src/tenancy/auth-context.ts
@@ -300720,7 +300946,7 @@ function filterByInstanceAccess(items, getInstanceId, apiKey) {
300720
300946
  }
300721
300947
  var authMiddleware;
300722
300948
  var init_auth = __esm(() => {
300723
- init_factory2();
300949
+ init_factory3();
300724
300950
  init_api_keys();
300725
300951
  init_tenant_scope();
300726
300952
  init_worker_tenant_context();
@@ -300943,7 +301169,7 @@ function pathFromRequest(url) {
300943
301169
  var log59, REPLAY_WINDOW_MS = 60000, ED25519_SPKI_PREFIX, HEADER_HOST_ID = "x-genie-host-id", HEADER_TIMESTAMP = "x-genie-timestamp", HEADER_SIGNATURE = "x-genie-signature", genieSignatureMiddleware;
300944
301170
  var init_genie_signature = __esm(() => {
300945
301171
  init_src();
300946
- init_factory2();
301172
+ init_factory3();
300947
301173
  log59 = createLogger("api:genie-signature");
300948
301174
  ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
300949
301175
  genieSignatureMiddleware = createMiddleware(async (c, next) => {
@@ -301335,7 +301561,7 @@ async function emitRedactionEvents(c, apiKey, presetKey, hits) {
301335
301561
  var log60, SEND_ROUTE_PREFIXES, REDACTION_MARKER = "[redacted]", SECRET_REDACTED_EVENT = "secret.redacted", MAX_REDACT_BYTES, presetRegistry = null, outputRedactorMiddleware;
301336
301562
  var init_output_redactor = __esm(() => {
301337
301563
  init_src();
301338
- init_factory2();
301564
+ init_factory3();
301339
301565
  init_profiles();
301340
301566
  log60 = createLogger("api:output-redactor");
301341
301567
  SEND_ROUTE_PREFIXES = ["/messages/send"];
@@ -301499,6 +301725,7 @@ var init_scopes = __esm(() => {
301499
301725
  "GET /events/timeline/:personId": "events:read",
301500
301726
  "POST /events/search": "events:read",
301501
301727
  "GET /events/:id": "events:read",
301728
+ "GET /events/:id/trace": "events:read",
301502
301729
  "GET /events/by-sender/:senderId": "events:read",
301503
301730
  "GET /follow-up/agents/:id": "follow-up:read",
301504
301731
  "PUT /follow-up/agents/:id": "follow-up:write",
@@ -301898,7 +302125,7 @@ function invalidSignedHostScopeContextResponse(c, hostId) {
301898
302125
  var log61, OUTBOUND_SEND_PREFIXES, PATH_INSTANCE_PREFIXES, PATH_CHAT_PREFIXES, PATH_MEDIA_INSTANCE_PREFIX = "/media/", scopeEnforcerMiddleware;
301899
302126
  var init_scope_enforcer = __esm(() => {
301900
302127
  init_src();
301901
- init_factory2();
302128
+ init_factory3();
301902
302129
  init_profiles();
301903
302130
  init_scopes();
301904
302131
  init_signed_host_scope_context();
@@ -302020,7 +302247,7 @@ async function safeReadJsonBody2(c) {
302020
302247
  var log62, requireSignedInstanceMiddleware;
302021
302248
  var init_require_signed_instance = __esm(() => {
302022
302249
  init_src();
302023
- init_factory2();
302250
+ init_factory3();
302024
302251
  init_scope_enforcer();
302025
302252
  log62 = createLogger("api:require-signed-instance");
302026
302253
  requireSignedInstanceMiddleware = createMiddleware(async (c, next) => {
@@ -302317,6 +302544,7 @@ var init_route_ownership = __esm(() => {
302317
302544
  "GET /api/v2/events/:eventId/payloads",
302318
302545
  "GET /api/v2/events/:eventId/payloads/:stage",
302319
302546
  "GET /api/v2/events/:id",
302547
+ "GET /api/v2/events/:id/trace",
302320
302548
  "GET /api/v2/events/analytics",
302321
302549
  "GET /api/v2/events/by-sender/:senderId",
302322
302550
  "GET /api/v2/events/schemas",
@@ -302543,6 +302771,7 @@ var init_route_ownership = __esm(() => {
302543
302771
  "POST /api/v2/voice/leave",
302544
302772
  "POST /api/v2/webhook-sources",
302545
302773
  "POST /api/v2/webhooks/:source",
302774
+ "POST /api/v2/webhooks/:source/heartbeat",
302546
302775
  "PUT /api/v2/agent-state/:agentId/:chatId",
302547
302776
  "PUT /api/v2/follow-up/agents/:id",
302548
302777
  "PUT /api/v2/follow-up/chats/:id",
@@ -302727,7 +302956,7 @@ function refuseUnaddressableRoute(c) {
302727
302956
  }
302728
302957
  var TENANT_HINT_HEADER = "x-omni-tenant-id", tenancyMiddleware;
302729
302958
  var init_tenancy = __esm(() => {
302730
- init_factory2();
302959
+ init_factory3();
302731
302960
  init_route();
302732
302961
  init_route_ownership();
302733
302962
  init_scope_projection();
@@ -351163,24 +351392,24 @@ class InMemoryPluginStorage {
351163
351392
  }
351164
351393
  function setStorageDatabase(db2) {
351165
351394
  globalDb = db2;
351166
- for (const [pluginId, storage2] of storageInstances.entries()) {
351167
- if (storage2 instanceof InMemoryPluginStorage) {
351395
+ for (const [pluginId, storage3] of storageInstances.entries()) {
351396
+ if (storage3 instanceof InMemoryPluginStorage) {
351168
351397
  storageInstances.set(pluginId, new DatabasePluginStorage(db2, pluginId));
351169
351398
  }
351170
351399
  }
351171
351400
  }
351172
351401
  function getPluginStorage(pluginId) {
351173
- let storage2 = storageInstances.get(pluginId);
351174
- if (!storage2) {
351402
+ let storage3 = storageInstances.get(pluginId);
351403
+ if (!storage3) {
351175
351404
  if (globalDb) {
351176
- storage2 = new DatabasePluginStorage(globalDb, pluginId);
351405
+ storage3 = new DatabasePluginStorage(globalDb, pluginId);
351177
351406
  } else {
351178
351407
  log87.warn("Database not available, using in-memory storage", { pluginId });
351179
- storage2 = new InMemoryPluginStorage(pluginId);
351408
+ storage3 = new InMemoryPluginStorage(pluginId);
351180
351409
  }
351181
- storageInstances.set(pluginId, storage2);
351410
+ storageInstances.set(pluginId, storage3);
351182
351411
  }
351183
- return storage2;
351412
+ return storage3;
351184
351413
  }
351185
351414
  var log87, INSTANCE_ID_IN_KEY, globalDb = null, storageInstances;
351186
351415
  var init_storage = __esm(() => {
@@ -355451,7 +355680,8 @@ async function setupAgentDispatcher(eventBus, services, db2) {
355451
355680
  tracker.recordCheckpoint(firstMsg.metadata.correlationId, "T5", JOURNEY_STAGES.T5);
355452
355681
  }
355453
355682
  queuedAck?.release();
355454
- await processAgentResponse(services, instance4, messages4, triggerType, db2, eventBus);
355683
+ const lastMsg = messages4[messages4.length - 1] ?? firstMsg;
355684
+ await runWithEventCausality({ correlationId: lastMsg.metadata.correlationId, causationId: lastMsg.metadata.eventId }, () => processAgentResponse(services, instance4, messages4, triggerType, db2, eventBus));
355455
355685
  };
355456
355686
  const debouncer = new MessageDebouncer(onDebouncedFlush, Date.now, {
355457
355687
  onQueuedBehindActiveRun: (info2) => void ackQueuedMessage(info2)
@@ -355488,6 +355718,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
355488
355718
  platformIdentityId: metadata.platformIdentityId,
355489
355719
  traceId,
355490
355720
  correlationId: metadata.correlationId,
355721
+ eventId: event.id,
355491
355722
  journeyTracked: metadata.timings != null,
355492
355723
  resolvedInstance: resolved,
355493
355724
  routeId,
@@ -355519,14 +355750,14 @@ async function setupAgentDispatcher(eventBus, services, db2) {
355519
355750
  if (!instance4)
355520
355751
  return;
355521
355752
  const traceId = metadata.traceId ?? generateCorrelationId("trc");
355522
- await processReactionTrigger(services, instance4, payload, {
355753
+ await runWithEventCausality({ correlationId: metadata.correlationId, causationId: event.id }, () => processReactionTrigger(services, instance4, payload, {
355523
355754
  instanceId: instance4.id,
355524
355755
  channelType: metadata.channelType,
355525
355756
  personId: metadata.personId,
355526
355757
  platformIdentityId: metadata.platformIdentityId,
355527
355758
  traceId,
355528
355759
  trustedTenantId: trustedDispatchTenant(metadata)
355529
- }, event, db2);
355760
+ }, event, db2));
355530
355761
  } catch (error3) {
355531
355762
  log91.error("Error processing reaction for dispatch", {
355532
355763
  instanceId: metadata.instanceId,
@@ -355551,14 +355782,14 @@ async function setupAgentDispatcher(eventBus, services, db2) {
355551
355782
  if (!instance4)
355552
355783
  return;
355553
355784
  const traceId = metadata.traceId ?? generateCorrelationId("trc");
355554
- await processReactionTrigger(services, instance4, payload, {
355785
+ await runWithEventCausality({ correlationId: metadata.correlationId, causationId: event.id }, () => processReactionTrigger(services, instance4, payload, {
355555
355786
  instanceId: instance4.id,
355556
355787
  channelType: metadata.channelType,
355557
355788
  personId: metadata.personId,
355558
355789
  platformIdentityId: metadata.platformIdentityId,
355559
355790
  traceId,
355560
355791
  trustedTenantId: trustedDispatchTenant(metadata)
355561
- }, event, db2);
355792
+ }, event, db2));
355562
355793
  } catch (error3) {
355563
355794
  log91.error("Error processing reaction removal for dispatch", {
355564
355795
  instanceId: metadata.instanceId,
@@ -358067,6 +358298,9 @@ class DeadLetterService {
358067
358298
  }
358068
358299
  async create(options) {
358069
358300
  const insertData = prepareDeadLetterInsert(options);
358301
+ if (options.autoRetry === false) {
358302
+ insertData.nextAutoRetryAt = null;
358303
+ }
358070
358304
  const [result] = await this.db.insert(deadLetterEvents).values(insertData).returning();
358071
358305
  if (!result) {
358072
358306
  throw new Error("Failed to create dead letter entry");
@@ -358741,6 +358975,46 @@ class EventService {
358741
358975
  }
358742
358976
  return result;
358743
358977
  }
358978
+ async trace(id) {
358979
+ const focus = await this.getById(id);
358980
+ const seen = new Set([focus.id]);
358981
+ const ancestors = [];
358982
+ let current = focus;
358983
+ let truncated = false;
358984
+ while (current.causationId && ancestors.length < TRACE_MAX_ANCESTORS) {
358985
+ if (seen.has(current.causationId))
358986
+ break;
358987
+ const [parent] = await this.db.select().from(omniEvents).where(eq(omniEvents.id, current.causationId)).limit(1);
358988
+ if (!parent)
358989
+ break;
358990
+ seen.add(parent.id);
358991
+ ancestors.unshift(parent);
358992
+ current = parent;
358993
+ }
358994
+ if (current.causationId && ancestors.length >= TRACE_MAX_ANCESTORS)
358995
+ truncated = true;
358996
+ const descendants = [];
358997
+ let frontier = [focus.id];
358998
+ let depth = 0;
358999
+ while (frontier.length > 0 && depth < TRACE_MAX_DEPTH && descendants.length < TRACE_MAX_NODES) {
359000
+ depth++;
359001
+ const children = await this.db.select().from(omniEvents).where(inArray(omniEvents.causationId, frontier)).orderBy(omniEvents.receivedAt).limit(TRACE_MAX_NODES + 1);
359002
+ const fresh = children.filter((c) => !seen.has(c.id));
359003
+ for (const child of fresh)
359004
+ seen.add(child.id);
359005
+ for (const child of fresh)
359006
+ descendants.push({ event: child, depth });
359007
+ if (descendants.length > TRACE_MAX_NODES) {
359008
+ descendants.length = TRACE_MAX_NODES;
359009
+ truncated = true;
359010
+ break;
359011
+ }
359012
+ frontier = fresh.map((c) => c.id);
359013
+ }
359014
+ if (frontier.length > 0 && depth >= TRACE_MAX_DEPTH)
359015
+ truncated = true;
359016
+ return { event: focus, ancestors, descendants, truncated };
359017
+ }
358744
359018
  async getTimeline(personId, options = {}) {
358745
359019
  const { channels, since, until, limit: limit2 = 50, cursor } = options;
358746
359020
  const conditions3 = [eq(omniEvents.personId, personId)];
@@ -358842,6 +359116,7 @@ class EventService {
358842
359116
  };
358843
359117
  }
358844
359118
  }
359119
+ var TRACE_MAX_ANCESTORS = 50, TRACE_MAX_DEPTH = 10, TRACE_MAX_NODES = 200;
358845
359120
  var init_events2 = __esm(() => {
358846
359121
  init_src();
358847
359122
  init_src5();
@@ -363201,7 +363476,10 @@ class WebhookService {
363201
363476
  if (data.signatureSecret && !data.signatureConfig) {
363202
363477
  throw new ValidationError2("signatureSecret cannot be set without a signatureConfig");
363203
363478
  }
363204
- const values2 = data.signatureSecret ? { ...data, signatureSecret: sealCredentialField(this.tenantId, data.signatureSecret) } : data;
363479
+ let values2 = data.signatureSecret ? { ...data, signatureSecret: sealCredentialField(this.tenantId, data.signatureSecret) } : data;
363480
+ if (values2.expectedIntervalSeconds != null) {
363481
+ values2 = { ...values2, livenessArmedAt: new Date, livenessStatus: "healthy" };
363482
+ }
363205
363483
  const [created] = await this.db.insert(webhookSources).values(values2).returning();
363206
363484
  if (!created) {
363207
363485
  throw new Error("Failed to create webhook source");
@@ -363227,12 +363505,28 @@ class WebhookService {
363227
363505
  patch.signatureSecret = null;
363228
363506
  }
363229
363507
  }
363508
+ await this.applyLivenessArming(id, data, patch);
363230
363509
  const [updated] = await this.db.update(webhookSources).set({ ...patch, updatedAt: new Date }).where(eq(webhookSources.id, id)).returning();
363231
363510
  if (!updated) {
363232
363511
  throw new NotFoundError("WebhookSource", id);
363233
363512
  }
363234
363513
  return updated;
363235
363514
  }
363515
+ async applyLivenessArming(id, data, patch) {
363516
+ if (data.expectedIntervalSeconds === undefined)
363517
+ return;
363518
+ if (data.expectedIntervalSeconds === null) {
363519
+ patch.livenessStatus = null;
363520
+ patch.livenessArmedAt = null;
363521
+ patch.stalledAt = null;
363522
+ return;
363523
+ }
363524
+ patch.livenessArmedAt = new Date;
363525
+ const existing = await this.getById(id);
363526
+ if (existing.livenessStatus === null) {
363527
+ patch.livenessStatus = "healthy";
363528
+ }
363529
+ }
363236
363530
  async delete(id) {
363237
363531
  const result = await this.db.delete(webhookSources).where(eq(webhookSources.id, id)).returning();
363238
363532
  if (!result.length) {
@@ -363275,12 +363569,12 @@ class WebhookService {
363275
363569
  }
363276
363570
  }
363277
363571
  }
363278
- const eventId = generateId();
363279
363572
  const eventType = resolveWebhookEventType(sourceName, source.eventTypeMapping, headers);
363280
363573
  const eventPayload = {
363281
363574
  source: sourceName,
363282
363575
  ...payload
363283
363576
  };
363577
+ let eventId = generateId();
363284
363578
  await this.enforceRegisteredSchema(eventType, eventPayload, eventId, `webhook '${sourceName}'`);
363285
363579
  await this.db.update(webhookSources).set({
363286
363580
  lastReceivedAt: new Date,
@@ -363288,10 +363582,10 @@ class WebhookService {
363288
363582
  updatedAt: new Date
363289
363583
  }).where(eq(webhookSources.id, source.id));
363290
363584
  if (this.eventBus) {
363291
- await this.eventBus.publishGeneric(eventType, eventPayload, {
363292
- correlationId: eventId,
363585
+ const result = await this.eventBus.publishGeneric(eventType, eventPayload, {
363293
363586
  source: "webhook"
363294
363587
  });
363588
+ eventId = result.id;
363295
363589
  }
363296
363590
  return {
363297
363591
  received: true,
@@ -363348,17 +363642,112 @@ class WebhookService {
363348
363642
  throw new ValidationError2(`${SCHEMA_VALIDATION_FAILED}: payload for '${eventType}' violates its registered schema (${origin})`, undefined, { eventType, errors: verdict.errors });
363349
363643
  }
363350
363644
  async trigger(eventType, payload, metadata) {
363351
- const eventId = metadata?.correlationId ?? generateId();
363352
- await this.enforceRegisteredSchema(eventType, payload, eventId, "manual trigger");
363645
+ const provisionalId = metadata?.correlationId ?? generateId();
363646
+ await this.enforceRegisteredSchema(eventType, payload, provisionalId, "manual trigger");
363353
363647
  if (this.eventBus) {
363354
- await this.eventBus.publishGeneric(eventType, payload, {
363355
- correlationId: eventId,
363648
+ const result = await this.eventBus.publishGeneric(eventType, payload, {
363649
+ correlationId: metadata?.correlationId,
363356
363650
  instanceId: metadata?.instanceId,
363357
363651
  source: "manual-trigger"
363358
363652
  });
363359
- return { eventId, published: true };
363653
+ return { eventId: result.id, published: true };
363654
+ }
363655
+ return { eventId: provisionalId, published: false };
363656
+ }
363657
+ async heartbeat(sourceName) {
363658
+ const source = await this.getByName(sourceName);
363659
+ if (!source) {
363660
+ throw new NotFoundError("WebhookSource", sourceName);
363661
+ }
363662
+ if (!source.enabled) {
363663
+ throw new OmniError({
363664
+ code: ERROR_CODES.FORBIDDEN,
363665
+ message: `Webhook source '${sourceName}' is disabled`,
363666
+ context: { sourceName }
363667
+ });
363668
+ }
363669
+ const now = new Date;
363670
+ await this.db.update(webhookSources).set({
363671
+ lastHeartbeatAt: now,
363672
+ heartbeatCount: sql`${webhookSources.heartbeatCount} + 1`,
363673
+ updatedAt: now
363674
+ }).where(eq(webhookSources.id, source.id));
363675
+ return {
363676
+ ok: true,
363677
+ source: sourceName,
363678
+ heartbeatAt: now.toISOString(),
363679
+ livenessStatus: source.livenessStatus,
363680
+ expectedIntervalSeconds: source.expectedIntervalSeconds
363681
+ };
363682
+ }
363683
+ async sweepLiveness(options = {}) {
363684
+ const { deadLetters } = options;
363685
+ const hooks2 = deadLetters ? {
363686
+ onStalled: (row, payload, publishedEventId) => fileStallDeadLetter(deadLetters, row, payload, publishedEventId),
363687
+ onRecovered: (row) => resolveStallDeadLetters(deadLetters, row)
363688
+ } : {};
363689
+ return sweepConnectorLiveness({
363690
+ repo: this.livenessRepo(),
363691
+ eventBus: this.eventBus,
363692
+ logger: log111,
363693
+ ...hooks2
363694
+ });
363695
+ }
363696
+ livenessRepo() {
363697
+ return {
363698
+ findSupervised: async () => {
363699
+ const rows = await this.db.select().from(webhookSources).where(and2(eq(webhookSources.enabled, true), isNotNull(webhookSources.expectedIntervalSeconds)));
363700
+ return rows.filter((row) => row.expectedIntervalSeconds !== null).map((row) => ({
363701
+ id: row.id,
363702
+ name: row.name,
363703
+ expectedIntervalSeconds: row.expectedIntervalSeconds,
363704
+ lastReceivedAt: row.lastReceivedAt,
363705
+ lastHeartbeatAt: row.lastHeartbeatAt,
363706
+ livenessArmedAt: row.livenessArmedAt,
363707
+ livenessStatus: row.livenessStatus,
363708
+ stalledAt: row.stalledAt,
363709
+ createdAt: row.createdAt,
363710
+ tenantId: row.tenantId
363711
+ }));
363712
+ },
363713
+ markStalled: async (id, at) => {
363714
+ const res = await this.db.update(webhookSources).set({ livenessStatus: "stalled", stalledAt: at, updatedAt: at }).where(and2(eq(webhookSources.id, id), sql`${webhookSources.livenessStatus} IS DISTINCT FROM 'stalled'`)).returning({ id: webhookSources.id });
363715
+ return res.length > 0;
363716
+ },
363717
+ markRecovered: async (id, at) => {
363718
+ const res = await this.db.update(webhookSources).set({ livenessStatus: "healthy", stalledAt: null, updatedAt: at }).where(and2(eq(webhookSources.id, id), eq(webhookSources.livenessStatus, "stalled"))).returning({ id: webhookSources.id });
363719
+ return res.length > 0;
363720
+ }
363721
+ };
363722
+ }
363723
+ }
363724
+ async function fileStallDeadLetter(deadLetters, row, payload, publishedEventId) {
363725
+ const event = {
363726
+ id: publishedEventId ?? generateId(),
363727
+ type: "system.connector.stalled",
363728
+ payload: { ...payload },
363729
+ metadata: {
363730
+ correlationId: generateId(),
363731
+ source: "connector-liveness",
363732
+ ...row.tenantId ? { tenantId: row.tenantId } : {}
363733
+ },
363734
+ timestamp: payload.stalledAt
363735
+ };
363736
+ await deadLetters.create({
363737
+ event,
363738
+ subject: "system.connector.stalled.internal.global",
363739
+ error: new Error(`Connector '${row.name}' declared >=1 event or heartbeat per ${row.expectedIntervalSeconds}s ` + `but has been silent for ${payload.silentForSeconds}s`),
363740
+ retryCount: 0,
363741
+ autoRetry: false
363742
+ });
363743
+ }
363744
+ async function resolveStallDeadLetters(deadLetters, row) {
363745
+ const { items } = await deadLetters.list({ status: ["pending"], eventType: ["system.connector.stalled"] });
363746
+ for (const entry of items) {
363747
+ const stored = entry.payload;
363748
+ if (stored.payload?.sourceId === row.id) {
363749
+ await deadLetters.resolve(entry.id, "connector-liveness: recovered");
363360
363750
  }
363361
- return { eventId, published: false };
363362
363751
  }
363363
363752
  }
363364
363753
  var log111;
@@ -363526,7 +363915,7 @@ function createContextMiddleware(db2, eventBus, channelRegistry2 = null) {
363526
363915
  return { middleware, services };
363527
363916
  }
363528
363917
  var init_context4 = __esm(() => {
363529
- init_factory2();
363918
+ init_factory3();
363530
363919
  init_services();
363531
363920
  });
363532
363921
 
@@ -363901,7 +364290,7 @@ function createRateLimiter2(config4 = RATE_LIMITS.general, keyPrefix = "ratelimi
363901
364290
  var log113, warnedUnparseableProxyHop = false, rateLimitStore, cleanupTimer, RATE_LIMITS, clientIpSchema, rateLimitMiddleware, webhookIngressRateLimitMiddleware;
363902
364291
  var init_rate_limit = __esm(() => {
363903
364292
  init_src();
363904
- init_factory2();
364293
+ init_factory3();
363905
364294
  init_zod();
363906
364295
  log113 = createLogger("api:rate-limit");
363907
364296
  rateLimitStore = new Map;
@@ -363945,7 +364334,7 @@ function timeoutMiddleware(config4 = {}) {
363945
364334
  }
363946
364335
  var DEFAULT_TIMEOUT_MS8 = 30000, defaultTimeoutMiddleware;
363947
364336
  var init_timeout = __esm(() => {
363948
- init_factory2();
364337
+ init_factory3();
363949
364338
  init_http_exception();
363950
364339
  defaultTimeoutMiddleware = timeoutMiddleware();
363951
364340
  });
@@ -363999,7 +364388,7 @@ function loadServerVersionInfo() {
363999
364388
  }
364000
364389
  var import__package, EMBEDDED_VERSION, LAST_RESORT_VERSION = "2.0.0-dev.1", FALLBACK_COMMIT = "unknown", SERVER_VERSION_INFO, versionHeadersMiddleware;
364001
364390
  var init_version_headers = __esm(() => {
364002
- init_factory2();
364391
+ init_factory3();
364003
364392
  import__package = __toESM(require_package7(), 1);
364004
364393
  EMBEDDED_VERSION = import__package.default?.version;
364005
364394
  SERVER_VERSION_INFO = loadServerVersionInfo();
@@ -364038,7 +364427,7 @@ function createWebhookAuthMiddleware(config4) {
364038
364427
  var log114;
364039
364428
  var init_webhook_auth = __esm(() => {
364040
364429
  init_src();
364041
- init_factory2();
364430
+ init_factory3();
364042
364431
  log114 = createLogger("api:webhook-auth");
364043
364432
  });
364044
364433
 
@@ -366358,7 +366747,8 @@ var init_automations3 = __esm(() => {
366358
366747
  bodyTemplate: exports_external.string().optional(),
366359
366748
  waitForResponse: exports_external.boolean().default(false),
366360
366749
  timeoutMs: exports_external.number().int().default(30000),
366361
- responseAs: exports_external.string().optional()
366750
+ responseAs: exports_external.string().optional(),
366751
+ includeEnvelope: exports_external.boolean().optional().openapi({ description: "Send the full OmniEvent envelope as the default body (default true)" })
366362
366752
  })
366363
366753
  });
366364
366754
  SendMessageActionSchema = exports_external.object({
@@ -366994,6 +367384,7 @@ function registerEventSchemas(registry4) {
366994
367384
  registry4.register("EventSummary", EventSummarySchema);
366995
367385
  registry4.register("EventAnalytics", EventAnalyticsSchema);
366996
367386
  registry4.register("EventSearch", EventSearchSchema);
367387
+ registry4.register("EventTrace", EventTraceSchema);
366997
367388
  registry4.registerPath({
366998
367389
  method: "get",
366999
367390
  path: "/events",
@@ -367118,6 +367509,22 @@ function registerEventSchemas(registry4) {
367118
367509
  404: { description: "Event not found", content: { "application/json": { schema: ErrorSchema } } }
367119
367510
  }
367120
367511
  });
367512
+ registry4.registerPath({
367513
+ method: "get",
367514
+ path: "/events/{id}/trace",
367515
+ operationId: "traceEvent",
367516
+ tags: ["Events"],
367517
+ summary: "Trace the causality chain around an event",
367518
+ description: "Walks UP via causationId to the root ingress event and DOWN breadth-first through fan-out (children are events whose causationId equals this id). correlationId groups the flow; causationId gives the tree.",
367519
+ request: { params: exports_external.object({ id: exports_external.string().uuid().openapi({ description: "Event UUID" }) }) },
367520
+ responses: {
367521
+ 200: {
367522
+ description: "Causality trace",
367523
+ content: { "application/json": { schema: exports_external.object({ data: EventTraceSchema }) } }
367524
+ },
367525
+ 404: { description: "Event not found", content: { "application/json": { schema: ErrorSchema } } }
367526
+ }
367527
+ });
367121
367528
  registry4.registerPath({
367122
367529
  method: "get",
367123
367530
  path: "/events/by-sender/{senderId}",
@@ -367147,7 +367554,7 @@ function registerEventSchemas(registry4) {
367147
367554
  }
367148
367555
  });
367149
367556
  }
367150
- var EventSchema, EventSummarySchema, EventAnalyticsSchema, EventSearchSchema;
367557
+ var EventSchema, EventSummarySchema, EventAnalyticsSchema, EventTraceSchema, EventSearchSchema;
367151
367558
  var init_events3 = __esm(() => {
367152
367559
  init_zod_openapi();
367153
367560
  init_common4();
@@ -367165,7 +367572,8 @@ var init_events3 = __esm(() => {
367165
367572
  agentId: exports_external.string().uuid().nullable().openapi({ description: "Agent UUID (FK \u2192 agents.id)" }),
367166
367573
  conversationId: exports_external.string().uuid().nullable().openapi({ description: "Conversation UUID (FK \u2192 conversations.id)" }),
367167
367574
  receivedAt: exports_external.string().datetime().openapi({ description: "When event was received" }),
367168
- processedAt: exports_external.string().datetime().nullable().openapi({ description: "When event was processed" })
367575
+ processedAt: exports_external.string().datetime().nullable().openapi({ description: "When event was processed" }),
367576
+ causationId: exports_external.string().uuid().nullable().openapi({ description: "Id of the immediate parent event (null for roots and pre-#957 rows)" })
367169
367577
  });
367170
367578
  EventSummarySchema = exports_external.object({
367171
367579
  id: exports_external.string().uuid().openapi({ description: "Event UUID" }),
@@ -367194,6 +367602,15 @@ var init_events3 = __esm(() => {
367194
367602
  count: exports_external.number().int().openapi({ description: "Event count in bucket" })
367195
367603
  })).optional().openapi({ description: "Timeline data (hourly or daily buckets)" })
367196
367604
  });
367605
+ EventTraceSchema = exports_external.object({
367606
+ event: EventSchema.openapi({ description: "The event the trace was requested for" }),
367607
+ ancestors: exports_external.array(EventSchema).openapi({ description: "Chain above the event via causationId, root first, ending at the immediate parent" }),
367608
+ descendants: exports_external.array(exports_external.object({
367609
+ event: EventSchema,
367610
+ depth: exports_external.number().int().openapi({ description: "Distance below the focus event (1 = direct child)" })
367611
+ })).openapi({ description: "Fan-out below the event, breadth-first" }),
367612
+ truncated: exports_external.boolean().openapi({ description: "True when a depth/node cap cut the walk short" })
367613
+ });
367197
367614
  EventSearchSchema = exports_external.object({
367198
367615
  query: exports_external.string().optional().openapi({ description: "Full-text search query" }),
367199
367616
  filters: exports_external.object({
@@ -369789,6 +370206,7 @@ function registerWebhookSchemas(registry4) {
369789
370206
  registry4.register("CreateWebhookSourceRequest", CreateWebhookSourceSchema);
369790
370207
  registry4.register("TriggerEventRequest", TriggerEventSchema);
369791
370208
  registry4.register("WebhookReceiveResponse", WebhookReceiveResponseSchema);
370209
+ registry4.register("WebhookHeartbeatResponse", WebhookHeartbeatResponseSchema);
369792
370210
  registry4.registerPath({
369793
370211
  method: "get",
369794
370212
  path: "/webhook-sources",
@@ -369887,6 +370305,25 @@ function registerWebhookSchemas(registry4) {
369887
370305
  400: { description: "Body is not a JSON object", content: { "application/json": { schema: ErrorSchema } } }
369888
370306
  }
369889
370307
  });
370308
+ registry4.registerPath({
370309
+ method: "post",
370310
+ path: "/webhooks/{source}/heartbeat",
370311
+ operationId: "heartbeatWebhookSource",
370312
+ tags: ["Webhooks"],
370313
+ summary: "Connector heartbeat",
370314
+ description: 'Record a connector heartbeat: "I ran, zero events found". Resets the liveness window of a supervised ' + "source (one declaring expectedIntervalSeconds) so silence-beyond-window detection can tell quiet from " + "dead. Creates NO journal event \u2014 only the stalled/recovered transitions are journaled. No request body.",
370315
+ request: {
370316
+ params: exports_external.object({ source: exports_external.string().openapi({ description: "Source name" }) })
370317
+ },
370318
+ responses: {
370319
+ 200: {
370320
+ description: "Heartbeat recorded",
370321
+ content: { "application/json": { schema: WebhookHeartbeatResponseSchema } }
370322
+ },
370323
+ 403: { description: "Source disabled", content: { "application/json": { schema: ErrorSchema } } },
370324
+ 404: { description: "Source not found", content: { "application/json": { schema: ErrorSchema } } }
370325
+ }
370326
+ });
369890
370327
  registry4.registerPath({
369891
370328
  method: "post",
369892
370329
  path: "/webhooks/ingress/{source}",
@@ -369925,7 +370362,7 @@ function registerWebhookSchemas(registry4) {
369925
370362
  }
369926
370363
  });
369927
370364
  }
369928
- var WebhookSignatureConfigSchema, WebhookEventTypeMappingSchema, WebhookSourceSchema, CreateWebhookSourceSchema, TriggerEventSchema, WebhookReceiveResponseSchema;
370365
+ var WebhookSignatureConfigSchema, WebhookEventTypeMappingSchema, WebhookSourceSchema, CreateWebhookSourceSchema, WebhookHeartbeatResponseSchema, TriggerEventSchema, WebhookReceiveResponseSchema;
369929
370366
  var init_webhooks2 = __esm(() => {
369930
370367
  init_src5();
369931
370368
  init_zod_openapi();
@@ -369963,6 +370400,16 @@ var init_webhooks2 = __esm(() => {
369963
370400
  }),
369964
370401
  hasSignatureSecret: exports_external.boolean().openapi({ description: "Whether a signature secret is stored (secret is write-only)" }),
369965
370402
  enabled: exports_external.boolean().openapi({ description: "Whether enabled" }),
370403
+ lastReceivedAt: exports_external.string().datetime().nullable().openapi({ description: "When the last webhook was received" }),
370404
+ totalReceived: exports_external.number().int().openapi({ description: "Total webhooks received" }),
370405
+ expectedIntervalSeconds: exports_external.number().int().nullable().openapi({ description: "Declared cadence: >=1 event or heartbeat per N seconds. Null = unsupervised" }),
370406
+ lastHeartbeatAt: exports_external.string().datetime().nullable().openapi({ description: 'Last heartbeat ("ran, zero events")' }),
370407
+ heartbeatCount: exports_external.number().int().openapi({ description: "Total heartbeats received" }),
370408
+ livenessStatus: exports_external.enum(connectorLivenessStatuses).nullable().openapi({ description: "Liveness state; null = unsupervised. Transitions emit system.connector.* events" }),
370409
+ livenessArmedAt: exports_external.string().datetime().nullable().openapi({ description: "When the cadence was (re)declared" }),
370410
+ stalledAt: exports_external.string().datetime().nullable().openapi({ description: "When the current stall began" }),
370411
+ windowSemantics: exports_external.enum(connectorWindowSemanticsValues).nullable().openapi({ description: "Declared window semantics; null = undeclared" }),
370412
+ mutationPolicy: exports_external.enum(connectorMutationPolicies).nullable().openapi({ description: "Declared upstream-mutation re-emit policy; null = undeclared" }),
369966
370413
  createdAt: exports_external.string().datetime().openapi({ description: "Creation timestamp" }),
369967
370414
  updatedAt: exports_external.string().datetime().openapi({ description: "Last update timestamp" })
369968
370415
  });
@@ -369979,7 +370426,23 @@ var init_webhooks2 = __esm(() => {
369979
370426
  eventTypeMapping: WebhookEventTypeMappingSchema.nullable().optional().openapi({
369980
370427
  description: "Semantic event-type extraction (e.g. header X-GitHub-Event: push emits custom.{source}.push). " + "Null or absent keeps the legacy collapsed custom.webhook.{source} type for every delivery."
369981
370428
  }),
369982
- enabled: exports_external.boolean().default(true).openapi({ description: "Whether enabled" })
370429
+ enabled: exports_external.boolean().default(true).openapi({ description: "Whether enabled" }),
370430
+ expectedIntervalSeconds: exports_external.number().int().min(1).max(2592000).nullable().optional().openapi({
370431
+ description: "Declared cadence: the connector promises >=1 event or heartbeat per N seconds (1s-30d). Declaring it " + "arms liveness supervision (silence beyond the window emits system.connector.stalled and marks the " + "source unhealthy); null disarms it."
370432
+ }),
370433
+ windowSemantics: exports_external.enum(connectorWindowSemanticsValues).nullable().optional().openapi({
370434
+ description: "Declared time-window semantics: 'future_only' (only not-yet-started items) or 'includes_in_progress'. " + "Informational contract for consumers; null = undeclared."
370435
+ }),
370436
+ mutationPolicy: exports_external.enum(connectorMutationPolicies).nullable().optional().openapi({
370437
+ description: "How the source re-emits a changed upstream item: 'same_id' (reschedule case \u2014 consumers must key on " + "id+content) or 'new_id'. Feeds the idempotency key template choice; null = undeclared."
370438
+ })
370439
+ });
370440
+ WebhookHeartbeatResponseSchema = exports_external.object({
370441
+ ok: exports_external.literal(true).openapi({ description: "Heartbeat recorded" }),
370442
+ source: exports_external.string().openapi({ description: "Webhook source name" }),
370443
+ heartbeatAt: exports_external.string().datetime().openapi({ description: "When the heartbeat was recorded" }),
370444
+ livenessStatus: exports_external.enum(connectorLivenessStatuses).nullable().openapi({ description: "Status before this heartbeat (a stalled source recovers on the next sweep tick)" }),
370445
+ expectedIntervalSeconds: exports_external.number().int().nullable().openapi({ description: "Declared cadence, if any" })
369983
370446
  });
369984
370447
  TriggerEventSchema = exports_external.object({
369985
370448
  eventType: exports_external.string().min(1).openapi({ description: "Event type (must start with custom.)" }),
@@ -371547,7 +372010,8 @@ var init_automations4 = __esm(() => {
371547
372010
  bodyTemplate: exports_external.string().optional().describe("Request body template (JSON)"),
371548
372011
  waitForResponse: exports_external.boolean().default(false).describe("Wait for response before continuing"),
371549
372012
  timeoutMs: exports_external.number().int().min(1000).max(120000).default(30000).describe("Request timeout"),
371550
- responseAs: exports_external.string().optional().describe("Store response as variable name")
372013
+ responseAs: exports_external.string().optional().describe("Store response as variable name"),
372014
+ includeEnvelope: exports_external.boolean().optional().describe("Send the full OmniEvent envelope as the default body when no bodyTemplate is set (default true)")
371551
372015
  })
371552
372016
  });
371553
372017
  sendMessageActionSchema = exports_external.object({
@@ -373343,6 +373807,16 @@ var init_events4 = __esm(() => {
373343
373807
  }
373344
373808
  return c.json({ data: event });
373345
373809
  });
373810
+ eventsRoutes.get("/:id/trace", async (c) => {
373811
+ const id = c.req.param("id");
373812
+ const services = c.get("services");
373813
+ const apiKey = c.get("apiKey");
373814
+ const trace24 = await services.events.trace(id);
373815
+ if (trace24.event.instanceId && apiKey && !ApiKeyService.instanceAllowed(apiKey.instanceIds, trace24.event.instanceId)) {
373816
+ return c.json({ error: { code: "FORBIDDEN", message: "API key does not have access to this instance" } }, 403);
373817
+ }
373818
+ return c.json({ data: trace24 });
373819
+ });
373346
373820
  eventsRoutes.get("/by-sender/:senderId", async (c) => {
373347
373821
  const senderId = c.req.param("senderId");
373348
373822
  const instanceId = c.req.query("instanceId");
@@ -378596,14 +379070,14 @@ var init_media2 = __esm(() => {
378596
379070
  }
378597
379071
  const relativePath = `${instanceId}/${path3}`;
378598
379072
  const db2 = c.get("services");
378599
- const storage2 = getMediaStorage(db2);
379073
+ const storage3 = getMediaStorage(db2);
378600
379074
  try {
378601
- const stat5 = await storage2.statMedia(relativePath);
379075
+ const stat5 = await storage3.statMedia(relativePath);
378602
379076
  if (!stat5) {
378603
379077
  return c.json({ error: { code: "NOT_FOUND", message: "Media not found" } }, 404);
378604
379078
  }
378605
379079
  const fileSize = stat5.size;
378606
- const mimeType = storage2.getMimeType(path3);
379080
+ const mimeType = storage3.getMimeType(path3);
378607
379081
  const rangeHeader = c.req.header("Range");
378608
379082
  if (rangeHeader) {
378609
379083
  const matches = rangeHeader.match(/bytes=(\d+)-(\d*)/);
@@ -378617,7 +379091,7 @@ var init_media2 = __esm(() => {
378617
379091
  headers: { "Content-Range": `bytes */${fileSize}`, "Accept-Ranges": "bytes" }
378618
379092
  });
378619
379093
  }
378620
- const chunk2 = await storage2.readMediaRange(relativePath, start, end);
379094
+ const chunk2 = await storage3.readMediaRange(relativePath, start, end);
378621
379095
  return new Response(chunk2, {
378622
379096
  status: 206,
378623
379097
  headers: {
@@ -378629,7 +379103,7 @@ var init_media2 = __esm(() => {
378629
379103
  });
378630
379104
  }
378631
379105
  }
378632
- const stream2 = await storage2.readMediaStream(relativePath);
379106
+ const stream2 = await storage3.readMediaStream(relativePath);
378633
379107
  return new Response(stream2, {
378634
379108
  status: 200,
378635
379109
  headers: {
@@ -382522,6 +382996,12 @@ var init_webhooks3 = __esm(() => {
382522
382996
  });
382523
382997
  return c.json(result);
382524
382998
  });
382999
+ webhooksRoutes.post("/webhooks/:source/heartbeat", async (c) => {
383000
+ const sourceName = c.req.param("source");
383001
+ const services = c.get("services");
383002
+ const result = await services.webhooks.heartbeat(sourceName);
383003
+ return c.json(result);
383004
+ });
382525
383005
  triggerEventSchema = exports_external.object({
382526
383006
  eventType: exports_external.string().min(1).refine((t) => t.startsWith("custom."), { message: 'Event type must start with "custom."' }).describe("Event type (must be custom.*)"),
382527
383007
  payload: exports_external.record(exports_external.string(), exports_external.unknown()).describe("Event payload"),
@@ -383421,7 +383901,7 @@ function platformAuthMiddleware(requiredScope, platformAction) {
383421
383901
  }
383422
383902
  var UNAUTHORIZED, FORBIDDEN;
383423
383903
  var init_platform_auth = __esm(() => {
383424
- init_factory2();
383904
+ init_factory3();
383425
383905
  init_api_keys();
383426
383906
  UNAUTHORIZED = { error: { code: "UNAUTHORIZED", message: "Platform credential required" } };
383427
383907
  FORBIDDEN = {
@@ -384213,6 +384693,7 @@ async function setupEventPersistence(eventBus, db2) {
384213
384693
  from: payload.from
384214
384694
  },
384215
384695
  agentId: metadata.agentId ?? null,
384696
+ causationId: metadata.causationId ?? null,
384216
384697
  conversationId: null,
384217
384698
  chatUuid
384218
384699
  };
@@ -384266,6 +384747,7 @@ async function setupEventPersistence(eventBus, db2) {
384266
384747
  voiceNote: payload.content.isVoiceNote
384267
384748
  },
384268
384749
  agentId: metadata.agentId ?? null,
384750
+ causationId: metadata.causationId ?? null,
384269
384751
  conversationId: null,
384270
384752
  chatUuid
384271
384753
  };
@@ -384306,6 +384788,7 @@ async function setupEventPersistence(eventBus, db2) {
384306
384788
  receivedAt: new Date(event.timestamp),
384307
384789
  deliveredAt: new Date(payload.deliveredAt),
384308
384790
  agentId: metadata.agentId ?? null,
384791
+ causationId: metadata.causationId ?? null,
384309
384792
  conversationId: null,
384310
384793
  chatUuid
384311
384794
  };
@@ -384345,6 +384828,7 @@ async function setupEventPersistence(eventBus, db2) {
384345
384828
  receivedAt: new Date(event.timestamp),
384346
384829
  readAt: new Date(payload.readAt),
384347
384830
  agentId: metadata.agentId ?? null,
384831
+ causationId: metadata.causationId ?? null,
384348
384832
  conversationId: null,
384349
384833
  chatUuid
384350
384834
  };
@@ -384399,6 +384883,7 @@ async function setupEventPersistence(eventBus, db2) {
384399
384883
  retryable: payload.retryable
384400
384884
  },
384401
384885
  agentId: metadata.agentId ?? null,
384886
+ causationId: metadata.causationId ?? null,
384402
384887
  conversationId: null,
384403
384888
  chatUuid
384404
384889
  };
@@ -384419,6 +384904,38 @@ async function setupEventPersistence(eventBus, db2) {
384419
384904
  });
384420
384905
  }
384421
384906
  }, { ...CONSUMER_OPTIONS, durable: "event-persistence-failed" });
384907
+ await eventBus.subscribePattern("custom.>", async (event) => {
384908
+ const metadata = event.metadata;
384909
+ try {
384910
+ await runConsumerInTenantContext(db2, event, async () => {
384911
+ const sdb = scopedHandle(db2);
384912
+ const newEvent = {
384913
+ ...eventIdInsert(event.id),
384914
+ channel: "internal",
384915
+ instanceId: metadata.instanceId && isValidUuid(metadata.instanceId) ? metadata.instanceId : null,
384916
+ eventType: event.type.slice(0, 50),
384917
+ direction: "internal",
384918
+ status: "completed",
384919
+ receivedAt: new Date(event.timestamp),
384920
+ rawPayload: deepSanitize(event.payload),
384921
+ metadata: {
384922
+ correlationId: metadata.correlationId,
384923
+ source: metadata.source,
384924
+ fullEventType: event.type
384925
+ },
384926
+ causationId: metadata.causationId ?? null,
384927
+ conversationId: null
384928
+ };
384929
+ await sdb.insert(omniEvents).values(newEvent).onConflictDoNothing({ target: omniEvents.id });
384930
+ });
384931
+ } catch (error3) {
384932
+ log124.error("Failed to persist custom event", {
384933
+ eventType: event.type,
384934
+ eventId: event.id,
384935
+ error: String(error3)
384936
+ });
384937
+ }
384938
+ }, { ...CONSUMER_OPTIONS, durable: "event-persistence-custom", startFrom: "new" });
384422
384939
  log124.info("Event persistence initialized - listening for message events");
384423
384940
  } catch (error3) {
384424
384941
  log124.error("Failed to set up event persistence", { error: String(error3) });
@@ -386672,6 +387189,26 @@ function setupScheduler(services, channelRegistry2) {
386672
387189
  });
386673
387190
  }
386674
387191
  });
387192
+ scheduler.register({
387193
+ name: "connector-liveness-sweeper",
387194
+ cron: "*/30 * * * * *",
387195
+ runOnStart: false,
387196
+ handler: async () => {
387197
+ await withCronMonitor("connector-liveness-sweeper", "*/30 * * * * *", 1, 1, async () => {
387198
+ const startTime3 = Date.now();
387199
+ try {
387200
+ const stats = await services.webhooks.sweepLiveness({ deadLetters: services.deadLetters });
387201
+ recordScheduledJob("connector-liveness-sweeper", "success", (Date.now() - startTime3) / 1000);
387202
+ if (stats.stalled > 0 || stats.recovered > 0) {
387203
+ log130.info("Connector liveness sweep tick", { ...stats });
387204
+ }
387205
+ } catch (err2) {
387206
+ recordScheduledJob("connector-liveness-sweeper", "failure", (Date.now() - startTime3) / 1000);
387207
+ throw err2;
387208
+ }
387209
+ });
387210
+ }
387211
+ });
386675
387212
  if (channelRegistry2) {
386676
387213
  const scheduledMessages2 = createScheduledMessageSweeper(services, channelRegistry2);
386677
387214
  scheduler.register({
@@ -389364,27 +389901,27 @@ var import_discord5 = __toESM(require_src2(), 1);
389364
389901
  // ../channel-discord/src/auth.ts
389365
389902
  init_src();
389366
389903
  var log21 = createLogger("discord:auth");
389367
- async function loadToken(storage, instanceId) {
389904
+ async function loadToken(storage2, instanceId) {
389368
389905
  const key = `${instanceId}:token`;
389369
- const data = await storage.get(key);
389906
+ const data = await storage2.get(key);
389370
389907
  if (data?.token) {
389371
389908
  log21.debug("Loaded token from storage", { instanceId });
389372
389909
  return data.token;
389373
389910
  }
389374
389911
  return null;
389375
389912
  }
389376
- async function saveToken(storage, instanceId, token) {
389913
+ async function saveToken(storage2, instanceId, token) {
389377
389914
  const key = `${instanceId}:token`;
389378
389915
  const data = {
389379
389916
  token,
389380
389917
  storedAt: Date.now()
389381
389918
  };
389382
- await storage.set(key, data);
389919
+ await storage2.set(key, data);
389383
389920
  log21.debug("Saved token to storage", { instanceId });
389384
389921
  }
389385
- async function clearToken(storage, instanceId) {
389922
+ async function clearToken(storage2, instanceId) {
389386
389923
  const key = `${instanceId}:token`;
389387
- await storage.delete(key);
389924
+ await storage2.delete(key);
389388
389925
  log21.debug("Cleared token from storage", { instanceId });
389389
389926
  }
389390
389927
 
@@ -489935,11 +490472,11 @@ class GroupCipher {
489935
490472
  const ret2 = wasm.groupcipher_encrypt(this.__wbg_ptr, ptr0, len0);
489936
490473
  return takeObject(ret2);
489937
490474
  }
489938
- constructor(storage, group_id, sender) {
490475
+ constructor(storage2, group_id, sender) {
489939
490476
  const ptr0 = passStringToWasm0(group_id, wasm.__wbindgen_export, wasm.__wbindgen_export2);
489940
490477
  const len0 = WASM_VECTOR_LEN;
489941
490478
  _assertClass(sender, ProtocolAddress);
489942
- const ret2 = wasm.groupcipher_new(addHeapObject(storage), ptr0, len0, sender.__wbg_ptr);
490479
+ const ret2 = wasm.groupcipher_new(addHeapObject(storage2), ptr0, len0, sender.__wbg_ptr);
489943
490480
  this.__wbg_ptr = ret2 >>> 0;
489944
490481
  GroupCipherFinalization.register(this, this.__wbg_ptr, this);
489945
490482
  return this;
@@ -489964,8 +490501,8 @@ class GroupSessionBuilder {
489964
490501
  const ret2 = wasm.groupsessionbuilder_create(this.__wbg_ptr, sender_key_name.__wbg_ptr);
489965
490502
  return takeObject(ret2);
489966
490503
  }
489967
- constructor(storage) {
489968
- const ret2 = wasm.groupsessionbuilder_new(addHeapObject(storage));
490504
+ constructor(storage2) {
490505
+ const ret2 = wasm.groupsessionbuilder_new(addHeapObject(storage2));
489969
490506
  this.__wbg_ptr = ret2 >>> 0;
489970
490507
  GroupSessionBuilderFinalization.register(this, this.__wbg_ptr, this);
489971
490508
  return this;
@@ -490621,9 +491158,9 @@ class SessionBuilder {
490621
491158
  const ret2 = wasm.sessionbuilder_initOutgoing(this.__wbg_ptr, addHeapObject(bundle_input));
490622
491159
  return takeObject(ret2);
490623
491160
  }
490624
- constructor(storage, remote_address) {
491161
+ constructor(storage2, remote_address) {
490625
491162
  _assertClass(remote_address, ProtocolAddress);
490626
- const ret2 = wasm.sessionbuilder_new(addHeapObject(storage), remote_address.__wbg_ptr);
491163
+ const ret2 = wasm.sessionbuilder_new(addHeapObject(storage2), remote_address.__wbg_ptr);
490627
491164
  this.__wbg_ptr = ret2 >>> 0;
490628
491165
  SessionBuilderFinalization.register(this, this.__wbg_ptr, this);
490629
491166
  return this;
@@ -490669,9 +491206,9 @@ class SessionCipher {
490669
491206
  const ret2 = wasm.sessioncipher_hasOpenSession(this.__wbg_ptr);
490670
491207
  return takeObject(ret2);
490671
491208
  }
490672
- constructor(storage, remote_address) {
491209
+ constructor(storage2, remote_address) {
490673
491210
  _assertClass(remote_address, ProtocolAddress);
490674
- const ret2 = wasm.sessionbuilder_new(addHeapObject(storage), remote_address.__wbg_ptr);
491211
+ const ret2 = wasm.sessionbuilder_new(addHeapObject(storage2), remote_address.__wbg_ptr);
490675
491212
  this.__wbg_ptr = ret2 >>> 0;
490676
491213
  SessionCipherFinalization.register(this, this.__wbg_ptr, this);
490677
491214
  return this;
@@ -498744,8 +499281,8 @@ var CacheableSync = class extends Hookified {
498744
499281
  data
498745
499282
  });
498746
499283
  }
498747
- subscribe(storage, cacheId) {
498748
- this._storage = storage;
499284
+ subscribe(storage2, cacheId) {
499285
+ this._storage = storage2;
498749
499286
  this._cacheId = cacheId;
498750
499287
  const setEvent = this.getPrefixedEvent("cache:set");
498751
499288
  const deleteEvent = this.getPrefixedEvent("cache:delete");
@@ -498753,7 +499290,7 @@ var CacheableSync = class extends Hookified {
498753
499290
  handler: async (message2) => {
498754
499291
  const data = message2.data;
498755
499292
  if (data.cacheId !== cacheId) {
498756
- await storage.set(data.key, data.value, data.ttl);
499293
+ await storage2.set(data.key, data.value, data.ttl);
498757
499294
  }
498758
499295
  }
498759
499296
  });
@@ -498761,7 +499298,7 @@ var CacheableSync = class extends Hookified {
498761
499298
  handler: async (message2) => {
498762
499299
  const data = message2.data;
498763
499300
  if (data.cacheId !== cacheId) {
498764
- await storage.delete(data.key);
499301
+ await storage2.delete(data.key);
498765
499302
  }
498766
499303
  }
498767
499304
  });
@@ -499749,7 +500286,7 @@ var index_default = NodeCache;
499749
500286
 
499750
500287
  // ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Utils/auth-utils.js
499751
500288
  var import_boom10 = __toESM(require_lib7(), 1);
499752
- import { AsyncLocalStorage } from "async_hooks";
500289
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
499753
500290
 
499754
500291
  // ../../node_modules/.bun/async-mutex@0.5.0/node_modules/async-mutex/index.mjs
499755
500292
  var E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
@@ -500725,7 +501262,7 @@ class PreKeyManager {
500725
501262
 
500726
501263
  // ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Utils/auth-utils.js
500727
501264
  var addTransactionCapability = (state, logger5, { maxCommitRetries, delayBetweenTriesMs }) => {
500728
- const txStorage = new AsyncLocalStorage;
501265
+ const txStorage = new AsyncLocalStorage2;
500729
501266
  const keyQueues = new Map;
500730
501267
  const txMutexes = new Map;
500731
501268
  const txMutexRefCounts = new Map;
@@ -503410,7 +503947,7 @@ function extractIdentityFromPkmsg(ciphertext) {
503410
503947
  }
503411
503948
  function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503412
503949
  const lidMapping = new LIDMappingStore(auth.keys, logger5, pnToLIDFunc);
503413
- const storage = signalStorage(auth, lidMapping);
503950
+ const storage2 = signalStorage(auth, lidMapping);
503414
503951
  const parsedKeys = auth.keys;
503415
503952
  const migratedSessionCache = new M({
503416
503953
  ttl: 3 * 24 * 60 * 60 * 1000,
@@ -503422,21 +503959,21 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503422
503959
  const senderNameStr = senderName.toString();
503423
503960
  const { [senderNameStr]: senderKey } = await auth.keys.get("sender-key", [senderNameStr]);
503424
503961
  if (!senderKey) {
503425
- await storage.storeSenderKey(senderName, new SenderKeyRecord2);
503962
+ await storage2.storeSenderKey(senderName, new SenderKeyRecord2);
503426
503963
  }
503427
- const skdm = await new GroupSessionBuilder2(storage).create(senderName);
503964
+ const skdm = await new GroupSessionBuilder2(storage2).create(senderName);
503428
503965
  return { senderName, skdm };
503429
503966
  };
503430
503967
  const repository = {
503431
503968
  decryptGroupMessage({ group, authorJid, msg }) {
503432
503969
  const senderName = jidToSignalSenderKeyName(group, authorJid);
503433
- const cipher = new GroupCipher2(storage, senderName);
503970
+ const cipher = new GroupCipher2(storage2, senderName);
503434
503971
  return parsedKeys.transaction(async () => {
503435
503972
  return cipher.decrypt(msg);
503436
503973
  }, group);
503437
503974
  },
503438
503975
  async processSenderKeyDistributionMessage({ item, authorJid }) {
503439
- const builder = new GroupSessionBuilder2(storage);
503976
+ const builder = new GroupSessionBuilder2(storage2);
503440
503977
  if (!item.groupId) {
503441
503978
  throw new Error("Group ID is required for sender key distribution message");
503442
503979
  }
@@ -503445,24 +503982,24 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503445
503982
  const senderNameStr = senderName.toString();
503446
503983
  const { [senderNameStr]: senderKey } = await auth.keys.get("sender-key", [senderNameStr]);
503447
503984
  if (!senderKey) {
503448
- await storage.storeSenderKey(senderName, new SenderKeyRecord2);
503985
+ await storage2.storeSenderKey(senderName, new SenderKeyRecord2);
503449
503986
  }
503450
503987
  return parsedKeys.transaction(async () => {
503451
503988
  const { [senderNameStr]: senderKey2 } = await auth.keys.get("sender-key", [senderNameStr]);
503452
503989
  if (!senderKey2) {
503453
- await storage.storeSenderKey(senderName, new SenderKeyRecord2);
503990
+ await storage2.storeSenderKey(senderName, new SenderKeyRecord2);
503454
503991
  }
503455
503992
  await builder.process(senderName, senderMsg);
503456
503993
  }, item.groupId);
503457
503994
  },
503458
503995
  async decryptMessage({ jid, type, ciphertext }) {
503459
503996
  const addr = jidToSignalProtocolAddress(jid);
503460
- const session = new libsignal.SessionCipher(storage, addr);
503997
+ const session = new libsignal.SessionCipher(storage2, addr);
503461
503998
  if (type === "pkmsg") {
503462
503999
  const identityKey = extractIdentityFromPkmsg(ciphertext);
503463
504000
  if (identityKey) {
503464
504001
  const addrStr = addr.toString();
503465
- const identityChanged = await storage.saveIdentity(addrStr, identityKey);
504002
+ const identityChanged = await storage2.saveIdentity(addrStr, identityKey);
503466
504003
  if (identityChanged) {
503467
504004
  logger5.info({ jid, addr: addrStr }, "identity key changed or new contact, session will be re-established");
503468
504005
  }
@@ -503486,7 +504023,7 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503486
504023
  },
503487
504024
  async encryptMessage({ jid, data }) {
503488
504025
  const addr = jidToSignalProtocolAddress(jid);
503489
- const cipher = new libsignal.SessionCipher(storage, addr);
504026
+ const cipher = new libsignal.SessionCipher(storage2, addr);
503490
504027
  return parsedKeys.transaction(async () => {
503491
504028
  const { type: sigType, body } = await cipher.encrypt(data);
503492
504029
  const type = sigType === 3 ? "pkmsg" : "msg";
@@ -503496,7 +504033,7 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503496
504033
  async encryptGroupMessage({ group, meId, data }) {
503497
504034
  return parsedKeys.transaction(async () => {
503498
504035
  const { senderName, skdm } = await ensureSenderKeyAndCreateSkdm(group, meId);
503499
- const ciphertext = await new GroupCipher2(storage, senderName).encrypt(data);
504036
+ const ciphertext = await new GroupCipher2(storage2, senderName).encrypt(data);
503500
504037
  return { ciphertext, senderKeyDistributionMessage: skdm.serialize() };
503501
504038
  }, group);
503502
504039
  },
@@ -503513,7 +504050,7 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503513
504050
  },
503514
504051
  async getSessionInfo(jid) {
503515
504052
  const addr = jidToSignalProtocolAddress(jid).toString();
503516
- const session = await storage.loadSession(addr);
504053
+ const session = await storage2.loadSession(addr);
503517
504054
  if (!session) {
503518
504055
  return null;
503519
504056
  }
@@ -503527,7 +504064,7 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503527
504064
  },
503528
504065
  async injectE2ESession({ jid, session }) {
503529
504066
  logger5.trace({ jid }, "injecting E2EE session");
503530
- const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
504067
+ const cipher = new libsignal.SessionBuilder(storage2, jidToSignalProtocolAddress(jid));
503531
504068
  return parsedKeys.transaction(async () => {
503532
504069
  await cipher.initOutgoing(session);
503533
504070
  }, jid);
@@ -503539,7 +504076,7 @@ function makeLibSignalRepository(auth, logger5, pnToLIDFunc) {
503539
504076
  async validateSession(jid) {
503540
504077
  try {
503541
504078
  const addr = jidToSignalProtocolAddress(jid);
503542
- const session = await storage.loadSession(addr.toString());
504079
+ const session = await storage2.loadSession(addr.toString());
503543
504080
  if (!session) {
503544
504081
  return { exists: false, reason: "no session" };
503545
504082
  }
@@ -511533,11 +512070,11 @@ function deserializeSignalData(type, data) {
511533
512070
  }
511534
512071
  return data;
511535
512072
  }
511536
- async function createStorageAuthState(storage, instanceId) {
512073
+ async function createStorageAuthState(storage2, instanceId) {
511537
512074
  const credsKey = `auth:${instanceId}:creds`;
511538
512075
  const keyPrefix = `auth:${instanceId}:keys`;
511539
512076
  let creds;
511540
- const existingCreds = await storage.get(credsKey);
512077
+ const existingCreds = await storage2.get(credsKey);
511541
512078
  if (existingCreds) {
511542
512079
  if (typeof existingCreds === "string") {
511543
512080
  creds = deserialize(existingCreds);
@@ -511607,10 +512144,10 @@ async function createStorageAuthState(storage, instanceId) {
511607
512144
  const previousPersist = persistQueues.get(key) ?? Promise.resolve();
511608
512145
  const nextPersist = previousPersist.catch(() => {}).then(async () => {
511609
512146
  if (value !== null && value !== undefined) {
511610
- await storage.set(key, serialize(value));
512147
+ await storage2.set(key, serialize(value));
511611
512148
  return;
511612
512149
  }
511613
- await storage.delete(key);
512150
+ await storage2.delete(key);
511614
512151
  }).catch((err2) => {
511615
512152
  if (value !== null && value !== undefined) {
511616
512153
  log50.error("Background key persist failed", { type, id: id.slice(-40), instanceId, err: String(err2) });
@@ -511639,7 +512176,7 @@ async function createStorageAuthState(storage, instanceId) {
511639
512176
  data[id] = deserializeSignalData(type, cached);
511640
512177
  continue;
511641
512178
  }
511642
- const value = await storage.get(key);
512179
+ const value = await storage2.get(key);
511643
512180
  if (value !== null && value !== undefined) {
511644
512181
  const parsed = parseStorageValue(value);
511645
512182
  setCachedValue(key, parsed);
@@ -511661,19 +512198,19 @@ async function createStorageAuthState(storage, instanceId) {
511661
512198
  }
511662
512199
  },
511663
512200
  saveCreds: async () => {
511664
- await storage.set(credsKey, serialize(creds));
512201
+ await storage2.set(credsKey, serialize(creds));
511665
512202
  }
511666
512203
  };
511667
512204
  }
511668
- async function clearAuthState(storage, instanceId) {
512205
+ async function clearAuthState(storage2, instanceId) {
511669
512206
  const credsKey = `auth:${instanceId}:creds`;
511670
512207
  const keyPrefix = `auth:${instanceId}:keys`;
511671
- await storage.delete(credsKey);
511672
- const keys = await storage.keys(`${keyPrefix}:*`);
512208
+ await storage2.delete(credsKey);
512209
+ const keys = await storage2.keys(`${keyPrefix}:*`);
511673
512210
  const batchSize = 50;
511674
512211
  for (let i = 0;i < keys.length; i += batchSize) {
511675
512212
  const batch = keys.slice(i, i + batchSize);
511676
- await Promise.all(batch.map((key) => storage.delete(key)));
512213
+ await Promise.all(batch.map((key) => storage2.delete(key)));
511677
512214
  }
511678
512215
  }
511679
512216