@open-mercato/webhooks 0.6.6-develop.6465.1.019f0fb26f → 0.6.6-develop.6472.1.1673e7e66b

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.
@@ -1,4 +1,6 @@
1
1
  import { createModuleQueue } from "@open-mercato/queue";
2
+ import { createLogger } from "@open-mercato/shared/lib/logger";
3
+ const logger = createLogger("webhooks");
2
4
  const queues = /* @__PURE__ */ new Map();
3
5
  const LOCAL_WORKER_PROMISE_KEY = "__openMercatoWebhookLocalWorkerPromise__";
4
6
  const WEBHOOK_DELIVERIES_QUEUE = "webhook-deliveries";
@@ -30,7 +32,7 @@ async function ensureLocalWebhookQueueWorkerStarted() {
30
32
  });
31
33
  })().catch((error) => {
32
34
  delete globalStore[LOCAL_WORKER_PROMISE_KEY];
33
- console.error("[webhooks] Failed to start local delivery worker:", error);
35
+ logger.error("Failed to start local delivery worker", { err: error });
34
36
  throw error;
35
37
  });
36
38
  await globalStore[LOCAL_WORKER_PROMISE_KEY];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/webhooks/lib/queue.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createModuleQueue, type Queue } from '@open-mercato/queue'\nimport type { WebhookDeliveryJob } from './delivery'\n\nconst queues = new Map<string, Queue<WebhookDeliveryJob>>()\nconst LOCAL_WORKER_PROMISE_KEY = '__openMercatoWebhookLocalWorkerPromise__'\n\nexport const WEBHOOK_DELIVERIES_QUEUE = 'webhook-deliveries'\n\nexport function getWebhookQueue(queueName: string = WEBHOOK_DELIVERIES_QUEUE): Queue<WebhookDeliveryJob> {\n const existing = queues.get(queueName)\n if (existing) return existing\n\n const concurrency = Math.max(1, Number.parseInt(process.env.WEBHOOK_QUEUE_CONCURRENCY ?? '10', 10) || 10)\n const created = createModuleQueue<WebhookDeliveryJob>(queueName, { concurrency })\n\n queues.set(queueName, created)\n return created\n}\n\nasync function ensureLocalWebhookQueueWorkerStarted(): Promise<void> {\n if (process.env.QUEUE_STRATEGY === 'async') return\n\n const globalStore = globalThis as typeof globalThis & {\n [LOCAL_WORKER_PROMISE_KEY]?: Promise<void>\n }\n\n if (globalStore[LOCAL_WORKER_PROMISE_KEY]) {\n await globalStore[LOCAL_WORKER_PROMISE_KEY]\n return\n }\n\n globalStore[LOCAL_WORKER_PROMISE_KEY] = (async () => {\n const queue = getWebhookQueue()\n\n await queue.process(async (job) => {\n const [{ createRequestContainer }, { processWebhookDeliveryJob }] = await Promise.all([\n import('@open-mercato/shared/lib/di/container'),\n import('./delivery'),\n ])\n\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await processWebhookDeliveryJob(em, job.payload)\n })\n })().catch((error) => {\n delete globalStore[LOCAL_WORKER_PROMISE_KEY]\n console.error('[webhooks] Failed to start local delivery worker:', error)\n throw error\n })\n\n await globalStore[LOCAL_WORKER_PROMISE_KEY]\n}\n\nexport async function enqueueWebhookDelivery(job: WebhookDeliveryJob, delayMs?: number): Promise<string> {\n const queue = getWebhookQueue()\n const jobId = await queue.enqueue(job, delayMs && delayMs > 0 ? { delayMs } : undefined)\n await ensureLocalWebhookQueueWorkerStarted()\n return jobId\n}\n"],
