@automagik/omni 2.260911.2 → 2.260911.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.
@@ -38426,7 +38426,7 @@ var init_debounce = __esm(() => {
38426
38426
  class AutomationEngine {
38427
38427
  config;
38428
38428
  subscriptions = new Map;
38429
- instanceQueues = new Map;
38429
+ queues = new Map;
38430
38430
  debounceManagers = new Map;
38431
38431
  automations = [];
38432
38432
  eventBus = null;
@@ -38751,29 +38751,38 @@ class AutomationEngine {
38751
38751
  const manager = new DebounceManager(automation.debounce, callback);
38752
38752
  this.debounceManagers.set(automation.id, manager);
38753
38753
  }
38754
+ resolveQueueKey(automation, context2, instanceId) {
38755
+ if (automation.maxConcurrency == null && automation.concurrencyKey == null)
38756
+ return instanceId;
38757
+ const base = `${instanceId}:${automation.id}`;
38758
+ if (!automation.concurrencyKey)
38759
+ return base;
38760
+ const partition = substituteTemplate(automation.concurrencyKey, context2).trim();
38761
+ return partition ? `${base}:${partition}` : base;
38762
+ }
38754
38763
  async queueExecution(automation, event, context2, instanceId) {
38755
- let queue = this.instanceQueues.get(instanceId);
38756
- if (!queue) {
38757
- const maxConcurrency = this.config.instanceConcurrencyOverrides?.[instanceId] ?? this.config.defaultConcurrency;
38758
- queue = {
38759
- instanceId,
38760
- activeCount: 0,
38761
- maxConcurrency,
38762
- pending: []
38763
- };
38764
- this.instanceQueues.set(instanceId, queue);
38765
- }
38764
+ const key = this.resolveQueueKey(automation, context2, instanceId);
38765
+ const maxConcurrency = automation.maxConcurrency ?? this.config.instanceConcurrencyOverrides?.[instanceId] ?? this.config.defaultConcurrency;
38766
+ const queue = this.queues.get(key) ?? {
38767
+ key,
38768
+ evictWhenIdle: key !== instanceId,
38769
+ activeCount: 0,
38770
+ maxConcurrency,
38771
+ pending: []
38772
+ };
38773
+ queue.maxConcurrency = maxConcurrency;
38774
+ this.queues.set(key, queue);
38766
38775
  if (queue.activeCount < queue.maxConcurrency) {
38767
38776
  return this.executeAutomation(automation, event, context2, queue);
38768
38777
  }
38769
38778
  const maxQueueDepth = this.config.maxQueueDepth ?? 100;
38770
38779
  if (queue.pending.length >= maxQueueDepth) {
38771
38780
  logger4.warn("Queue full, applying backpressure", {
38772
- instanceId,
38781
+ queueKey: key,
38773
38782
  queueDepth: queue.pending.length,
38774
38783
  maxDepth: maxQueueDepth
38775
38784
  });
38776
- throw new QueueFullError(instanceId, queue.pending.length, maxQueueDepth);
38785
+ throw new QueueFullError(key, queue.pending.length, maxQueueDepth);
38777
38786
  }
38778
38787
  const queueRef = queue;
38779
38788
  return new Promise((resolve) => {
@@ -38785,7 +38794,7 @@ class AutomationEngine {
38785
38794
  });
38786
38795
  logger4.debug("Execution queued", {
38787
38796
  automationId: automation.id,
38788
- instanceId,
38797
+ queueKey: key,
38789
38798
  queueLength: queueRef.pending.length
38790
38799
  });
38791
38800
  });
@@ -38892,6 +38901,10 @@ class AutomationEngine {
38892
38901
  next.resolve(result);
38893
38902
  }
38894
38903
  }
38904
+ if (queue.evictWhenIdle && queue.activeCount === 0 && queue.pending.length === 0) {
38905
+ if (this.queues.get(queue.key) === queue)
38906
+ this.queues.delete(queue.key);
38907
+ }
38895
38908
  }
38896
38909
  }
38897
38910
  async logExecution(result, trustedTenantId = null) {
@@ -38917,8 +38930,8 @@ class AutomationEngine {
38917
38930
  });
