@automagik/omni 2.260908.11 → 2.260908.13

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.
@@ -76865,7 +76865,7 @@ var require_ClientVoiceManager = __commonJS((exports, module) => {
76865
76865
 
76866
76866
  // ../../node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist/index.js
76867
76867
  var require_dist9 = __commonJS((exports, module) => {
76868
- var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist";
76868
+ var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist";
76869
76869
  var __create2 = Object.create;
76870
76870
  var __defProp2 = Object.defineProperty;
76871
76871
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -162145,7 +162145,7 @@ var require_indexes = __commonJS((exports, module) => {
162145
162145
 
162146
162146
  // ../../node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream/index.js
162147
162147
  var require_thread_stream = __commonJS((exports, module) => {
162148
- var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream";
162148
+ var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream";
162149
162149
  var { version } = require_package5();
162150
162150
  var { EventEmitter: EventEmitter3 } = __require("events");
162151
162151
  var { Worker } = __require("worker_threads");
@@ -162566,7 +162566,7 @@ var require_thread_stream = __commonJS((exports, module) => {
162566
162566
 
162567
162567
  // ../../node_modules/.bun/pino@9.14.0/node_modules/pino/lib/transport.js
162568
162568
  var require_transport2 = __commonJS((exports, module) => {
162569
- var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/pino@9.14.0/node_modules/pino/lib";
162569
+ var __dirname = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/pino@9.14.0/node_modules/pino/lib";
162570
162570
  var { createRequire: createRequire2 } = __require("module");
162571
162571
  var getCallers = require_caller();
162572
162572
  var { join: join8, isAbsolute, sep: sep2 } = __require("path");
@@ -172609,6 +172609,7 @@ __export(exports_schema, {
172609
172609
  eventTypes: () => eventTypes,
172610
172610
  eventSchemas: () => eventSchemas,
172611
172611
  eventPayloads: () => eventPayloads,
172612
+ durableConsumers: () => durableConsumers,
172612
172613
  deliveryStatuses: () => deliveryStatuses,
172613
172614
  debounceMode: () => debounceMode,
172614
172615
  deadLetterStatuses: () => deadLetterStatuses,
@@ -172669,7 +172670,7 @@ __export(exports_schema, {
172669
172670
  accessRules: () => accessRules,
172670
172671
  accessModes: () => accessModes
172671
172672
  });
172672
- 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;
172673
+ 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, durableConsumers, 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;
172673
172674
  var init_schema2 = __esm(() => {
172674
172675
  init_events();
172675
172676
  init_types5();
@@ -173405,10 +173406,12 @@ var init_schema2 = __esm(() => {
173405
173406
  idempotencyKey: text("idempotency_key"),
173406
173407
  metadata: jsonb("metadata").$type(),
173407
173408
  causationId: uuid("causation_id"),
173409
+ journalSeq: bigserial("journal_seq", { mode: "number" }),
173408
173410
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
173409
173411
  tenantId: uuid("tenant_id").references(() => tenants.id, { onDelete: "restrict" })
173410
173412
  }, (table3) => ({
173411
173413
  causationIdx: index("omni_events_causation_idx").on(table3.causationId),
173414
+ journalSeqUq: uniqueIndex("omni_events_journal_seq_uq").on(table3.journalSeq),
173412
173415
  tenantIdx: index("omni_events_tenant_idx").on(table3.tenantId),
173413
173416
  tenantIdUq: uniqueIndex("omni_events_tenant_id_uq").on(table3.tenantId, table3.id),
173414
173417
  idempotencyKeyUq: uniqueIndex("omni_events_idempotency_key_uq").on(table3.idempotencyKey),
@@ -174003,6 +174006,17 @@ var init_schema2 = __esm(() => {
174003
174006
  lastEventId: uuid("last_event_id"),
174004
174007
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
174005
174008
  });
174009
+ durableConsumers = pgTable("durable_consumers", {
174010
+ id: uuid("id").primaryKey().defaultRandom(),
174011
+ name: varchar("name", { length: 100 }).notNull(),
174012
+ eventType: varchar("event_type", { length: 255 }).notNull(),
174013
+ filters: jsonb("filters").$type(),
174014
+ cursor: bigint2("cursor", { mode: "number" }).notNull().default(0),
174015
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
174016
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
174017
+ }, (table3) => ({
174018
+ nameUq: uniqueIndex("durable_consumers_name_uq").on(table3.name)
174019
+ }));
174006
174020
  automationsRelations = relations(automations2, ({ many }) => ({
174007
174021
  logs: many(automationLogs)
174008
174022
  }));
@@ -178364,6 +178378,7 @@ __export(exports_src3, {
178364
178378
  eventSchemas: () => eventSchemas,
178365
178379
  eventPayloads: () => eventPayloads,
178366
178380
  eq: () => eq,
178381
+ durableConsumers: () => durableConsumers,
178367
178382
  desc: () => desc,
178368
178383
  deliveryStatuses: () => deliveryStatuses,
178369
178384
  debounceMode: () => debounceMode,
@@ -243939,7 +243954,7 @@ var require_client3 = __commonJS((exports) => {
243939
243954
 
243940
243955
  // ../../node_modules/.bun/@sentry+node-core@10.52.0+6488de8736d8e524/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js
243941
243956
  var require_esmLoader = __commonJS((exports) => {
243942
- var __filename = "/home/runner/work/omni/omni/node_modules/.bun/@sentry+node-core@10.52.0+6488de8736d8e524/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js";
243957
+ var __filename = "/home/runner/work/omni/omni/.stable-source/node_modules/.bun/@sentry+node-core@10.52.0+6488de8736d8e524/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js";
243943
243958
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
243944
243959
  var core3 = require_cjs6();
243945
243960
  var importInTheMiddle = require_import_in_the_middle();
@@ -251165,7 +251180,7 @@ var init_sentry_scrub = __esm(() => {
251165
251180
  var require_package7 = __commonJS((exports, module) => {
251166
251181
  module.exports = {
251167
251182
  name: "@omni/api",
251168
- version: "2.260908.11",
251183
+ version: "2.260908.13",
251169
251184
  private: true,
251170
251185
  type: "module",
251171
251186
  exports: {
@@ -286922,7 +286937,7 @@ var require_src52 = __commonJS((exports) => {
286922
286937
 
286923
286938
  // ../../node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src/channelz.js
286924
286939
  var require_channelz = __commonJS((exports) => {
286925
- var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
286940
+ 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";
286926
286941
  Object.defineProperty(exports, "__esModule", { value: true });
286927
286942
  exports.registerChannelzSocket = exports.registerChannelzServer = exports.registerChannelzSubchannel = exports.registerChannelzChannel = exports.ChannelzCallTrackerStub = exports.ChannelzCallTracker = exports.ChannelzChildrenTrackerStub = exports.ChannelzChildrenTracker = exports.ChannelzTrace = exports.ChannelzTraceStub = undefined;
286928
286943
  exports.unregisterChannelzRef = unregisterChannelzRef;
@@ -292325,7 +292340,7 @@ var require_duration = __commonJS((exports) => {
292325
292340
 
292326
292341
  // ../../node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src/orca.js
292327
292342
  var require_orca = __commonJS((exports) => {
292328
- var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
292343
+ 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";
292329
292344
  Object.defineProperty(exports, "__esModule", { value: true });
292330
292345
  exports.OrcaOobMetricsSubchannelWrapper = exports.GRPC_METRICS_HEADER = exports.ServerMetricRecorder = exports.PerRequestMetricRecorder = undefined;
292331
292346
  exports.createOrcaClient = createOrcaClient;
@@ -302747,6 +302762,7 @@ var init_route_ownership = __esm(() => {
302747
302762
  "DELETE /api/v2/conversations/:id",
302748
302763
  "DELETE /api/v2/event-ops/replay/:id",
302749
302764
  "DELETE /api/v2/events/:eventId/payloads",
302765
+ "DELETE /api/v2/events/consumers/:name",
302750
302766
  "DELETE /api/v2/follow-up/agents/:id",
302751
302767
  "DELETE /api/v2/follow-up/chats/:id",
302752
302768
  "DELETE /api/v2/follow-up/instances/:id",
@@ -302816,6 +302832,8 @@ var init_route_ownership = __esm(() => {
302816
302832
  "GET /api/v2/events/:id/trace",
302817
302833
  "GET /api/v2/events/analytics",
302818
302834
  "GET /api/v2/events/by-sender/:senderId",
302835
+ "GET /api/v2/events/consumers",
302836
+ "GET /api/v2/events/consumers/:name",
302819
302837
  "GET /api/v2/events/schemas",
302820
302838
  "GET /api/v2/events/schemas/:eventType",
302821
302839
  "GET /api/v2/events/timeline/:personId",
@@ -302957,6 +302975,9 @@ var init_route_ownership = __esm(() => {
302957
302975
  "POST /api/v2/dead-letters/:id/retry",
302958
302976
  "POST /api/v2/event-ops/replay",
302959
302977
  "POST /api/v2/event-ops/scheduled",
302978
+ "POST /api/v2/events/consumers",
302979
+ "POST /api/v2/events/consumers/:name/ack",
302980
+ "POST /api/v2/events/consumers/:name/pull",
302960
302981
  "POST /api/v2/events/schemas",
302961
302982
  "POST /api/v2/events/search",
302962
302983
  "POST /api/v2/events/trigger",
@@ -359003,6 +359024,365 @@ var init_dead_letters = __esm(() => {
359003
359024
  log99 = createLogger("dead-letters");
359004
359025
  });
359005
359026
 
359027
+ // ../api/src/services/events.ts
359028
+ function escapeLikePattern(value) {
359029
+ return value.replace(/([\\%_])/g, "\\$1");
359030
+ }
359031
+
359032
+ class EventService {
359033
+ pool;
359034
+ get db() {
359035
+ return scopedHandle(this.pool);
359036
+ }
359037
+ constructor(pool) {
359038
+ this.pool = pool;
359039
+ }
359040
+ async list(options = {}) {
359041
+ const {
359042
+ channel: channel5,
359043
+ instanceId,
359044
+ personId,
359045
+ eventType,
359046
+ contentType,
359047
+ direction,
359048
+ since,
359049
+ until,
359050
+ search,
359051
+ limit: limit2 = 50,
359052
+ cursor
359053
+ } = options;
359054
+ const conditions3 = [];
359055
+ if (channel5?.length) {
359056
+ conditions3.push(inArray(omniEvents.channel, channel5));
359057
+ }
359058
+ if (instanceId) {
359059
+ conditions3.push(eq(omniEvents.instanceId, instanceId));
359060
+ } else if (options.instanceIds?.length) {
359061
+ conditions3.push(inArray(omniEvents.instanceId, options.instanceIds));
359062
+ }
359063
+ if (personId) {
359064
+ conditions3.push(eq(omniEvents.personId, personId));
359065
+ }
359066
+ if (eventType?.length) {
359067
+ const exact = eventType.filter((t) => !t.endsWith("*"));
359068
+ const prefixes = eventType.filter((t) => t.endsWith("*")).map((t) => t.slice(0, -1));
359069
+ const typeClauses = [
359070
+ ...exact.length ? [inArray(omniEvents.eventType, exact)] : [],
359071
+ ...prefixes.map((p2) => like(omniEvents.eventType, `${escapeLikePattern(p2)}%`))
359072
+ ];
359073
+ const combined = typeClauses.length === 1 ? typeClauses[0] : or2(...typeClauses);
359074
+ if (combined)
359075
+ conditions3.push(combined);
359076
+ }
359077
+ if (contentType?.length) {
359078
+ conditions3.push(inArray(omniEvents.contentType, contentType));
359079
+ }
359080
+ if (direction) {
359081
+ conditions3.push(eq(omniEvents.direction, direction));
359082
+ }
359083
+ if (since) {
359084
+ conditions3.push(gte(omniEvents.receivedAt, since));
359085
+ }
359086
+ if (until) {
359087
+ conditions3.push(lte(omniEvents.receivedAt, until));
359088
+ }
359089
+ if (search) {
359090
+ const searchPattern = `%${search}%`;
359091
+ conditions3.push(or2(ilike(omniEvents.textContent, searchPattern), ilike(omniEvents.transcription, searchPattern), ilike(omniEvents.imageDescription, searchPattern)));
359092
+ }
359093
+ if (cursor) {
359094
+ conditions3.push(sql`${omniEvents.receivedAt} < ${cursor}`);
359095
+ }
359096
+ const whereClause = conditions3.length ? and2(...conditions3) : undefined;
359097
+ const items = await this.db.select().from(omniEvents).where(whereClause).orderBy(desc(omniEvents.receivedAt)).limit(limit2 + 1);
359098
+ const hasMore = items.length > limit2;
359099
+ if (hasMore) {
359100
+ items.pop();
359101
+ }
359102
+ const lastItem = items[items.length - 1];
359103
+ return {
359104
+ items,
359105
+ hasMore,
359106
+ cursor: lastItem?.receivedAt.toISOString()
359107
+ };
359108
+ }
359109
+ async getById(id) {
359110
+ const [result] = await this.db.select().from(omniEvents).where(eq(omniEvents.id, id)).limit(1);
359111
+ if (!result) {
359112
+ throw new NotFoundError("Event", id);
359113
+ }
359114
+ return result;
359115
+ }
359116
+ async trace(id) {
359117
+ const focus = await this.getById(id);
359118
+ const seen = new Set([focus.id]);
359119
+ const ancestors = [];
359120
+ let current = focus;
359121
+ let truncated = false;
359122
+ while (current.causationId && ancestors.length < TRACE_MAX_ANCESTORS) {
359123
+ if (seen.has(current.causationId))
359124
+ break;
359125
+ const [parent] = await this.db.select().from(omniEvents).where(eq(omniEvents.id, current.causationId)).limit(1);
359126
+ if (!parent)
359127
+ break;
359128
+ seen.add(parent.id);
359129
+ ancestors.unshift(parent);
359130
+ current = parent;
359131
+ }
359132
+ if (current.causationId && ancestors.length >= TRACE_MAX_ANCESTORS)
359133
+ truncated = true;
359134
+ const descendants = [];
359135
+ let frontier = [focus.id];
359136
+ let depth = 0;
359137
+ while (frontier.length > 0 && depth < TRACE_MAX_DEPTH && descendants.length < TRACE_MAX_NODES) {
359138
+ depth++;
359139
+ const children = await this.db.select().from(omniEvents).where(inArray(omniEvents.causationId, frontier)).orderBy(omniEvents.receivedAt).limit(TRACE_MAX_NODES + 1);
359140
+ const fresh = children.filter((c) => !seen.has(c.id));
359141
+ for (const child of fresh)
359142
+ seen.add(child.id);
359143
+ for (const child of fresh)
359144
+ descendants.push({ event: child, depth });
359145
+ if (descendants.length > TRACE_MAX_NODES) {
359146
+ descendants.length = TRACE_MAX_NODES;
359147
+ truncated = true;
359148
+ break;
359149
+ }
359150
+ frontier = fresh.map((c) => c.id);
359151
+ }
359152
+ if (frontier.length > 0 && depth >= TRACE_MAX_DEPTH)
359153
+ truncated = true;
359154
+ return { event: focus, ancestors, descendants, truncated };
359155
+ }
359156
+ async getTimeline(personId, options = {}) {
359157
+ const { channels, since, until, limit: limit2 = 50, cursor } = options;
359158
+ const conditions3 = [eq(omniEvents.personId, personId)];
359159
+ if (channels?.length) {
359160
+ conditions3.push(inArray(omniEvents.channel, channels));
359161
+ }
359162
+ if (since) {
359163
+ conditions3.push(gte(omniEvents.receivedAt, since));
359164
+ }
359165
+ if (until) {
359166
+ conditions3.push(lte(omniEvents.receivedAt, until));
359167
+ }
359168
+ if (cursor) {
359169
+ conditions3.push(sql`${omniEvents.receivedAt} < ${cursor}`);
359170
+ }
359171
+ const items = await this.db.select().from(omniEvents).where(and2(...conditions3)).orderBy(desc(omniEvents.receivedAt)).limit(limit2 + 1);
359172
+ const hasMore = items.length > limit2;
359173
+ if (hasMore) {
359174
+ items.pop();
359175
+ }
359176
+ const lastItem = items[items.length - 1];
359177
+ return {
359178
+ items,
359179
+ hasMore,
359180
+ cursor: lastItem?.receivedAt.toISOString()
359181
+ };
359182
+ }
359183
+ async getAnalytics(options = {}) {
359184
+ const { since, until, instanceId, granularity } = options;
359185
+ const conditions3 = [];
359186
+ if (since) {
359187
+ conditions3.push(gte(omniEvents.receivedAt, since));
359188
+ }
359189
+ if (until) {
359190
+ conditions3.push(lte(omniEvents.receivedAt, until));
359191
+ }
359192
+ if (instanceId) {
359193
+ conditions3.push(eq(omniEvents.instanceId, instanceId));
359194
+ }
359195
+ const whereClause = conditions3.length ? and2(...conditions3) : undefined;
359196
+ const countResults = await this.db.select({
359197
+ total: sql`count(*)::int`,
359198
+ successful: sql`count(*) filter (where ${omniEvents.status} = 'completed')::int`,
359199
+ failed: sql`count(*) filter (where ${omniEvents.status} = 'failed')::int`,
359200
+ avgProcessingTime: sql`avg(${omniEvents.processingTimeMs})::int`,
359201
+ avgAgentTime: sql`avg(${omniEvents.agentLatencyMs})::int`
359202
+ }).from(omniEvents).where(whereClause);
359203
+ const counts = countResults[0];
359204
+ const contentTypeCounts = await this.db.select({
359205
+ contentType: omniEvents.contentType,
359206
+ count: sql`count(*)::int`
359207
+ }).from(omniEvents).where(whereClause).groupBy(omniEvents.contentType);
359208
+ const errorStageCounts = await this.db.select({
359209
+ errorStage: omniEvents.errorStage,
359210
+ count: sql`count(*)::int`
359211
+ }).from(omniEvents).where(and2(whereClause, sql`${omniEvents.errorStage} is not null`)).groupBy(omniEvents.errorStage);
359212
+ const instanceCounts = await this.db.select({
359213
+ instanceId: omniEvents.instanceId,
359214
+ count: sql`count(*)::int`
359215
+ }).from(omniEvents).where(whereClause).groupBy(omniEvents.instanceId);
359216
+ const channelCounts = await this.db.select({
359217
+ channel: omniEvents.channel,
359218
+ count: sql`count(*)::int`
359219
+ }).from(omniEvents).where(whereClause).groupBy(omniEvents.channel);
359220
+ const directionCounts = await this.db.select({
359221
+ direction: omniEvents.direction,
359222
+ count: sql`count(*)::int`
359223
+ }).from(omniEvents).where(whereClause).groupBy(omniEvents.direction);
359224
+ const total = counts?.total ?? 0;
359225
+ const successful = counts?.successful ?? 0;
359226
+ const failed = counts?.failed ?? 0;
359227
+ let timeline;
359228
+ if (granularity) {
359229
+ const truncFunc = granularity === "hourly" ? "hour" : "day";
359230
+ const timelineCounts = await this.db.select({
359231
+ bucket: sql`date_trunc('${sql.raw(truncFunc)}', ${omniEvents.receivedAt})::text`,
359232
+ count: sql`count(*)::int`
359233
+ }).from(omniEvents).where(whereClause).groupBy(sql`date_trunc('${sql.raw(truncFunc)}', ${omniEvents.receivedAt})`).orderBy(sql`date_trunc('${sql.raw(truncFunc)}', ${omniEvents.receivedAt})`);
359234
+ timeline = timelineCounts.map((t) => ({ bucket: t.bucket, count: t.count }));
359235
+ }
359236
+ const inboundCount = directionCounts.find((d2) => d2.direction === "inbound")?.count ?? 0;
359237
+ const outboundCount = directionCounts.find((d2) => d2.direction === "outbound")?.count ?? 0;
359238
+ return {
359239
+ totalMessages: total,
359240
+ successfulMessages: successful,
359241
+ failedMessages: failed,
359242
+ successRate: total > 0 ? successful / total * 100 : 0,
359243
+ avgProcessingTimeMs: counts?.avgProcessingTime ?? null,
359244
+ avgAgentTimeMs: counts?.avgAgentTime ?? null,
359245
+ messageTypes: Object.fromEntries(contentTypeCounts.filter((c) => c.contentType != null).map((c) => [c.contentType, c.count])),
359246
+ errorStages: Object.fromEntries(errorStageCounts.filter((c) => c.errorStage != null).map((c) => [c.errorStage, c.count])),
359247
+ instances: Object.fromEntries(instanceCounts.filter((c) => c.instanceId != null).map((c) => [c.instanceId, c.count])),
359248
+ byChannel: Object.fromEntries(channelCounts.filter((c) => c.channel != null).map((c) => [c.channel, c.count])),
359249
+ byDirection: {
359250
+ inbound: inboundCount,
359251
+ outbound: outboundCount
359252
+ },
359253
+ timeline
359254
+ };
359255
+ }
359256
+ }
359257
+ var TRACE_MAX_ANCESTORS = 50, TRACE_MAX_DEPTH = 10, TRACE_MAX_NODES = 200;
359258
+ var init_events2 = __esm(() => {
359259
+ init_src();
359260
+ init_src5();
359261
+ init_drizzle_orm();
359262
+ init_tenant_scope();
359263
+ });
359264
+
359265
+ // ../api/src/services/event-consumers.ts
359266
+ function matchesConsumerPayload(row, filters) {
359267
+ if (!filters || filters.length === 0)
359268
+ return true;
359269
+ return evaluateConditions(filters, row.rawPayload ?? {});
359270
+ }
359271
+ function resolveInitialCursor(startFrom, head) {
359272
+ return startFrom === "beginning" ? 0 : head;
359273
+ }
359274
+ function computeLag(head, cursor) {
359275
+ return Math.max(0, head - cursor);
359276
+ }
359277
+
359278
+ class EventConsumerService {
359279
+ pool;
359280
+ eventBus;
359281
+ get db() {
359282
+ return scopedHandle(this.pool);
359283
+ }
359284
+ constructor(pool, eventBus = null) {
359285
+ this.pool = pool;
359286
+ this.eventBus = eventBus;
359287
+ }
359288
+ async head() {
359289
+ const [row] = await this.db.select({ head: sql`coalesce(max(${omniEvents.journalSeq}), 0)::bigint` }).from(omniEvents);
359290
+ return Number(row?.head ?? 0);
359291
+ }
359292
+ async list() {
359293
+ const [rows, head] = await Promise.all([
359294
+ this.db.select().from(durableConsumers).orderBy(asc(durableConsumers.name)),
359295
+ this.head()
359296
+ ]);
359297
+ return rows.map((row) => ({ ...row, head, lag: computeLag(head, row.cursor) }));
359298
+ }
359299
+ async getByName(name) {
359300
+ const [row] = await this.db.select().from(durableConsumers).where(eq(durableConsumers.name, name)).limit(1);
359301
+ if (!row)
359302
+ throw new NotFoundError("DurableConsumer", name);
359303
+ return row;
359304
+ }
359305
+ async inspect(name) {
359306
+ const row = await this.getByName(name);
359307
+ const head = await this.head();
359308
+ return { ...row, head, lag: computeLag(head, row.cursor) };
359309
+ }
359310
+ async create(input) {
359311
+ const head = await this.head();
359312
+ const cursor = resolveInitialCursor(input.startFrom ?? "now", head);
359313
+ const [created] = await this.db.insert(durableConsumers).values({ name: input.name, eventType: input.eventType, filters: input.filters ?? null, cursor }).onConflictDoNothing({ target: durableConsumers.name }).returning();
359314
+ if (!created) {
359315
+ throw new ConflictError("DurableConsumer", `a consumer named '${input.name}' already exists`, {
359316
+ name: input.name
359317
+ });
359318
+ }
359319
+ if (this.eventBus) {
359320
+ await this.eventBus.publishGeneric("system.consumer.created", {
359321
+ consumerId: created.id,
359322
+ name: created.name,
359323
+ eventType: created.eventType,
359324
+ cursor: created.cursor
359325
+ });
359326
+ }
359327
+ return { ...created, head, lag: computeLag(head, created.cursor) };
359328
+ }
359329
+ async delete(name) {
359330
+ const [deleted] = await this.db.delete(durableConsumers).where(eq(durableConsumers.name, name)).returning();
359331
+ if (!deleted)
359332
+ throw new NotFoundError("DurableConsumer", name);
359333
+ if (this.eventBus) {
359334
+ await this.eventBus.publishGeneric("system.consumer.deleted", {
359335
+ consumerId: deleted.id,
359336
+ name: deleted.name,
359337
+ eventType: deleted.eventType,
359338
+ cursor: deleted.cursor
359339
+ });
359340
+ }
359341
+ }
359342
+ async pull(name, options = {}) {
359343
+ const limit2 = Math.min(Math.max(options.limit ?? 100, 1), PULL_MAX_LIMIT);
359344
+ const waitMs = Math.min(Math.max(options.waitMs ?? 0, 0), PULL_MAX_WAIT_MS);
359345
+ const consumer = await this.getByName(name);
359346
+ const deadline = Date.now() + waitMs;
359347
+ let scanned = await this.scanPage(consumer, limit2);
359348
+ while (scanned.length === 0 && Date.now() < deadline) {
359349
+ await new Promise((resolve4) => setTimeout(resolve4, PULL_POLL_INTERVAL_MS));
359350
+ scanned = await this.scanPage(consumer, limit2);
359351
+ }
359352
+ const items = scanned.filter((row) => matchesConsumerPayload(row, consumer.filters));
359353
+ const last = scanned[scanned.length - 1];
359354
+ const head = await this.head();
359355
+ return {
359356
+ consumer: consumer.name,
359357
+ items,
359358
+ cursor: last ? Number(last.journalSeq) : consumer.cursor,
359359
+ head,
359360
+ hasMore: scanned.length === limit2
359361
+ };
359362
+ }
359363
+ async ack(name, cursor) {
359364
+ const [updated] = await this.db.update(durableConsumers).set({ cursor, updatedAt: new Date }).where(and2(eq(durableConsumers.name, name), lte(durableConsumers.cursor, cursor))).returning();
359365
+ if (!updated) {
359366
+ const existing = await this.getByName(name);
359367
+ throw new ValidationError2(`ack cursor ${cursor} is behind the stored cursor ${existing.cursor} \u2014 acks are monotonic`, undefined, { name, cursor, storedCursor: existing.cursor });
359368
+ }
359369
+ const head = await this.head();
359370
+ return { ...updated, head, lag: computeLag(head, updated.cursor) };
359371
+ }
359372
+ async scanPage(consumer, limit2) {
359373
+ const typeClause = consumer.eventType.endsWith("*") ? like(omniEvents.eventType, `${escapeLikePattern(consumer.eventType.slice(0, -1))}%`) : eq(omniEvents.eventType, consumer.eventType);
359374
+ return this.db.select().from(omniEvents).where(and2(gt(omniEvents.journalSeq, consumer.cursor), typeClause)).orderBy(asc(omniEvents.journalSeq)).limit(limit2);
359375
+ }
359376
+ }
359377
+ var PULL_POLL_INTERVAL_MS = 500, PULL_MAX_LIMIT = 500, PULL_MAX_WAIT_MS = 30000;
359378
+ var init_event_consumers = __esm(() => {
359379
+ init_src();
359380
+ init_src5();
359381
+ init_drizzle_orm();
359382
+ init_tenant_scope();
359383
+ init_events2();
359384
+ });
359385
+
359006
359386
  // ../api/src/services/event-ops.ts
359007
359387
  class EventOpsService {
359008
359388
  pool;
@@ -359396,244 +359776,6 @@ var init_event_schemas = __esm(() => {
359396
359776
  log101 = createLogger("api:event-schemas");
359397
359777
  });
359398
359778
 
359399
- // ../api/src/services/events.ts
359400
- function escapeLikePattern(value) {
359401
- return value.replace(/([\\%_])/g, "\\$1");
359402
- }
359403
-
359404
- class EventService {
359405
- pool;
359406
- get db() {
359407
- return scopedHandle(this.pool);
359408
- }
359409
- constructor(pool) {
359410
- this.pool = pool;
359411
- }
359412
- async list(options = {}) {
359413
- const {
359414
- channel: channel5,
359415
- instanceId,
359416
- personId,
359417
- eventType,
359418
- contentType,
359419
- direction,
359420
- since,
359421
- until,
359422
- search,
359423
- limit: limit2 = 50,
359424
- cursor
359425
- } = options;
359426
- const conditions3 = [];
359427
- if (channel5?.length) {
359428
- conditions3.push(inArray(omniEvents.channel, channel5));
359429
- }
359430
- if (instanceId) {
359431
- conditions3.push(eq(omniEvents.instanceId, instanceId));
359432
- } else if (options.instanceIds?.length) {
359433
- conditions3.push(inArray(omniEvents.instanceId, options.instanceIds));
359434
- }
359435
- if (personId) {
359436
- conditions3.push(eq(omniEvents.personId, personId));
359437
- }
359438
- if (eventType?.length) {
359439
- const exact = eventType.filter((t) => !t.endsWith("*"));
359440
- const prefixes = eventType.filter((t) => t.endsWith("*")).map((t) => t.slice(0, -1));
359441
- const typeClauses = [
359442
- ...exact.length ? [inArray(omniEvents.eventType, exact)] : [],
359443
- ...prefixes.map((p2) => like(omniEvents.eventType, `${escapeLikePattern(p2)}%`))
359444
- ];
359445
- const combined = typeClauses.length === 1 ? typeClauses[0] : or2(...typeClauses);
359446
- if (combined)
359447
- conditions3.push(combined);
359448
- }
359449
- if (contentType?.length) {
359450
- conditions3.push(inArray(omniEvents.contentType, contentType));
359451
- }
359452
- if (direction) {
359453
- conditions3.push(eq(omniEvents.direction, direction));
359454
- }
359455
- if (since) {
359456
- conditions3.push(gte(omniEvents.receivedAt, since));
359457
- }
359458
- if (until) {
359459
- conditions3.push(lte(omniEvents.receivedAt, until));
359460
- }
359461
- if (search) {
359462
- const searchPattern = `%${search}%`;
359463
- conditions3.push(or2(ilike(omniEvents.textContent, searchPattern), ilike(omniEvents.transcription, searchPattern), ilike(omniEvents.imageDescription, searchPattern)));
359464
- }
359465
- if (cursor) {
359466
- conditions3.push(sql`${omniEvents.receivedAt} < ${cursor}`);
359467
- }
359468
- const whereClause = conditions3.length ? and2(...conditions3) : undefined;
359469
- const items = await this.db.select().from(omniEvents).where(whereClause).orderBy(desc(omniEvents.receivedAt)).limit(limit2 + 1);
359470
- const hasMore = items.length > limit2;
359471
- if (hasMore) {
359472
- items.pop();
359473
- }
359474
- const lastItem = items[items.length - 1];
359475
- return {
359476
- items,
359477
- hasMore,
359478
- cursor: lastItem?.receivedAt.toISOString()
359479
- };
359480
- }
359481
- async getById(id) {
359482
- const [result] = await this.db.select().from(omniEvents).where(eq(omniEvents.id, id)).limit(1);
359483
- if (!result) {
359484
- throw new NotFoundError("Event", id);
359485
- }
359486
- return result;
359487
- }
359488
- async trace(id) {
359489
- const focus = await this.getById(id);
359490
- const seen = new Set([focus.id]);
359491
- const ancestors = [];
359492
- let current = focus;
359493
- let truncated = false;
359494
- while (current.causationId && ancestors.length < TRACE_MAX_ANCESTORS) {
359495
- if (seen.has(current.causationId))
359496
- break;
359497
- const [parent] = await this.db.select().from(omniEvents).where(eq(omniEvents.id, current.causationId)).limit(1);
359498
- if (!parent)
359499
- break;
359500
- seen.add(parent.id);
359501
- ancestors.unshift(parent);
359502
- current = parent;
359503
- }
359504
- if (current.causationId && ancestors.length >= TRACE_MAX_ANCESTORS)
359505
- truncated = true;
359506
- const descendants = [];
359507
- let frontier = [focus.id];
359508
- let depth = 0;
359509
- while (frontier.length > 0 && depth < TRACE_MAX_DEPTH && descendants.length < TRACE_MAX_NODES) {
359510
- depth++;
359511
- const children = await this.db.select().from(omniEvents).where(inArray(omniEvents.causationId, frontier)).orderBy(omniEvents.receivedAt).limit(TRACE_MAX_NODES + 1);
359512
- const fresh = children.filter((c) => !seen.has(c.id));
359513
- for (const child of fresh)
359514
- seen.add(child.id);
359515
- for (const child of fresh)
359516
- descendants.push({ event: child, depth });
359517
- if (descendants.length > TRACE_MAX_NODES) {
359518
- descendants.length = TRACE_MAX_NODES;
359519
- truncated = true;
359520
- break;
359521
- }
359522
- frontier = fresh.map((c) => c.id);
359523
- }
359524
- if (frontier.length > 0 && depth >= TRACE_MAX_DEPTH)
359525
- truncated = true;
359526
- return { event: focus, ancestors, descendants, truncated };
359527
- }
359528
- async getTimeline(personId, options = {}) {
359529
- const { channels, since, until, limit: limit2 = 50, cursor } = options;
359530
- const conditions3 = [eq(omniEvents.personId, personId)];
359531
- if (channels?.length) {
359532
- conditions3.push(inArray(omniEvents.channel, channels));
359533
- }
359534
- if (since) {
359535
- conditions3.push(gte(omniEvents.receivedAt, since));
359536
- }
359537
- if (until) {
359538
- conditions3.push(lte(omniEvents.receivedAt, until));
359539
- }
359540
- if (cursor) {
359541
- conditions3.push(sql`${omniEvents.receivedAt} < ${cursor}`);
359542
- }
359543
- const items = await this.db.select().from(omniEvents).where(and2(...conditions3)).orderBy(desc(omniEvents.receivedAt)).limit(limit2 + 1);
359544
- const hasMore = items.length > limit2;
359545
- if (hasMore) {
359546
- items.pop();
359547
- }
359548
- const lastItem = items[items.length - 1];
359549
- return {
359550
- items,
359551
- hasMore,
359552
- cursor: lastItem?.receivedAt.toISOString()
359553
- };
359554
- }
359555
- async getAnalytics(options = {}) {
359556
- const { since, until, instanceId, granularity } = options;
359557
- const conditions3 = [];
359558
- if (since) {
359559
- conditions3.push(gte(omniEvents.receivedAt, since));
359560
- }
359561
- if (until) {
359562
- conditions3.push(lte(omniEvents.receivedAt, until));
359563
- }
359564
- if (instanceId) {
359565
- conditions3.push(eq(omniEvents.instanceId, instanceId));
359566
- }
359567
- const whereClause = conditions3.length ? and2(...conditions3) : undefined;
359568
- const countResults = await this.db.select({
359569
- total: sql`count(*)::int`,
359570
- successful: sql`count(*) filter (where ${omniEvents.status} = 'completed')::int`,
359571
- failed: sql`count(*) filter (where ${omniEvents.status} = 'failed')::int`,
359572
- avgProcessingTime: sql`avg(${omniEvents.processingTimeMs})::int`,
359573
- avgAgentTime: sql`avg(${omniEvents.agentLatencyMs})::int`
359574
- }).from(omniEvents).where(whereClause);
359575
- const counts = countResults[0];
359576
- const contentTypeCounts = await this.db.select({
359577
- contentType: omniEvents.contentType,
359578
- count: sql`count(*)::int`
359579
- }).from(omniEvents).where(whereClause).groupBy(omniEvents.contentType);
359580
- const errorStageCounts = await this.db.select({
359581
- errorStage: omniEvents.errorStage,
359582
- count: sql`count(*)::int`
359583
- }).from(omniEvents).where(and2(whereClause, sql`${omniEvents.errorStage} is not null`)).groupBy(omniEvents.errorStage);
359584
- const instanceCounts = await this.db.select({
359585
- instanceId: omniEvents.instanceId,
359586
- count: sql`count(*)::int`
359587
- }).from(omniEvents).where(whereClause).groupBy(omniEvents.instanceId);
359588
- const channelCounts = await this.db.select({
359589
- channel: omniEvents.channel,
359590
- count: sql`count(*)::int`
359591
- }).from(omniEvents).where(whereClause).groupBy(omniEvents.channel);
359592
- const directionCounts = await this.db.select({
359593
- direction: omniEvents.direction,
359594
- count: sql`count(*)::int`
359595
- }).from(omniEvents).where(whereClause).groupBy(omniEvents.direction);
359596
- const total = counts?.total ?? 0;
359597
- const successful = counts?.successful ?? 0;
359598
- const failed = counts?.failed ?? 0;
359599
- let timeline;
359600
- if (granularity) {
359601
- const truncFunc = granularity === "hourly" ? "hour" : "day";
359602
- const timelineCounts = await this.db.select({
359603
- bucket: sql`date_trunc('${sql.raw(truncFunc)}', ${omniEvents.receivedAt})::text`,
359604
- count: sql`count(*)::int`
359605
- }).from(omniEvents).where(whereClause).groupBy(sql`date_trunc('${sql.raw(truncFunc)}', ${omniEvents.receivedAt})`).orderBy(sql`date_trunc('${sql.raw(truncFunc)}', ${omniEvents.receivedAt})`);
359606
- timeline = timelineCounts.map((t) => ({ bucket: t.bucket, count: t.count }));
359607
- }
359608
- const inboundCount = directionCounts.find((d2) => d2.direction === "inbound")?.count ?? 0;
359609
- const outboundCount = directionCounts.find((d2) => d2.direction === "outbound")?.count ?? 0;
359610
- return {
359611
- totalMessages: total,
359612
- successfulMessages: successful,
359613
- failedMessages: failed,
359614
- successRate: total > 0 ? successful / total * 100 : 0,
359615
- avgProcessingTimeMs: counts?.avgProcessingTime ?? null,
359616
- avgAgentTimeMs: counts?.avgAgentTime ?? null,
359617
- messageTypes: Object.fromEntries(contentTypeCounts.filter((c) => c.contentType != null).map((c) => [c.contentType, c.count])),
359618
- errorStages: Object.fromEntries(errorStageCounts.filter((c) => c.errorStage != null).map((c) => [c.errorStage, c.count])),
359619
- instances: Object.fromEntries(instanceCounts.filter((c) => c.instanceId != null).map((c) => [c.instanceId, c.count])),
359620
- byChannel: Object.fromEntries(channelCounts.filter((c) => c.channel != null).map((c) => [c.channel, c.count])),
359621
- byDirection: {
359622
- inbound: inboundCount,
359623
- outbound: outboundCount
359624
- },
359625
- timeline
359626
- };
359627
- }
359628
- }
359629
- var TRACE_MAX_ANCESTORS = 50, TRACE_MAX_DEPTH = 10, TRACE_MAX_NODES = 200;
359630
- var init_events2 = __esm(() => {
359631
- init_src();
359632
- init_src5();
359633
- init_drizzle_orm();
359634
- init_tenant_scope();
359635
- });
359636
-
359637
359779
  // ../api/src/lib/close-contact-state.ts
359638
359780
  function isChatInActiveCloseState(settings) {
359639
359781
  if (!settings)
@@ -364595,6 +364737,7 @@ function createServices(db2, eventBus) {
364595
364737
  payloadStore,
364596
364738
  eventOps,
364597
364739
  eventSchemas: eventSchemas2,
364740
+ eventConsumers: new EventConsumerService(db2, eventBus),
364598
364741
  webhooks: new WebhookService(db2, eventBus, eventSchemas2, deadLetters),
364599
364742
  automations: automationsService,
364600
364743
  manifestCompiler,
@@ -364650,6 +364793,7 @@ var init_services = __esm(() => {
364650
364793
  init_consumer_offsets();
364651
364794
  init_conversations();
364652
364795
  init_dead_letters();
364796
+ init_event_consumers();
364653
364797
  init_event_ops();
364654
364798
  init_event_schemas();
364655
364799
  init_events2();
@@ -368149,6 +368293,160 @@ var init_dead_letters2 = __esm(() => {
368149
368293
  });
368150
368294
  });
368151
368295
 
368296
+ // ../api/src/schemas/openapi/event-consumers.ts
368297
+ function registerEventConsumerSchemas(registry4) {
368298
+ registry4.register("DurableConsumer", DurableConsumerSchema);
368299
+ registry4.register("CreateConsumerRequest", CreateConsumerSchema);
368300
+ registry4.register("ConsumerPullResult", PullResultSchema);
368301
+ registry4.registerPath({
368302
+ method: "get",
368303
+ path: "/events/consumers",
368304
+ operationId: "listEventConsumers",
368305
+ tags: ["Events"],
368306
+ summary: "List durable event consumers",
368307
+ description: "Every registered durable consumer with its filter, cursor, and live lag (journal head minus cursor).",
368308
+ responses: {
368309
+ 200: {
368310
+ description: "Registered consumers",
368311
+ content: { "application/json": { schema: exports_external.object({ items: exports_external.array(DurableConsumerSchema) }) } }
368312
+ }
368313
+ }
368314
+ });
368315
+ registry4.registerPath({
368316
+ method: "post",
368317
+ path: "/events/consumers",
368318
+ operationId: "createEventConsumer",
368319
+ tags: ["Events"],
368320
+ summary: "Register a durable event consumer",
368321
+ description: "Registers a named consumer over the event journal: a type filter (trailing-* prefix glob, the events-wait " + "contract) plus optional payload conditions (the automation-trigger matcher), and a stored cursor. " + "startFrom 'now' (default) begins at the journal head; 'beginning' replays the full journal (projections).",
368322
+ request: { body: { content: { "application/json": { schema: CreateConsumerSchema } } } },
368323
+ responses: {
368324
+ 201: {
368325
+ description: "Consumer registered",
368326
+ content: { "application/json": { schema: exports_external.object({ data: DurableConsumerSchema }) } }
368327
+ },
368328
+ 409: {
368329
+ description: "A consumer with this name already exists",
368330
+ content: { "application/json": { schema: ErrorSchema } }
368331
+ }
368332
+ }
368333
+ });
368334
+ registry4.registerPath({
368335
+ method: "get",
368336
+ path: "/events/consumers/{name}",
368337
+ operationId: "getEventConsumer",
368338
+ tags: ["Events"],
368339
+ summary: "Inspect a durable event consumer",
368340
+ description: "The consumer registration plus its live cursor position and lag.",
368341
+ request: { params: exports_external.object({ name: exports_external.string().openapi({ description: "Consumer name" }) }) },
368342
+ responses: {
368343
+ 200: {
368344
+ description: "Consumer with live lag",
368345
+ content: { "application/json": { schema: exports_external.object({ data: DurableConsumerSchema }) } }
368346
+ },
368347
+ 404: { description: "No such consumer", content: { "application/json": { schema: ErrorSchema } } }
368348
+ }
368349
+ });
368350
+ registry4.registerPath({
368351
+ method: "delete",
368352
+ path: "/events/consumers/{name}",
368353
+ operationId: "deleteEventConsumer",
368354
+ tags: ["Events"],
368355
+ summary: "Delete a durable event consumer",
368356
+ description: "Removes the registration and its cursor. The journal itself is untouched.",
368357
+ request: { params: exports_external.object({ name: exports_external.string().openapi({ description: "Consumer name" }) }) },
368358
+ responses: {
368359
+ 200: {
368360
+ description: "Deleted",
368361
+ content: { "application/json": { schema: exports_external.object({ success: exports_external.boolean() }) } }
368362
+ },
368363
+ 404: { description: "No such consumer", content: { "application/json": { schema: ErrorSchema } } }
368364
+ }
368365
+ });
368366
+ registry4.registerPath({
368367
+ method: "post",
368368
+ path: "/events/consumers/{name}/pull",
368369
+ operationId: "pullEventConsumer",
368370
+ tags: ["Events"],
368371
+ summary: "Pull journal events from the stored cursor",
368372
+ description: "Pages journal events strictly after the stored cursor, in journal_seq order, pre-filtered by the type glob " + "and payload conditions. Does NOT advance the cursor \u2014 ack the returned cursor to commit progress " + "(at-least-once: a client that crashes mid-page re-pulls the same page). waitMs long-polls when no rows are available.",
368373
+ request: {
368374
+ params: exports_external.object({ name: exports_external.string().openapi({ description: "Consumer name" }) }),
368375
+ query: PullConsumerQuerySchema
368376
+ },
368377
+ responses: {
368378
+ 200: { description: "One page of events", content: { "application/json": { schema: PullResultSchema } } },
368379
+ 404: { description: "No such consumer", content: { "application/json": { schema: ErrorSchema } } }
368380
+ }
368381
+ });
368382
+ registry4.registerPath({
368383
+ method: "post",
368384
+ path: "/events/consumers/{name}/ack",
368385
+ operationId: "ackEventConsumer",
368386
+ tags: ["Events"],
368387
+ summary: "Advance the consumer cursor (monotonic)",
368388
+ description: "Commits progress up to a pull result's cursor. Monotonic: an ack equal to the stored cursor is an " + "idempotent no-op, an ack behind it is refused with 400 \u2014 a durable cursor never moves backwards.",
368389
+ request: {
368390
+ params: exports_external.object({ name: exports_external.string().openapi({ description: "Consumer name" }) }),
368391
+ body: { content: { "application/json": { schema: AckConsumerSchema } } }
368392
+ },
368393
+ responses: {
368394
+ 200: {
368395
+ description: "Cursor advanced (or already there)",
368396
+ content: { "application/json": { schema: exports_external.object({ data: DurableConsumerSchema }) } }
368397
+ },
368398
+ 400: { description: "Ack behind the stored cursor", content: { "application/json": { schema: ErrorSchema } } },
368399
+ 404: { description: "No such consumer", content: { "application/json": { schema: ErrorSchema } } }
368400
+ }
368401
+ });
368402
+ }
368403
+ var CONSUMER_NAME_PATTERN, ConsumerConditionSchema, DurableConsumerSchema, CreateConsumerSchema, PullConsumerQuerySchema, AckConsumerSchema, PullResultSchema;
368404
+ var init_event_consumers2 = __esm(() => {
368405
+ init_zod_openapi();
368406
+ init_common4();
368407
+ CONSUMER_NAME_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
368408
+ ConsumerConditionSchema = exports_external.object({
368409
+ field: exports_external.string().min(1).max(500).openapi({ description: "Dot-notation path into the event's rawPayload (e.g. user.id)" }),
368410
+ operator: exports_external.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "not_contains", "exists", "not_exists", "regex"]).openapi({ description: "Comparison operator (same matcher as automation trigger conditions)" }),
368411
+ value: exports_external.unknown().optional().openapi({ description: "Comparison value. Ignored for 'exists'/'not_exists'" })
368412
+ });
368413
+ DurableConsumerSchema = exports_external.object({
368414
+ id: exports_external.string().uuid().openapi({ description: "Consumer UUID" }),
368415
+ name: exports_external.string().openapi({ description: "Unique consumer name (the follow/ack handle)" }),
368416
+ eventType: exports_external.string().openapi({ description: "Type filter: exact event type or trailing-* prefix glob" }),
368417
+ filters: exports_external.array(ConsumerConditionSchema).nullable().openapi({ description: "Payload conditions (AND), or null" }),
368418
+ cursor: exports_external.number().int().openapi({ description: "Last acked journal_seq; delivery resumes strictly after it" }),
368419
+ head: exports_external.number().int().openapi({ description: "Highest journal_seq currently in the journal" }),
368420
+ lag: exports_external.number().int().openapi({ description: "head - cursor (all journal rows past the cursor, not only matches)" }),
368421
+ createdAt: exports_external.string().datetime().openapi({ description: "Creation timestamp" }),
368422
+ updatedAt: exports_external.string().datetime().openapi({ description: "Last cursor/registry update timestamp" })
368423
+ });
368424
+ CreateConsumerSchema = exports_external.object({
368425
+ name: exports_external.string().min(1).max(100).regex(CONSUMER_NAME_PATTERN, "Consumer name must be lowercase tokens: a-z 0-9 . _ - (starting alphanumeric)").openapi({ description: "Unique consumer name (e.g. deploy-tracker)" }),
368426
+ eventType: exports_external.string().min(1).max(255).openapi({ description: "Type filter: exact event type, or trailing-* prefix glob (e.g. custom.github.*)" }),
368427
+ filters: exports_external.array(ConsumerConditionSchema).max(20).optional().openapi({ description: "Payload conditions (AND) \u2014 same matcher as events wait --filter" }),
368428
+ startFrom: exports_external.enum(["now", "beginning"]).optional().openapi({ description: "Initial cursor: 'now' = journal head (default), 'beginning' = full replay" })
368429
+ });
368430
+ PullConsumerQuerySchema = exports_external.object({
368431
+ limit: exports_external.coerce.number().int().min(1).max(500).optional().openapi({ description: "Max journal rows to scan (default 100)" }),
368432
+ waitMs: exports_external.coerce.number().int().min(0).max(30000).optional().openapi({ description: "Long-poll: wait up to this long when no rows are available (default 0)" })
368433
+ });
368434
+ AckConsumerSchema = exports_external.object({
368435
+ cursor: exports_external.coerce.number().int().min(0).openapi({
368436
+ description: `The journal_seq to advance to (a pull result's "cursor"). Monotonic: equal = no-op, lower = 400`
368437
+ })
368438
+ });
368439
+ PullResultSchema = exports_external.object({
368440
+ consumer: exports_external.string().openapi({ description: "Consumer name" }),
368441
+ items: exports_external.array(exports_external.record(exports_external.string(), exports_external.unknown())).openapi({ description: "Matching journal rows, ascending journal_seq" }),
368442
+ cursor: exports_external.number().int().openapi({
368443
+ description: "Highest journal_seq SCANNED (not merely matched) \u2014 ack this value to advance past filtered-out rows"
368444
+ }),
368445
+ head: exports_external.number().int().openapi({ description: "Journal head at pull time" }),
368446
+ hasMore: exports_external.boolean().openapi({ description: "True when the scan filled the page \u2014 more rows are already waiting" })
368447
+ });
368448
+ });
368449
+
368152
368450
  // ../api/src/schemas/openapi/event-ops.ts
368153
368451
  function registerEventOpsSchemas(registry4) {
368154
368452
  registry4.register("ReplayOptions", ReplayOptionsSchema);
@@ -371898,6 +372196,7 @@ var init_openapi2 = __esm(() => {
371898
372196
  init_common4();
371899
372197
  init_conversations2();
371900
372198
  init_dead_letters2();
372199
+ init_event_consumers2();
371901
372200
  init_event_ops2();
371902
372201
  init_event_schemas2();
371903
372202
  init_events3();
@@ -371935,6 +372234,7 @@ var init_openapi2 = __esm(() => {
371935
372234
  registerDeadLetterSchemas(registry4);
371936
372235
  registerEventOpsSchemas(registry4);
371937
372236
  registerEventSchemaSchemas(registry4);
372237
+ registerEventConsumerSchemas(registry4);
371938
372238
  registerMetricsSchemas(registry4);
371939
372239
  registerAutomationSchemas(registry4);
371940
372240
  registerPayloadSchemas(registry4);
@@ -374727,6 +375027,52 @@ var init_dead_letters3 = __esm(() => {
374727
375027
  });
374728
375028
  });
374729
375029
 
375030
+ // ../api/src/routes/v2/event-consumers.ts
375031
+ var eventConsumersRoutes;
375032
+ var init_event_consumers3 = __esm(() => {
375033
+ init_dist6();
375034
+ init_dist2();
375035
+ init_event_consumers2();
375036
+ eventConsumersRoutes = new Hono2;
375037
+ eventConsumersRoutes.get("/events/consumers", async (c) => {
375038
+ const services = c.get("services");
375039
+ const items = await services.eventConsumers.list();
375040
+ return c.json({ items });
375041
+ });
375042
+ eventConsumersRoutes.post("/events/consumers", zValidator("json", CreateConsumerSchema), async (c) => {
375043
+ const input = c.req.valid("json");
375044
+ const services = c.get("services");
375045
+ const data = await services.eventConsumers.create(input);
375046
+ return c.json({ data }, 201);
375047
+ });
375048
+ eventConsumersRoutes.get("/events/consumers/:name", async (c) => {
375049
+ const name = c.req.param("name");
375050
+ const services = c.get("services");
375051
+ const data = await services.eventConsumers.inspect(name);
375052
+ return c.json({ data });
375053
+ });
375054
+ eventConsumersRoutes.delete("/events/consumers/:name", async (c) => {
375055
+ const name = c.req.param("name");
375056
+ const services = c.get("services");
375057
+ await services.eventConsumers.delete(name);
375058
+ return c.json({ success: true });
375059
+ });
375060
+ eventConsumersRoutes.post("/events/consumers/:name/pull", zValidator("query", PullConsumerQuerySchema), async (c) => {
375061
+ const name = c.req.param("name");
375062
+ const { limit: limit2, waitMs } = c.req.valid("query");
375063
+ const services = c.get("services");
375064
+ const result = await services.eventConsumers.pull(name, { limit: limit2, waitMs });
375065
+ return c.json(result);
375066
+ });
375067
+ eventConsumersRoutes.post("/events/consumers/:name/ack", zValidator("json", AckConsumerSchema), async (c) => {
375068
+ const name = c.req.param("name");
375069
+ const { cursor } = c.req.valid("json");
375070
+ const services = c.get("services");
375071
+ const data = await services.eventConsumers.ack(name, cursor);
375072
+ return c.json({ data });
375073
+ });
375074
+ });
375075
+
374730
375076
  // ../api/src/routes/v2/event-ops.ts
374731
375077
  var eventOpsRoutes, replayOptionsSchema;
374732
375078
  var init_event_ops3 = __esm(() => {
@@ -385027,6 +385373,7 @@ var init_v2 = __esm(() => {
385027
385373
  init_context5();
385028
385374
  init_conversations3();
385029
385375
  init_dead_letters3();
385376
+ init_event_consumers3();
385030
385377
  init_event_ops3();
385031
385378
  init_event_schemas3();
385032
385379
  init_events4();
@@ -385065,6 +385412,7 @@ var init_v2 = __esm(() => {
385065
385412
  v2Routes.route("/scheduled-messages", scheduledMessagesRoutes);
385066
385413
  v2Routes.route("/slack", slackRoutes);
385067
385414
  v2Routes.route("/", eventSchemasRoutes);
385415
+ v2Routes.route("/", eventConsumersRoutes);
385068
385416
  v2Routes.route("/events", eventsRoutes);
385069
385417
  v2Routes.route("/journeys", journeysRoutes);
385070
385418
  v2Routes.route("/persons", personsRoutes);