5
- "mappings": "AACA,SAAS,yBAAqC;AAG9C,MAAM,SAAS,oBAAI,IAAuC;AAC1D,MAAM,2BAA2B;AAE1B,MAAM,2BAA2B;AAEjC,SAAS,gBAAgB,YAAoB,0BAAqD;AACvG,QAAM,WAAW,OAAO,IAAI,SAAS;AACrC,MAAI,SAAU,QAAO;AAErB,QAAM,cAAc,KAAK,IAAI,GAAG,OAAO,SAAS,QAAQ,IAAI,6BAA6B,MAAM,EAAE,KAAK,EAAE;AACxG,QAAM,UAAU,kBAAsC,WAAW,EAAE,YAAY,CAAC;AAEhF,SAAO,IAAI,WAAW,OAAO;AAC7B,SAAO;AACT;AAEA,eAAe,uCAAsD;AACnE,MAAI,QAAQ,IAAI,mBAAmB,QAAS;AAE5C,QAAM,cAAc;AAIpB,MAAI,YAAY,wBAAwB,GAAG;AACzC,UAAM,YAAY,wBAAwB;AAC1C;AAAA,EACF;AAEA,cAAY,wBAAwB,KAAK,YAAY;AACnD,UAAM,QAAQ,gBAAgB;AAE9B,UAAM,MAAM,QAAQ,OAAO,QAAQ;AACjC,YAAM,CAAC,EAAE,uBAAuB,GAAG,EAAE,0BAA0B,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpF,OAAO,uCAAuC;AAAA,QAC9C,OAAO,YAAY;AAAA,MACrB,CAAC;AAED,YAAM,YAAY,MAAM,uBAAuB;AAC/C,YAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,YAAM,0BAA0B,IAAI,IAAI,OAAO;AAAA,IACjD,CAAC;AAAA,EACH,GAAG,EAAE,MAAM,CAAC,UAAU;AACpB,WAAO,YAAY,wBAAwB;AAC3C,YAAQ,MAAM,qDAAqD,KAAK;AACxE,UAAM;AAAA,EACR,CAAC;AAED,QAAM,YAAY,wBAAwB;AAC5C;AAEA,eAAsB,uBAAuB,KAAyB,SAAmC;AACvG,QAAM,QAAQ,gBAAgB;AAC9B,QAAM,QAAQ,MAAM,MAAM,QAAQ,KAAK,WAAW,UAAU,IAAI,EAAE,QAAQ,IAAI,MAAS;AACvF,QAAM,qCAAqC;AAC3C,SAAO;AACT;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createModuleQueue, type Queue } from '@open-mercato/queue'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { WebhookDeliveryJob } from './delivery'\n\nconst logger = createLogger('webhooks')\n\nconst queues = new Map<string, Queue<WebhookDeliveryJob>>()\nconst LOCAL_WORKER_PROMISE_KEY = '__openMercatoWebhookLocalWorkerPromise__'\n\nexport const WEBHOOK_DELIVERIES_QUEUE = 'webhook-deliveries'\n\nexport function getWebhookQueue(queueName: string = WEBHOOK_DELIVERIES_QUEUE): Queue<WebhookDeliveryJob> {\n const existing = queues.get(queueName)\n if (existing) return existing\n\n const concurrency = Math.max(1, Number.parseInt(process.env.WEBHOOK_QUEUE_CONCURRENCY ?? '10', 10) || 10)\n const created = createModuleQueue<WebhookDeliveryJob>(queueName, { concurrency })\n\n queues.set(queueName, created)\n return created\n}\n\nasync function ensureLocalWebhookQueueWorkerStarted(): Promise<void> {\n if (process.env.QUEUE_STRATEGY === 'async') return\n\n const globalStore = globalThis as typeof globalThis & {\n [LOCAL_WORKER_PROMISE_KEY]?: Promise<void>\n }\n\n if (globalStore[LOCAL_WORKER_PROMISE_KEY]) {\n await globalStore[LOCAL_WORKER_PROMISE_KEY]\n return\n }\n\n globalStore[LOCAL_WORKER_PROMISE_KEY] = (async () => {\n const queue = getWebhookQueue()\n\n await queue.process(async (job) => {\n const [{ createRequestContainer }, { processWebhookDeliveryJob }] = await Promise.all([\n import('@open-mercato/shared/lib/di/container'),\n import('./delivery'),\n ])\n\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await processWebhookDeliveryJob(em, job.payload)\n })\n })().catch((error) => {\n delete globalStore[LOCAL_WORKER_PROMISE_KEY]\n logger.error('Failed to start local delivery worker', { err: error })\n throw error\n })\n\n await globalStore[LOCAL_WORKER_PROMISE_KEY]\n}\n\nexport async function enqueueWebhookDelivery(job: WebhookDeliveryJob, delayMs?: number): Promise<string> {\n const queue = getWebhookQueue()\n const jobId = await queue.enqueue(job, delayMs && delayMs > 0 ? { delayMs } : undefined)\n await ensureLocalWebhookQueueWorkerStarted()\n return jobId\n}\n"],
5
+ "mappings": "AACA,SAAS,yBAAqC;AAC9C,SAAS,oBAAoB;AAG7B,MAAM,SAAS,aAAa,UAAU;AAEtC,MAAM,SAAS,oBAAI,IAAuC;AAC1D,MAAM,2BAA2B;AAE1B,MAAM,2BAA2B;AAEjC,SAAS,gBAAgB,YAAoB,0BAAqD;AACvG,QAAM,WAAW,OAAO,IAAI,SAAS;AACrC,MAAI,SAAU,QAAO;AAErB,QAAM,cAAc,KAAK,IAAI,GAAG,OAAO,SAAS,QAAQ,IAAI,6BAA6B,MAAM,EAAE,KAAK,EAAE;AACxG,QAAM,UAAU,kBAAsC,WAAW,EAAE,YAAY,CAAC;AAEhF,SAAO,IAAI,WAAW,OAAO;AAC7B,SAAO;AACT;AAEA,eAAe,uCAAsD;AACnE,MAAI,QAAQ,IAAI,mBAAmB,QAAS;AAE5C,QAAM,cAAc;AAIpB,MAAI,YAAY,wBAAwB,GAAG;AACzC,UAAM,YAAY,wBAAwB;AAC1C;AAAA,EACF;AAEA,cAAY,wBAAwB,KAAK,YAAY;AACnD,UAAM,QAAQ,gBAAgB;AAE9B,UAAM,MAAM,QAAQ,OAAO,QAAQ;AACjC,YAAM,CAAC,EAAE,uBAAuB,GAAG,EAAE,0BAA0B,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpF,OAAO,uCAAuC;AAAA,QAC9C,OAAO,YAAY;AAAA,MACrB,CAAC;AAED,YAAM,YAAY,MAAM,uBAAuB;AAC/C,YAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,YAAM,0BAA0B,IAAI,IAAI,OAAO;AAAA,IACjD,CAAC;AAAA,EACH,GAAG,EAAE,MAAM,CAAC,UAAU;AACpB,WAAO,YAAY,wBAAwB;AAC3C,WAAO,MAAM,yCAAyC,EAAE,KAAK,MAAM,CAAC;AACpE,UAAM;AAAA,EACR,CAAC;AAED,QAAM,YAAY,wBAAwB;AAC5C;AAEA,eAAsB,uBAAuB,KAAyB,SAAmC;AACvG,QAAM,QAAQ,gBAAgB;AAC9B,QAAM,QAAQ,MAAM,MAAM,QAAQ,KAAK,WAAW,UAAU,IAAI,EAAE,QAAQ,IAAI,MAAS;AACvF,QAAM,qCAAqC;AAC3C,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,11 @@
1
1
  import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
2
  import { resolveNotificationService } from "@open-mercato/core/modules/notifications/lib/notificationService";
3
3
  import { buildFeatureNotificationFromType } from "@open-mercato/core/modules/notifications/lib/notificationBuilder";
4
+ import { createLogger } from "@open-mercato/shared/lib/logger";
4
5
  import { WebhookEntity } from "../data/entities.js";
5
6
  import { resolveWebhookIntegrationSettings } from "../lib/integration-settings.js";
6
7
  import { notificationTypes } from "../notifications.js";
8
+ const logger = createLogger("webhooks").child({ component: "failed-delivery-notification" });
7
9
  const metadata = {
8
10
  event: "webhooks.delivery.exhausted",
9
11
  persistent: true,
@@ -55,7 +57,7 @@ async function handle(payload, ctx) {
55
57
  organizationId
56
58
  });
57
59
  } catch (err) {
58
- console.error("[webhooks:failed-delivery-notification] Failed to create notification:", err);
60
+ logger.error("Failed to create notification", { err });
59
61
  }
60
62
  }
