@automagik/omni 2.260911.3 → 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.
@@ -251672,7 +251672,7 @@ var init_sentry_scrub = __esm(() => {
251672
251672
  var require_package7 = __commonJS((exports, module) => {
251673
251673
  module.exports = {
251674
251674
  name: "@omni/api",
251675
- version: "2.260911.3",
251675
+ version: "2.260911.4",
251676
251676
  private: true,
251677
251677
  type: "module",
251678
251678
  exports: {
@@ -375856,6 +375856,9 @@ var init_ingress_idempotency = __esm(() => {
375856
375856
 
375857
375857
  // ../api/src/services/webhooks.ts
375858
375858
  import { createHmac as createHmac4, timingSafeEqual } from "crypto";
375859
+ function scopeTriggerKey(key, instanceId, tenantId) {
375860
+ return `manual:${instanceId ?? tenantId ?? "global"}:${key}`;
375861
+ }
375859
375862
  function timingSafeEqualStrings(a, b3) {
375860
375863
  const bufA = Buffer.from(a);
375861
375864
  const bufB = Buffer.from(b3);
@@ -376026,7 +376029,7 @@ class WebhookService {
376026
376029
  payload,
376027
376030
  headers
376028
376031
  });
376029
- const claimed = await this.db.insert(omniEvents).values({
376032
+ const claim = await this.claimJournalRow({
376030
376033
  id: eventId,
376031
376034
  channel: "internal",
376032
376035
  eventType,
@@ -376036,18 +376039,17 @@ class WebhookService {
376036
376039
  idempotencyKey,
376037
376040
  receivedAt: new Date,
376038
376041
  metadata: { correlationId: eventId, source: "webhook", fullEventType: eventType, webhookSource: sourceName }
376039
- }).onConflictDoNothing({ target: omniEvents.idempotencyKey }).returning({ id: omniEvents.id });
376040
- if (claimed.length === 0) {
376042
+ });
376043
+ if (claim.duplicate) {
376041
376044
  await this.db.update(webhookSources).set({
376042
376045
  totalDuplicates: sql`${webhookSources.totalDuplicates} + 1`,
376043
376046
  updatedAt: new Date
376044
376047
  }).where(eq(webhookSources.id, source.id));
376045
- const [original] = await this.db.select({ id: omniEvents.id }).from(omniEvents).where(eq(omniEvents.idempotencyKey, idempotencyKey)).limit(1);
376046
376048
  log114.info("Webhook redelivery acked without a second event", { sourceName, idempotencyKey });
376047
376049
  return {
376048
376050
  received: true,
376049
376051
  duplicate: true,
376050
- eventId: original?.id ?? eventId,
376052
+ eventId: claim.eventId,
376051
376053
  source: sourceName,
376052
376054
  eventType
376053
376055
  };
@@ -376082,6 +376084,14 @@ class WebhookService {
376082
376084
  eventType
376083
376085
  };
376084
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
+ }
376085
376095
  verifySignature(source, rawBody, headers) {
376086
376096
  const config4 = source.signatureConfig;
376087
376097
  if (!config4)
@@ -376145,16 +376155,66 @@ class WebhookService {
376145
376155
  async trigger(eventType, payload, metadata) {
376146
376156
  const provisionalId = metadata?.correlationId ?? generateId();
376147
376157
  await this.enforceRegisteredSchema(eventType, payload, provisionalId, "manual trigger");
376148
- if (this.eventBus) {
376149
- const result = await this.eventBus.publishGeneric(eventType, payload, {
376150
- correlationId: metadata?.correlationId,
376151
- causationId: metadata?.causationId,
376152
- 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,
376153
376204
  source: "manual-trigger"
376154
376205
  });
376155
- 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;
376156
376216
  }
376157
- return { eventId: provisionalId, published: false };
376217
+ return { eventId, published: true, duplicate: false };
376158
376218
  }
376159
376219
  async heartbeat(sourceName) {
376160
376220
  const source = await this.getByName(sourceName);
@@ -383545,7 +383605,10 @@ var init_webhooks2 = __esm(() => {
383545
383605
  payload: exports_external.record(exports_external.string(), exports_external.unknown()).openapi({ description: "Event payload" }),
383546
383606
  correlationId: exports_external.string().optional().openapi({ description: "Correlation ID" }),
383547
383607
  causationId: exports_external.string().uuid().optional().openapi({ description: "Parent event ID; stamps causationId so the emission is parented in the causality tree" }),
383548
- 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
+ })
383549
383612
  });
383550
383613
  WebhookReceiveResponseSchema = exports_external.object({
383551
383614
  eventId: exports_external.string().uuid().openapi({ description: "Created event ID (the ORIGINAL event on a duplicate)" }),
@@ -396356,10 +396419,11 @@ var init_webhooks3 = __esm(() => {
396356
396419
  payload: exports_external.record(exports_external.string(), exports_external.unknown()).describe("Event payload"),
396357
396420
  correlationId: exports_external.string().optional().describe("Optional correlation ID"),
396358
396421
  causationId: exports_external.string().uuid().optional().describe("Optional parent event ID (causality tree, #1072)"),
396359
- 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)")
396360
396424
  });
396361
396425
  webhooksRoutes.post("/events/trigger", zValidator("json", triggerEventSchema), async (c) => {
396362
- const { eventType, payload, correlationId, causationId, instanceId } = c.req.valid("json");
396426
+ const { eventType, payload, correlationId, causationId, instanceId, idempotencyKey } = c.req.valid("json");
396363
396427
  const services = c.get("services");
396364
396428
  const apiKey = c.get("apiKey");
396365
396429
  if (instanceId && apiKey && !ApiKeyService.instanceAllowed(apiKey.instanceIds, instanceId)) {
@@ -396368,7 +396432,8 @@ var init_webhooks3 = __esm(() => {
396368
396432
  const result = await services.webhooks.trigger(eventType, payload, {
396369
396433
  correlationId,
396370
396434
  causationId,
396371
- instanceId
396435
+ instanceId,
396436
+ idempotencyKey
396372
396437
  });
396373
396438
  return c.json(result, 201);
396374
396439
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260911.3",
3
+ "version": "2.260911.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/automagik-dev/omni.git",