38918
38931
  }
38919
38932
  getMetrics() {
38920
- const instanceQueues = Array.from(this.instanceQueues.values()).map((q) => ({
38921
- instanceId: q.instanceId,
38933
+ const instanceQueues = Array.from(this.queues.values()).map((q) => ({
38934
+ instanceId: q.key,
38922
38935
  activeCount: q.activeCount,
38923
38936
  pendingCount: q.pending.length
38924
38937
  }));
@@ -38961,12 +38974,12 @@ var init_engine = __esm(() => {
38961
38974
  init_templates();
38962
38975
  logger4 = createLogger("automations:engine");
38963
38976
  QueueFullError = class QueueFullError extends Error {
38964
- instanceId;
38977
+ queueKey;
38965
38978
  queueDepth;
38966
38979
  maxDepth;
38967
- constructor(instanceId, queueDepth, maxDepth) {
38968
- super(`Queue full for instance ${instanceId}: ${queueDepth}/${maxDepth} pending`);
38969
- this.instanceId = instanceId;
38980
+ constructor(queueKey, queueDepth, maxDepth) {
38981
+ super(`Queue full for ${queueKey}: ${queueDepth}/${maxDepth} pending`);
38982
+ this.queueKey = queueKey;
38970
38983
  this.queueDepth = queueDepth;
38971
38984
  this.maxDepth = maxDepth;
38972
38985
  this.name = "QueueFullError";
@@ -76985,7 +76998,7 @@ var require_ClientVoiceManager = __commonJS((exports, module) => {
76985
76998
 
76986
76999
  // ../../node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist/index.js
76987
77000
  var require_dist9 = __commonJS((exports, module) => {
76988
- var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist";
77001
+ var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist";
76989
77002
  var __create2 = Object.create;
76990
77003
  var __defProp2 = Object.defineProperty;
76991
77004
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -162265,7 +162278,7 @@ var require_indexes = __commonJS((exports, module) => {
162265
162278
 
162266
162279
  // ../../node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream/index.js
162267
162280
  var require_thread_stream = __commonJS((exports, module) => {
162268
- var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream";
162281
+ var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream";
162269
162282
  var { version } = require_package5();
162270
162283
  var { EventEmitter: EventEmitter3 } = __require("events");
162271
162284
  var { Worker } = __require("worker_threads");
@@ -162686,7 +162699,7 @@ var require_thread_stream = __commonJS((exports, module) => {
162686
162699
 
162687
162700
  // ../../node_modules/.bun/pino@9.14.0/node_modules/pino/lib/transport.js
162688
162701
  var require_transport2 = __commonJS((exports, module) => {
162689
- var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/pino@9.14.0/node_modules/pino/lib";
162702
+ var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/pino@9.14.0/node_modules/pino/lib";
162690
162703
  var { createRequire: createRequire2 } = __require("module");
162691
162704
  var getCallers = require_caller();
162692
162705
  var { join: join8, isAbsolute, sep: sep2 } = __require("path");
@@ -174411,6 +174424,8 @@ var init_schema2 = __esm(() => {
174411
174424
  enabled: boolean2("enabled").notNull().default(true),
174412
174425
  priority: integer("priority").notNull().default(0),
174413
174426
  transactionalEmissions: boolean2("transactional_emissions").notNull().default(false),
174427
+ maxConcurrency: integer("max_concurrency"),
174428
+ concurrencyKey: text("concurrency_key"),
174414
174429
  managedByAgentId: uuid("managed_by_agent_id").references(() => agents.id, { onDelete: "cascade" }),
174415
174430
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
174416
174431
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -244431,7 +244446,7 @@ var require_client3 = __commonJS((exports) => {
244431
244446
 
244432
244447
  // ../../node_modules/.bun/@sentry+node-core@10.52.0+2c50d7e904f6cfd7/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js
244433
244448
  var require_esmLoader = __commonJS((exports) => {
244434
- var __filename = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/@sentry+node-core@10.52.0+2c50d7e904f6cfd7/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js";
244449
+ var __filename = "/home/runner/work/omni/omni/node_modules/.bun/@sentry+node-core@10.52.0+2c50d7e904f6cfd7/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js";
244435
244450
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
244436
244451
  var core3 = require_cjs6();
244437
244452
  var importInTheMiddle = require_import_in_the_middle();
@@ -251657,7 +251672,7 @@ var init_sentry_scrub = __esm(() => {
251657
251672
  var require_package7 = __commonJS((exports, module) => {
251658
251673
  module.exports = {
251659
251674
  name: "@omni/api",
251660
- version: "2.260911.2",
251675
+ version: "2.260911.4",
251661
251676
  private: true,
251662
251677
  type: "module",
251663
251678
  exports: {
@@ -278759,7 +278774,7 @@ var require_src45 = __commonJS((exports) => {
278759
278774
 
278760
278775
  // ../../node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src/channelz.js
278761
278776
  var require_channelz = __commonJS((exports) => {
278762
- var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
278777
+ var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
278763
278778
  Object.defineProperty(exports, "__esModule", { value: true });
278764
278779
  exports.registerChannelzSocket = exports.registerChannelzServer = exports.registerChannelzSubchannel = exports.registerChannelzChannel = exports.ChannelzCallTrackerStub = exports.ChannelzCallTracker = exports.ChannelzChildrenTrackerStub = exports.ChannelzChildrenTracker = exports.ChannelzTrace = exports.ChannelzTraceStub = undefined;
278765
278780
  exports.unregisterChannelzRef = unregisterChannelzRef;
@@ -284162,7 +284177,7 @@ var require_duration = __commonJS((exports) => {
284162
284177
 
284163
284178
  // ../../node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src/orca.js
284164
284179
  var require_orca = __commonJS((exports) => {
284165
- var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
284180
+ var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
284166
284181
  Object.defineProperty(exports, "__esModule", { value: true });
284167
284182
  exports.OrcaOobMetricsSubchannelWrapper = exports.GRPC_METRICS_HEADER = exports.ServerMetricRecorder = exports.PerRequestMetricRecorder = undefined;
284168
284183
  exports.createOrcaClient = createOrcaClient;
@@ -375841,6 +375856,9 @@ var init_ingress_idempotency = __esm(() => {
375841
375856
 
375842
375857
  // ../api/src/services/webhooks.ts
375843
375858
  import { createHmac as createHmac4, timingSafeEqual } from "crypto";
375859
+ function scopeTriggerKey(key, instanceId, tenantId) {
375860
+ return `manual:${instanceId ?? tenantId ?? "global"}:${key}`;
375861
+ }
375844
375862
  function timingSafeEqualStrings(a, b3) {
375845
375863
  const bufA = Buffer.from(a);
375846
375864
  const bufB = Buffer.from(b3);
@@ -376011,7 +376029,7 @@ class WebhookService {
376011
376029
  payload,
376012
376030
  headers
376013
376031
  });
376014
- const claimed = await this.db.insert(omniEvents).values({
376032
+ const claim = await this.claimJournalRow({
376015
376033
  id: eventId,
376016
376034
  channel: "internal",
376017
376035
  eventType,
@@ -376021,18 +376039,17 @@ class WebhookService {
376021
376039
  idempotencyKey,
376022
376040
  receivedAt: new Date,
376023
376041
  metadata: { correlationId: eventId, source: "webhook", fullEventType: eventType, webhookSource: sourceName }
376024
- }).onConflictDoNothing({ target: omniEvents.idempotencyKey }).returning({ id: omniEvents.id });
376025
- if (claimed.length === 0) {
376042
+ });
376043
+ if (claim.duplicate) {
376026
376044
  await this.db.update(webhookSources).set({
376027
376045
  totalDuplicates: sql`${webhookSources.totalDuplicates} + 1`,
376028
376046
  updatedAt: new Date
376029
376047
  }).where(eq(webhookSources.id, source.id));
376030
- const [original] = await this.db.select({ id: omniEvents.id }).from(omniEvents).where(eq(omniEvents.idempotencyKey, idempotencyKey)).limit(1);
376031
376048
  log114.info("Webhook redelivery acked without a second event", { sourceName, idempotencyKey });
376032
376049
  return {
376033
376050
  received: true,
376034
376051
  duplicate: true,
376035
- eventId: original?.id ?? eventId,
376052
+ eventId: claim.eventId,
376036
376053
  source: sourceName,
376037
376054
  eventType
376038
376055
  };
@@ -376067,6 +376084,14 @@ class WebhookService {
376067
376084
  eventType
376068
376085
  };
376069
376086
  }
376087
+ async claimJournalRow(row) {
376088
+ const claimed = await this.db.insert(omniEvents).values(row).onConflictDoNothing({ target: omniEvents.idempotencyKey }).returning({ id: omniEvents.id });
376089
+ if (claimed.length > 0) {
376090
+ return { eventId: row.id, duplicate: false };
376091
+ }
376092
+ const [original] = await this.db.select({ id: omniEvents.id }).from(omniEvents).where(eq(omniEvents.idempotencyKey, row.idempotencyKey)).limit(1);
376093
+ return { eventId: original?.id ?? row.id, duplicate: true };
376094
+ }
376070
376095
  verifySignature(source, rawBody, headers) {
376071
376096
  const config4 = source.signatureConfig;
376072
376097
  if (!config4)
@@ -376130,16 +376155,66 @@ class WebhookService {
376130
376155
  async trigger(eventType, payload, metadata) {
376131
376156
  const provisionalId = metadata?.correlationId ?? generateId();
376132
376157
  await this.enforceRegisteredSchema(eventType, payload, provisionalId, "manual trigger");
376133
- if (this.eventBus) {
376134
- const result = await this.eventBus.publishGeneric(eventType, payload, {
376135
- correlationId: metadata?.correlationId,
376136
- causationId: metadata?.causationId,
376137
- instanceId: metadata?.instanceId,
376158
+ const bus2 = this.eventBus;
376159
+ if (!bus2) {
376160
+ return { eventId: provisionalId, published: false };
376161
+ }
376162
+ const key = metadata?.idempotencyKey;
376163
+ if (key) {
376164
+ return this.triggerClaimed(bus2, eventType, payload, metadata ?? {}, key);
376165
+ }
376166
+ const result = await bus2.publishGeneric(eventType, payload, {
376167
+ correlationId: metadata?.correlationId,
376168
+ causationId: metadata?.causationId,
376169
+ instanceId: metadata?.instanceId,
376170
+ source: "manual-trigger"
376171
+ });
376172
+ return { eventId: result.id, published: true };
376173
+ }
376174
+ async triggerClaimed(bus2, eventType, payload, metadata, key) {
376175
+ const idempotencyKey = scopeTriggerKey(key, metadata.instanceId, this.tenantId);
376176
+ const eventId = generateId();
376177
+ const claim = await this.claimJournalRow({
376178
+ id: eventId,
376179
+ channel: "internal",
376180
+ eventType,
376181
+ direction: "internal",
376182
+ status: "completed",
376183
+ rawPayload: payload,
376184
+ idempotencyKey,
376185
+ causationId: metadata.causationId ?? null,
376186
+ receivedAt: new Date,
376187
+ metadata: {
376188
+ correlationId: metadata.correlationId ?? eventId,
376189
+ source: "manual-trigger",
376190
+ fullEventType: eventType,
376191
+ idempotencyKey
376192
+ }
376193
+ });
376194
+ if (claim.duplicate) {
376195
+ log114.info("Manual trigger deduped: idempotency key already journaled", { eventType, idempotencyKey });
376196
+ return { eventId: claim.eventId, published: false, duplicate: true };
376197
+ }
376198
+ try {
376199
+ await bus2.publishGeneric(eventType, payload, {
376200
+ correlationId: metadata.correlationId,
376201
+ causationId: metadata.causationId,
376202
+ instanceId: metadata.instanceId,
376203
+ publishEventId: eventId,
376138
376204
  source: "manual-trigger"
376139
376205
  });
376140
- return { eventId: result.id, published: true };
376206
+ } catch (error3) {
376207
+ await this.db.delete(omniEvents).where(eq(omniEvents.id, eventId)).catch((releaseError) => {
376208
+ log114.error("Failed to release trigger idempotency claim after publish failure", {
376209
+ eventType,
376210
+ eventId,
376211
+ idempotencyKey,
376212
+ error: String(releaseError)
376213
+ });
376214
+ });
376215
+ throw error3;
376141
376216
  }
376142
- return { eventId: provisionalId, published: false };
376217
+ return { eventId, published: true, duplicate: false };
376143
376218
  }
376144
376219
  async heartbeat(sourceName) {
376145
376220
  const source = await this.getByName(sourceName);
@@ -379382,6 +379457,12 @@ var init_automations3 = __esm(() => {
379382
379457
  transactionalEmissions: exports_external.boolean().openapi({
379383
379458
  description: "Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero"
379384
379459
  }),
379460
+ maxConcurrency: exports_external.number().int().nullable().openapi({
379461
+ description: "Per-automation concurrency limit (#1108). null = queued per instance with the engine default; " + "set = a queue private to this automation, 1 being strict single-flight"
379462
+ }),
379463
+ concurrencyKey: exports_external.string().nullable().openapi({
379464
+ description: "Template over the event payload partitioning this automation\u2019s queue (#1108), e.g. " + '"{{payload.from.id}}" to serialize per chat; null = one queue for the whole automation'
379465
+ }),
379385
379466
  managedByAgentId: exports_external.string().uuid().nullable().openapi({
379386
379467
  description: "Set when this automation was compiled from an agent event manifest (RFC #925 G4b, #986); " + "null = hand-made. Managed automations reject manual mutation \u2014 edit the owning agent\u2019s manifest instead"
379387
379468
  }),
@@ -379400,6 +379481,12 @@ var init_automations3 = __esm(() => {
379400
379481
  priority: exports_external.number().int().default(0).openapi({ description: "Priority" }),
379401
379482
  transactionalEmissions: exports_external.boolean().default(false).openapi({
379402
379483
  description: "Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero. Default false = immediate publishing"
379484
+ }),
379485
+ maxConcurrency: exports_external.number().int().min(1).nullable().optional().openapi({
379486
+ description: "Per-automation concurrency limit (#1108). Omit/null = today\u2019s per-instance queueing with the engine " + "default; 1 = strict single-flight, which is what a read-before-write action needs"
379487
+ }),
379488
+ concurrencyKey: exports_external.string().min(1).nullable().optional().openapi({
379489
+ description: "Template over the event payload partitioning this automation\u2019s queue (#1108), e.g. " + '"{{payload.from.id}}" to serialize per chat; omit/null = one queue for the whole automation'
379403
379490
  })
379404
379491
  });
379405
379492
  AutomationLogSchema = exports_external.object({
@@ -379445,7 +379532,9 @@ var init_automations3 = __esm(() => {
379445
379532
  AutomationMetricsSchema = exports_external.object({
379446
379533
  running: exports_external.boolean().openapi({ description: "Engine running" }),
379447
379534
  instanceQueues: exports_external.array(exports_external.object({
379448
- instanceId: exports_external.string().openapi({ description: "Instance ID" }),
379535
+ instanceId: exports_external.string().openapi({
379536
+ description: 'Queue key: the instance ID, or "<instanceId>:<automationId>[:<partition>]" for an automation ' + "running on its own queue (#1108)"
379537
+ }),
379449
379538
  activeCount: exports_external.number().int().openapi({ description: "Active jobs" }),
379450
379539
  pendingCount: exports_external.number().int().openapi({ description: "Pending jobs" })
379451
379540
  })).optional().openapi({ description: "Instance queue stats" }),
@@ -383516,7 +383605,10 @@ var init_webhooks2 = __esm(() => {
383516
383605
  payload: exports_external.record(exports_external.string(), exports_external.unknown()).openapi({ description: "Event payload" }),
383517
383606
  correlationId: exports_external.string().optional().openapi({ description: "Correlation ID" }),
383518
383607
  causationId: exports_external.string().uuid().optional().openapi({ description: "Parent event ID; stamps causationId so the emission is parented in the causality tree" }),
383519
- instanceId: exports_external.string().uuid().optional().openapi({ description: "Instance ID for context" })
383608
+ instanceId: exports_external.string().uuid().optional().openapi({ description: "Instance ID for context" }),
383609
+ idempotencyKey: exports_external.string().min(1).max(255).optional().openapi({
383610
+ description: "Producer-supplied ingress key (#1109). Unique per instance (else per tenant), not global. A key already journaled publishes nothing and returns the ORIGINAL event id with duplicate: true. Omit for undeduped publishing."
383611
+ })
383520
383612
  });
383521
383613
  WebhookReceiveResponseSchema = exports_external.object({
383522
383614
  eventId: exports_external.string().uuid().openapi({ description: "Created event ID (the ORIGINAL event on a duplicate)" }),
@@ -385197,7 +385289,9 @@ var init_automations4 = __esm(() => {
385197
385289
  debounce: debounceSchema.optional().describe("Message debounce configuration"),
385198
385290
  enabled: exports_external.boolean().default(true).describe("Whether automation is enabled"),
385199
385291
  priority: exports_external.number().int().default(0).describe("Priority (higher runs first)"),
385200
- transactionalEmissions: exports_external.boolean().default(false).describe("Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero. Default false = immediate publishing")
385292
+ transactionalEmissions: exports_external.boolean().default(false).describe("Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero. Default false = immediate publishing"),
385293
+ maxConcurrency: exports_external.number().int().min(1).nullable().optional().describe("Per-automation concurrency limit (#1108). Omit/null = today\u2019s per-instance queueing with the engine " + "default; 1 = strict single-flight, which is what a read-before-write action needs"),
385294
+ concurrencyKey: exports_external.string().min(1).nullable().optional().describe("Template over the event payload partitioning this automation\u2019s queue (#1108), e.g. " + '"{{payload.from.id}}" to serialize per chat; omit/null = one queue for the whole automation')
385201
385295
  });
385202
385296
  updateAutomationSchema = createAutomationSchema.partial();
385203
385297
  listQuerySchema5 = exports_external.object({
@@ -396325,10 +396419,11 @@ var init_webhooks3 = __esm(() => {
396325
396419
  payload: exports_external.record(exports_external.string(), exports_external.unknown()).describe("Event payload"),
396326
396420
  correlationId: exports_external.string().optional().describe("Optional correlation ID"),
396327
396421
  causationId: exports_external.string().uuid().optional().describe("Optional parent event ID (causality tree, #1072)"),
396328
- instanceId: exports_external.string().uuid().optional().describe("Optional instance ID for context")
396422
+ instanceId: exports_external.string().uuid().optional().describe("Optional instance ID for context"),
396423
+ idempotencyKey: exports_external.string().min(1).max(255).optional().describe("Optional producer-supplied ingress key; a key already journaled returns the original event (#1109)")
396329
396424
  });
396330
396425
  webhooksRoutes.post("/events/trigger", zValidator("json", triggerEventSchema), async (c) => {
396331
- const { eventType, payload, correlationId, causationId, instanceId } = c.req.valid("json");
396426
+ const { eventType, payload, correlationId, causationId, instanceId, idempotencyKey } = c.req.valid("json");
396332
396427
  const services = c.get("services");
396333
396428
  const apiKey = c.get("apiKey");
396334
396429
  if (instanceId && apiKey && !ApiKeyService.instanceAllowed(apiKey.instanceIds, instanceId)) {
@@ -396337,7 +396432,8 @@ var init_webhooks3 = __esm(() => {
396337
396432
  const result = await services.webhooks.trigger(eventType, payload, {
396338
396433
  correlationId,
396339
396434
  causationId,
396340
- instanceId
396435
+ instanceId,
396436
+ idempotencyKey
396341
396437
  });
396342
396438
  return c.json(result, 201);
396343
396439
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260911.2",
3
+ "version": "2.260911.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/automagik-dev/omni.git",