61
63
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/webhooks/subscribers/failed-delivery-notification.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'\nimport { buildFeatureNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'\nimport { WebhookEntity } from '../data/entities'\nimport { resolveWebhookIntegrationSettings } from '../lib/integration-settings'\nimport { notificationTypes } from '../notifications'\n\nexport const metadata = {\n event: 'webhooks.delivery.exhausted',\n persistent: true,\n id: 'webhooks:failed-delivery-notification',\n}\n\ntype WebhookDeliveryExhaustedPayload = {\n deliveryId: string\n webhookId: string\n eventType: string\n errorMessage?: string | null\n tenantId: string\n organizationId?: string | null\n}\n\ntype ResolverContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport default async function handle(payload: WebhookDeliveryExhaustedPayload, ctx: ResolverContext) {\n try {\n const organizationId = payload.organizationId ?? null\n const settings = await resolveWebhookIntegrationSettings(ctx, {\n tenantId: payload.tenantId,\n organizationId: organizationId ?? '',\n })\n if (!settings.notifyOnFailedDelivery) return\n\n const notificationService = resolveNotificationService(ctx)\n const typeDef = notificationTypes.find((type) => type.type === 'webhooks.delivery.failed')\n if (!typeDef) return\n\n const em = ctx.resolve<EntityManager>('em').fork()\n const webhook = await findOneWithDecryption(\n em,\n WebhookEntity,\n {\n id: payload.webhookId,\n tenantId: payload.tenantId,\n organizationId: organizationId ?? undefined,\n deletedAt: null,\n },\n {},\n { tenantId: payload.tenantId, organizationId: organizationId ?? '' },\n )\n\n const webhookName = webhook?.name?.trim() || payload.webhookId\n const errorMessage = payload.errorMessage?.trim() || 'Delivery retries exhausted'\n\n const notificationInput = buildFeatureNotificationFromType(typeDef, {\n requiredFeature: 'webhooks.manage',\n titleVariables: {\n webhookName,\n },\n bodyVariables: {\n webhookName,\n eventType: payload.eventType,\n errorMessage,\n },\n sourceEntityType: 'webhooks:webhook',\n sourceEntityId: payload.webhookId,\n linkHref: `/backend/webhooks/${payload.webhookId}`,\n groupKey: `delivery-failed:${payload.deliveryId}`,\n })\n\n await notificationService.createForFeature(notificationInput, {\n tenantId: payload.tenantId,\n organizationId,\n })\n } catch (err) {\n console.error('[webhooks:failed-delivery-notification] Failed to create notification:', err)\n }\n}\n"],
5
- "mappings": "AACA,SAAS,6BAA6B;AACtC,SAAS,kCAAkC;AAC3C,SAAS,wCAAwC;AACjD,SAAS,qBAAqB;AAC9B,SAAS,yCAAyC;AAClD,SAAS,yBAAyB;AAE3B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAeA,eAAO,OAA8B,SAA0C,KAAsB;AACnG,MAAI;AACF,UAAM,iBAAiB,QAAQ,kBAAkB;AACjD,UAAM,WAAW,MAAM,kCAAkC,KAAK;AAAA,MAC5D,UAAU,QAAQ;AAAA,MAClB,gBAAgB,kBAAkB;AAAA,IACpC,CAAC;AACD,QAAI,CAAC,SAAS,uBAAwB;AAEtC,UAAM,sBAAsB,2BAA2B,GAAG;AAC1D,UAAM,UAAU,kBAAkB,KAAK,CAAC,SAAS,KAAK,SAAS,0BAA0B;AACzF,QAAI,CAAC,QAAS;AAEd,UAAM,KAAK,IAAI,QAAuB,IAAI,EAAE,KAAK;AACjD,UAAM,UAAU,MAAM;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,QACE,IAAI,QAAQ;AAAA,QACZ,UAAU,QAAQ;AAAA,QAClB,gBAAgB,kBAAkB;AAAA,QAClC,WAAW;AAAA,MACb;AAAA,MACA,CAAC;AAAA,MACD,EAAE,UAAU,QAAQ,UAAU,gBAAgB,kBAAkB,GAAG;AAAA,IACrE;AAEA,UAAM,cAAc,SAAS,MAAM,KAAK,KAAK,QAAQ;AACrD,UAAM,eAAe,QAAQ,cAAc,KAAK,KAAK;AAErD,UAAM,oBAAoB,iCAAiC,SAAS;AAAA,MAClE,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,QACd;AAAA,MACF;AAAA,MACA,eAAe;AAAA,QACb;AAAA,QACA,WAAW,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,MACA,kBAAkB;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,qBAAqB,QAAQ,SAAS;AAAA,MAChD,UAAU,mBAAmB,QAAQ,UAAU;AAAA,IACjD,CAAC;AAED,UAAM,oBAAoB,iBAAiB,mBAAmB;AAAA,MAC5D,UAAU,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,0EAA0E,GAAG;AAAA,EAC7F;AACF;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'\nimport { buildFeatureNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { WebhookEntity } from '../data/entities'\nimport { resolveWebhookIntegrationSettings } from '../lib/integration-settings'\nimport { notificationTypes } from '../notifications'\n\nconst logger = createLogger('webhooks').child({ component: 'failed-delivery-notification' })\n\nexport const metadata = {\n event: 'webhooks.delivery.exhausted',\n persistent: true,\n id: 'webhooks:failed-delivery-notification',\n}\n\ntype WebhookDeliveryExhaustedPayload = {\n deliveryId: string\n webhookId: string\n eventType: string\n errorMessage?: string | null\n tenantId: string\n organizationId?: string | null\n}\n\ntype ResolverContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport default async function handle(payload: WebhookDeliveryExhaustedPayload, ctx: ResolverContext) {\n try {\n const organizationId = payload.organizationId ?? null\n const settings = await resolveWebhookIntegrationSettings(ctx, {\n tenantId: payload.tenantId,\n organizationId: organizationId ?? '',\n })\n if (!settings.notifyOnFailedDelivery) return\n\n const notificationService = resolveNotificationService(ctx)\n const typeDef = notificationTypes.find((type) => type.type === 'webhooks.delivery.failed')\n if (!typeDef) return\n\n const em = ctx.resolve<EntityManager>('em').fork()\n const webhook = await findOneWithDecryption(\n em,\n WebhookEntity,\n {\n id: payload.webhookId,\n tenantId: payload.tenantId,\n organizationId: organizationId ?? undefined,\n deletedAt: null,\n },\n {},\n { tenantId: payload.tenantId, organizationId: organizationId ?? '' },\n )\n\n const webhookName = webhook?.name?.trim() || payload.webhookId\n const errorMessage = payload.errorMessage?.trim() || 'Delivery retries exhausted'\n\n const notificationInput = buildFeatureNotificationFromType(typeDef, {\n requiredFeature: 'webhooks.manage',\n titleVariables: {\n webhookName,\n },\n bodyVariables: {\n webhookName,\n eventType: payload.eventType,\n errorMessage,\n },\n sourceEntityType: 'webhooks:webhook',\n sourceEntityId: payload.webhookId,\n linkHref: `/backend/webhooks/${payload.webhookId}`,\n groupKey: `delivery-failed:${payload.deliveryId}`,\n })\n\n await notificationService.createForFeature(notificationInput, {\n tenantId: payload.tenantId,\n organizationId,\n })\n } catch (err) {\n logger.error('Failed to create notification', { err })\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,6BAA6B;AACtC,SAAS,kCAAkC;AAC3C,SAAS,wCAAwC;AACjD,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,yCAAyC;AAClD,SAAS,yBAAyB;AAElC,MAAM,SAAS,aAAa,UAAU,EAAE,MAAM,EAAE,WAAW,+BAA+B,CAAC;AAEpF,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAeA,eAAO,OAA8B,SAA0C,KAAsB;AACnG,MAAI;AACF,UAAM,iBAAiB,QAAQ,kBAAkB;AACjD,UAAM,WAAW,MAAM,kCAAkC,KAAK;AAAA,MAC5D,UAAU,QAAQ;AAAA,MAClB,gBAAgB,kBAAkB;AAAA,IACpC,CAAC;AACD,QAAI,CAAC,SAAS,uBAAwB;AAEtC,UAAM,sBAAsB,2BAA2B,GAAG;AAC1D,UAAM,UAAU,kBAAkB,KAAK,CAAC,SAAS,KAAK,SAAS,0BAA0B;AACzF,QAAI,CAAC,QAAS;AAEd,UAAM,KAAK,IAAI,QAAuB,IAAI,EAAE,KAAK;AACjD,UAAM,UAAU,MAAM;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,QACE,IAAI,QAAQ;AAAA,QACZ,UAAU,QAAQ;AAAA,QAClB,gBAAgB,kBAAkB;AAAA,QAClC,WAAW;AAAA,MACb;AAAA,MACA,CAAC;AAAA,MACD,EAAE,UAAU,QAAQ,UAAU,gBAAgB,kBAAkB,GAAG;AAAA,IACrE;AAEA,UAAM,cAAc,SAAS,MAAM,KAAK,KAAK,QAAQ;AACrD,UAAM,eAAe,QAAQ,cAAc,KAAK,KAAK;AAErD,UAAM,oBAAoB,iCAAiC,SAAS;AAAA,MAClE,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,QACd;AAAA,MACF;AAAA,MACA,eAAe;AAAA,QACb;AAAA,QACA,WAAW,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,MACA,kBAAkB;AAAA,MAClB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,qBAAqB,QAAQ,SAAS;AAAA,MAChD,UAAU,mBAAmB,QAAQ,UAAU;AAAA,IACjD,CAAC;AAED,UAAM,oBAAoB,iBAAiB,mBAAmB;AAAA,MAC5D,UAAU,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,MAAM,iCAAiC,EAAE,IAAI,CAAC;AAAA,EACvD;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,6 @@
1
+ import { createLogger } from "@open-mercato/shared/lib/logger";
1
2
  import { getWebhookEndpointAdapter } from "../lib/adapter-registry.js";
3
+ const logger = createLogger("webhooks").child({ component: "inbound" });
2
4
  const metadata = {
3
5
  event: "webhooks.inbound.received",
4
6
  persistent: true,
@@ -24,11 +26,7 @@ async function handler(payload) {
24
26
  organizationId: typeof payload.organizationId === "string" ? payload.organizationId : void 0
25
27
  });
26
28
  } catch (err) {
27
- console.error("[webhooks:inbound] Processing failed:", {
28
- providerKey,
29
- eventType,
30
- error: err instanceof Error ? err.message : String(err)
31
- });
29
+ logger.error("Processing failed", { providerKey, eventType, err });
32
30
  throw err;
33
31
  }
34
32
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/webhooks/subscribers/inbound-process.ts"],
4
- "sourcesContent": ["import { getWebhookEndpointAdapter } from '../lib/adapter-registry'\n\nexport const metadata = {\n event: 'webhooks.inbound.received',\n persistent: true,\n id: 'webhooks:inbound-process',\n}\n\nexport default async function handler(payload: Record<string, unknown>) {\n const providerKey = typeof payload.providerKey === 'string' ? payload.providerKey : null\n const eventType = typeof payload.eventType === 'string' ? payload.eventType : null\n const verifiedPayload = isRecord(payload.payload) ? payload.payload : null\n\n if (!providerKey || !eventType || !verifiedPayload) {\n return\n }\n\n const adapter = getWebhookEndpointAdapter(providerKey)\n if (!adapter) {\n throw new Error(`Webhook endpoint adapter \"${providerKey}\" is not registered`)\n }\n\n try {\n await adapter.processInbound({\n providerKey,\n eventType,\n payload: verifiedPayload,\n tenantId: typeof payload.tenantId === 'string' ? payload.tenantId : undefined,\n organizationId: typeof payload.organizationId === 'string' ? payload.organizationId : undefined,\n })\n } catch (err) {\n console.error('[webhooks:inbound] Processing failed:', {\n providerKey,\n eventType,\n error: err instanceof Error ? err.message : String(err),\n })\n throw err\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],
5
- "mappings": "AAAA,SAAS,iCAAiC;AAEnC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,QAA+B,SAAkC;AACtE,QAAM,cAAc,OAAO,QAAQ,gBAAgB,WAAW,QAAQ,cAAc;AACpF,QAAM,YAAY,OAAO,QAAQ,cAAc,WAAW,QAAQ,YAAY;AAC9E,QAAM,kBAAkB,SAAS,QAAQ,OAAO,IAAI,QAAQ,UAAU;AAEtE,MAAI,CAAC,eAAe,CAAC,aAAa,CAAC,iBAAiB;AAClD;AAAA,EACF;AAEA,QAAM,UAAU,0BAA0B,WAAW;AACrD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,6BAA6B,WAAW,qBAAqB;AAAA,EAC/E;AAEA,MAAI;AACF,UAAM,QAAQ,eAAe;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW;AAAA,MACpE,gBAAgB,OAAO,QAAQ,mBAAmB,WAAW,QAAQ,iBAAiB;AAAA,IACxF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,yCAAyC;AAAA,MACrD;AAAA,MACA;AAAA,MACA,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD,CAAC;AACD,UAAM;AAAA,EACR;AACF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;",
4
+ "sourcesContent": ["import { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getWebhookEndpointAdapter } from '../lib/adapter-registry'\n\nconst logger = createLogger('webhooks').child({ component: 'inbound' })\n\nexport const metadata = {\n event: 'webhooks.inbound.received',\n persistent: true,\n id: 'webhooks:inbound-process',\n}\n\nexport default async function handler(payload: Record<string, unknown>) {\n const providerKey = typeof payload.providerKey === 'string' ? payload.providerKey : null\n const eventType = typeof payload.eventType === 'string' ? payload.eventType : null\n const verifiedPayload = isRecord(payload.payload) ? payload.payload : null\n\n if (!providerKey || !eventType || !verifiedPayload) {\n return\n }\n\n const adapter = getWebhookEndpointAdapter(providerKey)\n if (!adapter) {\n throw new Error(`Webhook endpoint adapter \"${providerKey}\" is not registered`)\n }\n\n try {\n await adapter.processInbound({\n providerKey,\n eventType,\n payload: verifiedPayload,\n tenantId: typeof payload.tenantId === 'string' ? payload.tenantId : undefined,\n organizationId: typeof payload.organizationId === 'string' ? payload.organizationId : undefined,\n })\n } catch (err) {\n logger.error('Processing failed', { providerKey, eventType, err })\n throw err\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,iCAAiC;AAE1C,MAAM,SAAS,aAAa,UAAU,EAAE,MAAM,EAAE,WAAW,UAAU,CAAC;AAE/D,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,QAA+B,SAAkC;AACtE,QAAM,cAAc,OAAO,QAAQ,gBAAgB,WAAW,QAAQ,cAAc;AACpF,QAAM,YAAY,OAAO,QAAQ,cAAc,WAAW,QAAQ,YAAY;AAC9E,QAAM,kBAAkB,SAAS,QAAQ,OAAO,IAAI,QAAQ,UAAU;AAEtE,MAAI,CAAC,eAAe,CAAC,aAAa,CAAC,iBAAiB;AAClD;AAAA,EACF;AAEA,QAAM,UAAU,0BAA0B,WAAW;AACrD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,6BAA6B,WAAW,qBAAqB;AAAA,EAC/E;AAEA,MAAI;AACF,UAAM,QAAQ,eAAe;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW;AAAA,MACpE,gBAAgB,OAAO,QAAQ,mBAAmB,WAAW,QAAQ,iBAAiB;AAAA,IACxF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,MAAM,qBAAqB,EAAE,aAAa,WAAW,IAAI,CAAC;AACjE,UAAM;AAAA,EACR;AACF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;",
6
6
  "names": []
7
7
  }
@@ -2,9 +2,11 @@ import { WebhookDeliveryEntity, WebhookEntity } from "../data/entities.js";
2
2
  import { findWithDecryption, findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
3
3
  import { matchAnyWebhookEventPattern } from "@open-mercato/shared/lib/events/patterns";
4
4
  import { getDeclaredEvents } from "@open-mercato/shared/modules/events";
5
+ import { createLogger } from "@open-mercato/shared/lib/logger";
5
6
  import { createWebhookDelivery } from "../lib/delivery.js";
6
7
  import { enqueueWebhookDelivery } from "../lib/queue.js";
7
8
  import { isWebhookIntegrationEnabled } from "../lib/integration-state.js";
9
+ const logger = createLogger("webhooks");
8
10
  const metadata = {
9
11
  event: "*",
10
12
  persistent: true,
@@ -99,12 +101,12 @@ async function handler(payload, ctx) {
99
101
  await webhookEm.flush();
100
102
  }
101
103
  }
102
- console.error("[webhooks] Failed to enqueue outbound delivery", {
104
+ logger.error("Failed to enqueue outbound delivery", {
103
105
  webhookId: webhook.id,
104
106
  eventId,
105
107
  tenantId,
106
108
  organizationId: organizationId ?? webhook.organizationId,
107
- error: error instanceof Error ? error.message : String(error)
109
+ err: error
108
110
  });
109
111
  }
110
112
  })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/webhooks/subscribers/outbound-dispatch.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { SubscriberContext } from '@open-mercato/events/types'\nimport { WebhookDeliveryEntity, WebhookEntity } from '../data/entities'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { matchAnyWebhookEventPattern } from '@open-mercato/shared/lib/events/patterns'\nimport { getDeclaredEvents } from '@open-mercato/shared/modules/events'\nimport { createWebhookDelivery } from '../lib/delivery'\nimport { enqueueWebhookDelivery } from '../lib/queue'\nimport { isWebhookIntegrationEnabled } from '../lib/integration-state'\n\nexport const metadata = {\n event: '*',\n persistent: true,\n id: 'webhooks:outbound-dispatch',\n}\n\nfunction shouldSkipOutboundDispatch(eventId: string): boolean {\n if (eventId.startsWith('webhooks.') || eventId.startsWith('application.')) return true\n\n const declaredEvent = getDeclaredEvents().find((event) => event.id === eventId)\n return declaredEvent?.excludeFromTriggers === true\n}\n\nfunction forkOutboundEntityManager(em: EntityManager): EntityManager {\n const fork = (em as unknown as { fork?: (options?: Record<string, unknown>) => EntityManager }).fork\n if (typeof fork !== 'function') return em\n return fork.call(em, { clear: true, useContext: false })\n}\n\nfunction integrationScopeKey(tenantId: string, organizationId: string): string {\n return `${tenantId}:${organizationId}`\n}\n\nexport default async function handler(\n payload: Record<string, unknown>,\n ctx: (SubscriberContext & { eventId?: string }) | { container?: { resolve: <T = unknown>(name: string) => T }; eventId?: string; eventName?: string; resolve?: <T = unknown>(name: string) => T },\n) {\n const eventId = ctx.eventId ?? ctx.eventName ?? (payload.eventId as string) ?? (payload.type as string)\n if (!eventId) return\n if (shouldSkipOutboundDispatch(eventId)) return\n\n const tenantId = payload.tenantId as string | undefined\n const organizationId = payload.organizationId as string | undefined\n if (!tenantId) return\n\n if (eventId.startsWith('webhooks.')) return\n if (eventId.startsWith('query_index.')) return\n\n\n const resolve = ('resolve' in ctx && typeof ctx.resolve === 'function')\n ? ctx.resolve\n : ('container' in ctx && ctx.container && typeof ctx.container.resolve === 'function')\n ? ctx.container.resolve.bind(ctx.container)\n : null\n\n if (!resolve) return\n\n const em = (resolve('em') as EntityManager).fork()\n\n const webhooks = await findWithDecryption(\n em,\n WebhookEntity,\n {\n isActive: true,\n deletedAt: null,\n tenantId,\n ...(organizationId ? { organizationId } : {}),\n },\n {},\n { tenantId, organizationId: organizationId ?? null },\n )\n\n if (!webhooks.length) return\n\n const matchingWebhooks = webhooks.filter((webhook) =>\n matchAnyWebhookEventPattern(eventId, webhook.subscribedEvents),\n )\n\n if (!matchingWebhooks.length) return\n\n const integrationEnabledByScope = new Map<string, Promise<boolean>>()\n\n const resolveIntegrationEnabled = (webhook: WebhookEntity): Promise<boolean> => {\n const key = integrationScopeKey(webhook.tenantId, webhook.organizationId)\n let pending = integrationEnabledByScope.get(key)\n if (!pending) {\n pending = isWebhookIntegrationEnabled(em, {\n tenantId: webhook.tenantId,\n organizationId: webhook.organizationId,\n })\n integrationEnabledByScope.set(key, pending)\n }\n return pending\n }\n\n await Promise.all(\n matchingWebhooks.map(async (webhook) => {\n if (!(await resolveIntegrationEnabled(webhook))) return\n\n const webhookEm = forkOutboundEntityManager(em)\n let createdDeliveryId: string | null = null\n try {\n const delivery = await createWebhookDelivery({\n em: webhookEm,\n webhook,\n eventId,\n payload,\n })\n createdDeliveryId = delivery.id\n\n await enqueueWebhookDelivery({\n deliveryId: delivery.id,\n tenantId: delivery.tenantId,\n organizationId: delivery.organizationId,\n })\n } catch (error) {\n if (createdDeliveryId) {\n const failedDelivery = await findOneWithDecryption(\n webhookEm,\n WebhookDeliveryEntity,\n { id: createdDeliveryId, tenantId: webhook.tenantId, organizationId: webhook.organizationId },\n undefined,\n { tenantId: webhook.tenantId, organizationId: webhook.organizationId },\n )\n if (failedDelivery) {\n failedDelivery.status = 'failed'\n failedDelivery.errorMessage = error instanceof Error ? `Queue enqueue failed: ${error.message}` : 'Queue enqueue failed'\n failedDelivery.nextRetryAt = null\n await webhookEm.flush()\n }\n }\n console.error('[webhooks] Failed to enqueue outbound delivery', {\n webhookId: webhook.id,\n eventId,\n tenantId,\n organizationId: organizationId ?? webhook.organizationId,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }),\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { SubscriberContext } from '@open-mercato/events/types'\nimport { WebhookDeliveryEntity, WebhookEntity } from '../data/entities'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { matchAnyWebhookEventPattern } from '@open-mercato/shared/lib/events/patterns'\nimport { getDeclaredEvents } from '@open-mercato/shared/modules/events'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { createWebhookDelivery } from '../lib/delivery'\nimport { enqueueWebhookDelivery } from '../lib/queue'\nimport { isWebhookIntegrationEnabled } from '../lib/integration-state'\n\nconst logger = createLogger('webhooks')\n\nexport const metadata = {\n event: '*',\n persistent: true,\n id: 'webhooks:outbound-dispatch',\n}\n\nfunction shouldSkipOutboundDispatch(eventId: string): boolean {\n if (eventId.startsWith('webhooks.') || eventId.startsWith('application.')) return true\n\n const declaredEvent = getDeclaredEvents().find((event) => event.id === eventId)\n return declaredEvent?.excludeFromTriggers === true\n}\n\nfunction forkOutboundEntityManager(em: EntityManager): EntityManager {\n const fork = (em as unknown as { fork?: (options?: Record<string, unknown>) => EntityManager }).fork\n if (typeof fork !== 'function') return em\n return fork.call(em, { clear: true, useContext: false })\n}\n\nfunction integrationScopeKey(tenantId: string, organizationId: string): string {\n return `${tenantId}:${organizationId}`\n}\n\nexport default async function handler(\n payload: Record<string, unknown>,\n ctx: (SubscriberContext & { eventId?: string }) | { container?: { resolve: <T = unknown>(name: string) => T }; eventId?: string; eventName?: string; resolve?: <T = unknown>(name: string) => T },\n) {\n const eventId = ctx.eventId ?? ctx.eventName ?? (payload.eventId as string) ?? (payload.type as string)\n if (!eventId) return\n if (shouldSkipOutboundDispatch(eventId)) return\n\n const tenantId = payload.tenantId as string | undefined\n const organizationId = payload.organizationId as string | undefined\n if (!tenantId) return\n\n if (eventId.startsWith('webhooks.')) return\n if (eventId.startsWith('query_index.')) return\n\n\n const resolve = ('resolve' in ctx && typeof ctx.resolve === 'function')\n ? ctx.resolve\n : ('container' in ctx && ctx.container && typeof ctx.container.resolve === 'function')\n ? ctx.container.resolve.bind(ctx.container)\n : null\n\n if (!resolve) return\n\n const em = (resolve('em') as EntityManager).fork()\n\n const webhooks = await findWithDecryption(\n em,\n WebhookEntity,\n {\n isActive: true,\n deletedAt: null,\n tenantId,\n ...(organizationId ? { organizationId } : {}),\n },\n {},\n { tenantId, organizationId: organizationId ?? null },\n )\n\n if (!webhooks.length) return\n\n const matchingWebhooks = webhooks.filter((webhook) =>\n matchAnyWebhookEventPattern(eventId, webhook.subscribedEvents),\n )\n\n if (!matchingWebhooks.length) return\n\n const integrationEnabledByScope = new Map<string, Promise<boolean>>()\n\n const resolveIntegrationEnabled = (webhook: WebhookEntity): Promise<boolean> => {\n const key = integrationScopeKey(webhook.tenantId, webhook.organizationId)\n let pending = integrationEnabledByScope.get(key)\n if (!pending) {\n pending = isWebhookIntegrationEnabled(em, {\n tenantId: webhook.tenantId,\n organizationId: webhook.organizationId,\n })\n integrationEnabledByScope.set(key, pending)\n }\n return pending\n }\n\n await Promise.all(\n matchingWebhooks.map(async (webhook) => {\n if (!(await resolveIntegrationEnabled(webhook))) return\n\n const webhookEm = forkOutboundEntityManager(em)\n let createdDeliveryId: string | null = null\n try {\n const delivery = await createWebhookDelivery({\n em: webhookEm,\n webhook,\n eventId,\n payload,\n })\n createdDeliveryId = delivery.id\n\n await enqueueWebhookDelivery({\n deliveryId: delivery.id,\n tenantId: delivery.tenantId,\n organizationId: delivery.organizationId,\n })\n } catch (error) {\n if (createdDeliveryId) {\n const failedDelivery = await findOneWithDecryption(\n webhookEm,\n WebhookDeliveryEntity,\n { id: createdDeliveryId, tenantId: webhook.tenantId, organizationId: webhook.organizationId },\n undefined,\n { tenantId: webhook.tenantId, organizationId: webhook.organizationId },\n )\n if (failedDelivery) {\n failedDelivery.status = 'failed'\n failedDelivery.errorMessage = error instanceof Error ? `Queue enqueue failed: ${error.message}` : 'Queue enqueue failed'\n failedDelivery.nextRetryAt = null\n await webhookEm.flush()\n }\n }\n logger.error('Failed to enqueue outbound delivery', {\n webhookId: webhook.id,\n eventId,\n tenantId,\n organizationId: organizationId ?? webhook.organizationId,\n err: error,\n })\n }\n }),\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,6 @@
1
+ import { createLogger } from "@open-mercato/shared/lib/logger";
1
2
  import { processWebhookDeliveryJob } from "../lib/delivery.js";
3
+ const logger = createLogger("webhooks").child({ component: "delivery" });
2
4
  const metadata = {
3
5
  queue: "webhook-deliveries",
4
6
  id: "webhooks:delivery-worker",
@@ -9,10 +11,10 @@ async function handler(job, ctx) {
9
11
  try {
10
12
  await processWebhookDeliveryJob(em, job.data);
11
13
  } catch (error) {
12
- console.error("[webhooks:delivery] Job processing failed", {
14
+ logger.error("Job processing failed", {
13
15
  deliveryId: job.data.deliveryId,
14
16
  tenantId: job.data.tenantId,
15
- error: error instanceof Error ? error.message : String(error)
17
+ err: error
16
18
  });
17
19
  throw error;
18
20
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/webhooks/workers/webhook-delivery.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { processWebhookDeliveryJob, type WebhookDeliveryJob } from '../lib/delivery'\n\nexport const metadata = {\n queue: 'webhook-deliveries',\n id: 'webhooks:delivery-worker',\n concurrency: 10,\n}\n\nexport default async function handler(\n job: { data: WebhookDeliveryJob },\n ctx: { resolve: <T = unknown>(name: string) => T },\n) {\n const em = (ctx.resolve('em') as EntityManager).fork()\n try {\n await processWebhookDeliveryJob(em, job.data)\n } catch (error) {\n console.error('[webhooks:delivery] Job processing failed', {\n deliveryId: job.data.deliveryId,\n tenantId: job.data.tenantId,\n error: error instanceof Error ? error.message : String(error),\n })\n throw error\n }\n}\n"],
5
- "mappings": "AACA,SAAS,iCAA0D;AAE5D,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,aAAa;AACf;AAEA,eAAO,QACL,KACA,KACA;AACA,QAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AACrD,MAAI;AACF,UAAM,0BAA0B,IAAI,IAAI,IAAI;AAAA,EAC9C,SAAS,OAAO;AACd,YAAQ,MAAM,6CAA6C;AAAA,MACzD,YAAY,IAAI,KAAK;AAAA,MACrB,UAAU,IAAI,KAAK;AAAA,MACnB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D,CAAC;AACD,UAAM;AAAA,EACR;AACF;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { processWebhookDeliveryJob, type WebhookDeliveryJob } from '../lib/delivery'\n\nconst logger = createLogger('webhooks').child({ component: 'delivery' })\n\nexport const metadata = {\n queue: 'webhook-deliveries',\n id: 'webhooks:delivery-worker',\n concurrency: 10,\n}\n\nexport default async function handler(\n job: { data: WebhookDeliveryJob },\n ctx: { resolve: <T = unknown>(name: string) => T },\n) {\n const em = (ctx.resolve('em') as EntityManager).fork()\n try {\n await processWebhookDeliveryJob(em, job.data)\n } catch (error) {\n logger.error('Job processing failed', {\n deliveryId: job.data.deliveryId,\n tenantId: job.data.tenantId,\n err: error,\n })\n throw error\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAS,iCAA0D;AAEnE,MAAM,SAAS,aAAa,UAAU,EAAE,MAAM,EAAE,WAAW,WAAW,CAAC;AAEhE,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,aAAa;AACf;AAEA,eAAO,QACL,KACA,KACA;AACA,QAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AACrD,MAAI;AACF,UAAM,0BAA0B,IAAI,IAAI,IAAI;AAAA,EAC9C,SAAS,OAAO;AACd,WAAO,MAAM,yBAAyB;AAAA,MACpC,YAAY,IAAI,KAAK;AAAA,MACrB,UAAU,IAAI,KAAK;AAAA,MACnB,KAAK;AAAA,IACP,CAAC;AACD,UAAM;AAAA,EACR;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/webhooks",
3
- "version": "0.6.6-develop.6465.1.019f0fb26f",
3
+ "version": "0.6.6-develop.6472.1.1673e7e66b",
4
4
  "license": "MIT",
5
5
  "description": "Webhooks module for Open Mercato — Standard Webhooks compliant outbound/inbound delivery",
6
6
  "type": "module",
@@ -70,19 +70,19 @@
70
70
  }
71
71
  },
72
72
  "dependencies": {
73
- "@open-mercato/core": "0.6.6-develop.6465.1.019f0fb26f",
74
- "@open-mercato/queue": "0.6.6-develop.6465.1.019f0fb26f",
75
- "@open-mercato/ui": "0.6.6-develop.6465.1.019f0fb26f",
73
+ "@open-mercato/core": "0.6.6-develop.6472.1.1673e7e66b",
74
+ "@open-mercato/queue": "0.6.6-develop.6472.1.1673e7e66b",
75
+ "@open-mercato/ui": "0.6.6-develop.6472.1.1673e7e66b",
76
76
  "svix": "^1.96.1"
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@mikro-orm/postgresql": "^7.0.14",
80
- "@open-mercato/shared": "0.6.6-develop.6465.1.019f0fb26f",
80
+ "@open-mercato/shared": "0.6.6-develop.6472.1.1673e7e66b",
81
81
  "react": "^19.0.0",
82
82
  "react-dom": "^19.0.0"
83
83
  },
84
84
  "devDependencies": {
85
- "@open-mercato/shared": "0.6.6-develop.6465.1.019f0fb26f",
85
+ "@open-mercato/shared": "0.6.6-develop.6472.1.1673e7e66b",
86
86
  "@types/jest": "^30.0.0",
87
87
  "@types/react": "^19.2.17",
88
88
  "@types/react-dom": "^19.2.3",
@@ -1,7 +1,10 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
2
  import { createModuleQueue, type Queue } from '@open-mercato/queue'
3
+ import { createLogger } from '@open-mercato/shared/lib/logger'
3
4
  import type { WebhookDeliveryJob } from './delivery'
4
5
 
6
+ const logger = createLogger('webhooks')
7
+
5
8
  const queues = new Map<string, Queue<WebhookDeliveryJob>>()
6
9
  const LOCAL_WORKER_PROMISE_KEY = '__openMercatoWebhookLocalWorkerPromise__'
7
10
 
@@ -45,7 +48,7 @@ async function ensureLocalWebhookQueueWorkerStarted(): Promise<void> {
45
48
  })
46
49
  })().catch((error) => {
47
50
  delete globalStore[LOCAL_WORKER_PROMISE_KEY]
48
- console.error('[webhooks] Failed to start local delivery worker:', error)
51
+ logger.error('Failed to start local delivery worker', { err: error })
49
52
  throw error
50
53
  })
51
54
 
@@ -1,6 +1,18 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
2
  import handler from '../outbound-dispatch'
3
3
 
4
+ jest.mock('@open-mercato/shared/lib/logger', () => {
5
+ const mocked = {
6
+ debug: jest.fn(),
7
+ info: jest.fn(),
8
+ warn: jest.fn(),
9
+ error: jest.fn(),
10
+ child: jest.fn(),
11
+ }
12
+ mocked.child.mockImplementation(() => mocked)
13
+ return { createLogger: jest.fn(() => mocked) }
14
+ })
15
+
4
16
  jest.mock('@open-mercato/shared/lib/encryption/find', () => ({
5
17
  findWithDecryption: jest.fn(),
6
18
  findOneWithDecryption: jest.fn(),
@@ -22,6 +34,9 @@ jest.mock('../../lib/integration-state', () => ({
22
34
 
23
35
  import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
24
36
  import { getDeclaredEvents } from '@open-mercato/shared/modules/events'
37
+ import { createLogger } from '@open-mercato/shared/lib/logger'
38
+
39
+ const dispatchLoggerError = createLogger('webhooks').error as jest.Mock
25
40
  import { createWebhookDelivery } from '../../lib/delivery'
26
41
  import { enqueueWebhookDelivery } from '../../lib/queue'
27
42
  import { isWebhookIntegrationEnabled } from '../../lib/integration-state'
@@ -189,7 +204,7 @@ describe('webhooks outbound dispatch subscriber', () => {
189
204
  })
190
205
 
191
206
  it('scopes the failed-delivery lookup to webhook tenantId and organizationId when enqueue throws', async () => {
192
- const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined)
207
+ dispatchLoggerError.mockClear()
193
208
 
194
209
  try {
195
210
  const { rootEm, webhookEm } = createDispatchEntityManagers()
@@ -234,18 +249,18 @@ describe('webhooks outbound dispatch subscriber', () => {
234
249
  expect.objectContaining({ tenantId: 'tenant-1', organizationId: 'org-1' }),
235
250
  )
236
251
  expect(webhookEm.flush).toHaveBeenCalled()
237
- expect(consoleErrorSpy).toHaveBeenCalledWith(
238
- '[webhooks] Failed to enqueue outbound delivery',
252
+ expect(dispatchLoggerError).toHaveBeenCalledWith(
253
+ 'Failed to enqueue outbound delivery',
239
254
  expect.objectContaining({
240
255
  webhookId: 'webhook-1',
241
256
  eventId: 'catalog.product.created',
242
257
  tenantId: 'tenant-1',
243
258
  organizationId: 'org-1',
244
- error: 'Queue unavailable',
259
+ err: expect.objectContaining({ message: 'Queue unavailable' }),
245
260
  }),
246
261
  )
247
262
  } finally {
248
- consoleErrorSpy.mockRestore()
263
+ dispatchLoggerError.mockClear()
249
264
  }
250
265
  })
251
266
 
@@ -2,10 +2,13 @@ import type { EntityManager } from '@mikro-orm/postgresql'
2
2
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
3
  import { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'
4
4
  import { buildFeatureNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'
5
+ import { createLogger } from '@open-mercato/shared/lib/logger'
5
6
  import { WebhookEntity } from '../data/entities'
6
7
  import { resolveWebhookIntegrationSettings } from '../lib/integration-settings'
7
8
  import { notificationTypes } from '../notifications'
8
9
 
10
+ const logger = createLogger('webhooks').child({ component: 'failed-delivery-notification' })
11
+
9
12
  export const metadata = {
10
13
  event: 'webhooks.delivery.exhausted',
11
14
  persistent: true,
@@ -76,6 +79,6 @@ export default async function handle(payload: WebhookDeliveryExhaustedPayload, c
76
79
  organizationId,
77
80
  })
78
81
  } catch (err) {
79
- console.error('[webhooks:failed-delivery-notification] Failed to create notification:', err)
82
+ logger.error('Failed to create notification', { err })
80
83
  }
81
84
  }
@@ -1,5 +1,8 @@
1
+ import { createLogger } from '@open-mercato/shared/lib/logger'
1
2
  import { getWebhookEndpointAdapter } from '../lib/adapter-registry'
2
3
 
4
+ const logger = createLogger('webhooks').child({ component: 'inbound' })
5
+
3
6
  export const metadata = {
4
7
  event: 'webhooks.inbound.received',
5
8
  persistent: true,
@@ -29,11 +32,7 @@ export default async function handler(payload: Record<string, unknown>) {
29
32
  organizationId: typeof payload.organizationId === 'string' ? payload.organizationId : undefined,
30
33
  })
31
34
  } catch (err) {
32
- console.error('[webhooks:inbound] Processing failed:', {
33
- providerKey,
34
- eventType,
35
- error: err instanceof Error ? err.message : String(err),
36
- })
35
+ logger.error('Processing failed', { providerKey, eventType, err })
37
36
  throw err
38
37
  }
39
38
  }
@@ -4,10 +4,13 @@ import { WebhookDeliveryEntity, WebhookEntity } from '../data/entities'
4
4
  import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
5
5
  import { matchAnyWebhookEventPattern } from '@open-mercato/shared/lib/events/patterns'
6
6
  import { getDeclaredEvents } from '@open-mercato/shared/modules/events'
7
+ import { createLogger } from '@open-mercato/shared/lib/logger'
7
8
  import { createWebhookDelivery } from '../lib/delivery'
8
9
  import { enqueueWebhookDelivery } from '../lib/queue'
9
10
  import { isWebhookIntegrationEnabled } from '../lib/integration-state'
10
11
 
12
+ const logger = createLogger('webhooks')
13
+
11
14
  export const metadata = {
12
15
  event: '*',
13
16
  persistent: true,
@@ -129,12 +132,12 @@ export default async function handler(
129
132
  await webhookEm.flush()
130
133
  }
131
134
  }
132
- console.error('[webhooks] Failed to enqueue outbound delivery', {
135
+ logger.error('Failed to enqueue outbound delivery', {
133
136
  webhookId: webhook.id,
134
137
  eventId,
135
138
  tenantId,
136
139
  organizationId: organizationId ?? webhook.organizationId,
137
- error: error instanceof Error ? error.message : String(error),
140
+ err: error,
138
141
  })
139
142
  }
140
143
  }),
@@ -1,6 +1,9 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { createLogger } from '@open-mercato/shared/lib/logger'
2
3
  import { processWebhookDeliveryJob, type WebhookDeliveryJob } from '../lib/delivery'
3
4
 
5
+ const logger = createLogger('webhooks').child({ component: 'delivery' })
6
+
4
7
  export const metadata = {
5
8
  queue: 'webhook-deliveries',
6
9
  id: 'webhooks:delivery-worker',
@@ -15,10 +18,10 @@ export default async function handler(
15
18
  try {
16
19
  await processWebhookDeliveryJob(em, job.data)
17
20
  } catch (error) {
18
- console.error('[webhooks:delivery] Job processing failed', {
21
+ logger.error('Job processing failed', {
19
22
  deliveryId: job.data.deliveryId,
20
23
  tenantId: job.data.tenantId,
21
- error: error instanceof Error ? error.message : String(error),
24
+ err: error,
22
25
  })
23
26
  throw error
24
27
  }