@classytic/crm 0.5.0 → 0.7.0

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,130 @@
2
2
 
3
3
  All notable changes to `@classytic/crm` are documented here.
4
4
 
5
+ ## [0.7.0] — 2026-07-05
6
+
7
+ ### Added — org-wide email suppression list
8
+
9
+ - **`Suppression` entity** (`crm.repositories.suppression`, model
10
+ `Suppression`): global per-org "never email this address again" list —
11
+ the gate hosts consult before EVERY outbound email. Unsubscribes on
12
+ `Subscription` stay per-campaign; suppression is org-wide.
13
+ - `suppress(email, { reason, source?, subjectKind?, subjectId?, metadata? }, ctx?)`
14
+ — idempotent `getOrCreate` on the unique `(organizationId, email)`
15
+ index (no check-then-save); emits `crm:suppression.added` only when
16
+ THIS call inserted the row.
17
+ - `isSuppressed(email, ctx?)` → boolean.
18
+ - `filterSuppressed(emails, ctx?)` → `Set<string>` of the suppressed
19
+ subset — ONE `$in` query for the campaign-fanout hot path.
20
+ - `unsuppress(email, ctx?)` — atomic delete; emits
21
+ `crm:suppression.removed` only when a row was actually removed.
22
+ - All verbs normalize emails (trim + lowercase; schema stores lowercase).
23
+ - **`SUPPRESSION_REASONS`** (`'bounce' | 'complaint' | 'unsubscribe' |
24
+ 'manual'`) — the first three `satisfies readonly EmailEventKind[]` (P6),
25
+ so a rename in `EMAIL_EVENT_KINDS` fails compilation here.
26
+ - **Events** `crm:suppression.added` / `crm:suppression.removed` — Zod
27
+ catalog definitions included (no-drift invariant stays green);
28
+ `organizationId` rides event meta as usual.
29
+ - **Validators** `suppressSchema` / `unsuppressSchema` /
30
+ `suppressionFilterSchema`.
31
+
32
+ ### Added — reply-detection exit verb
33
+
34
+ - **`EnrollmentRepository.exitActiveOnReply(subjects, ctx?)`** — the ONE
35
+ method a host's `crm:message.received` subscriber calls: finds ACTIVE
36
+ enrollments for the given `{ subjectKind, subjectId }` list, batch-loads
37
+ their sequences in a single `$in` query, skips those with
38
+ `replyDetectionEnabled === false`, and exits the rest via `exit(id,
39
+ 'reply')` (each exit emits `crm:enrollment.exited`). Lost CAS races
40
+ (concurrent pause/complete/exit) are skipped, not failed. Returns the
41
+ enrollments this call exited.
42
+ - `EnrollmentRepositoryDeps` now carries `sequences: SequenceRepository`
43
+ (same cross-repo deps idiom as `OpportunityRepository.pipelines` /
44
+ `MessageRepository.conversations`) — wired automatically by
45
+ `createCrm()`; only hosts constructing `EnrollmentRepository` by hand
46
+ need to pass it.
47
+
48
+ ## [0.6.0] — 2026-07-02
49
+
50
+ Breaking-in-behavior release (ships as MINOR per house convention):
51
+ outbox-first, session-safe event dispatch — the previously deferred
52
+ PACKAGE_RULES §P8/§P8.1 work.
53
+
54
+ ### Added — unit-of-work contract (P8.1, shared with refit/review/cart/invoice)
55
+
56
+ - **`engine.withTransaction(ctx, body)`** — runs `body` inside a MongoDB
57
+ transaction with post-commit event discipline: events dispatched through
58
+ `txCtx` are queued under `ctx[PENDING_EVENTS]` and flushed to the
59
+ transport only AFTER commit; the queue resets on retry attempts; an abort
60
+ leaks nothing to in-process subscribers. Reuses the caller's session (and
61
+ queue) when `ctx.session` is already set. Standalone-Mongo dev boots opt
62
+ in via the existing `allowNonTransactional: true`.
63
+ - **`PENDING_EVENTS`** (`Symbol.for('@classytic/crm:pendingEvents')`) +
64
+ **`flushPending(transport, queue, logger?)`** + **`runUnit`** exported
65
+ from the root for hosts composing their own outer transaction.
66
+ - **`CrmConfig.outbox?: OutboxStore`** (from `@classytic/primitives/outbox`)
67
+ — when wired, every domain event is persisted via
68
+ `outbox.save(event, { session })` in the SAME session as the business
69
+ write; the host's relay publishes committed rows. Outbox save failures
70
+ PROPAGATE (P8: a swallowed save means the write persists while its event
71
+ vanishes).
72
+ - **`CrmEventDispatcher`** — EventTransport-compatible wrapper repositories
73
+ route every event through (`engine.events` is now this wrapper; the host
74
+ `publish`/`subscribe` surface is unchanged).
75
+ - **`UnmanagedSessionError`** (`code: 'UNMANAGED_SESSION'`) — a host-owned
76
+ `ctx.session` arriving with neither an outbox nor a `PENDING_EVENTS`
77
+ queue now throws instead of ghost-publishing mid-transaction.
78
+ **Behavioral break:** callers that previously threaded a bare session and
79
+ tolerated ghost events must switch to `engine.withTransaction` (or wire
80
+ an outbox / attach a queue).
81
+
82
+ ### Added — timezone-aware forecasting
83
+
84
+ - **`ForecastOptions.timeZone`** — IANA zone for the default month bucket
85
+ (e.g. `'Asia/Dhaka'`). Without it, months cut at UTC boundaries: a deal
86
+ expected to close July 1, 02:00 Dhaka time (June 30, 20:00 UTC) files
87
+ under JUNE. Uses `civilDateOf` from `@classytic/primitives/timezone`.
88
+ Peer floor bumped: `@classytic/primitives >=0.9.0`.
89
+
90
+ ### Fixed — sequence/enrollment (completes the 0.6.0 WIP)
91
+
92
+ - **Event catalog no-drift restored**: 10 missing Zod definitions added
93
+ (`crm:sequence.{created,active,paused,archived}`,
94
+ `crm:enrollment.{created,step_sent,paused,resumed,completed,exited}`) —
95
+ `crm:sequence.created` and `crm:enrollment.step_sent` are host-emitted
96
+ (create via `def.create()`), the rest publish in-repo.
97
+ - **`EnrollmentRepository.setWorkflowRunId` / `advanceStep` no longer
98
+ bypass the repository**: both used raw `model.findOneAndUpdate` with a
99
+ manual tenant filter — escaping `multiTenantPlugin` scoping AND
100
+ `ctx.session` (a call inside `withTransaction` would commit outside the
101
+ transaction). `advanceStep` is now a `claim()` CAS on `currentStepIndex`
102
+ with `where: { status: 'active' }`; `setWorkflowRunId` goes through
103
+ `repo.update`.
104
+
105
+ ### Tests
106
+
107
+ - 14 new: `tests/unit/dispatch.test.ts` (6 — outbox propagation/session
108
+ routing/guard/swallow), `tests/integration/unit-of-work.test.ts` (3 —
109
+ convert() on a replica set: zero mid-tx events, post-commit flush, abort
110
+ leaks nothing, bare-session guard), `tests/unit/forecast-timezone.test.ts`
111
+ (5 — the +06:00 month-boundary trap). 110/110 total.
112
+
113
+ ## [0.5.1] — 2026-06-14
114
+
115
+ ### Fixed — declaration bundle
116
+
117
+ - **fix: declaration bundle exported mangled aliases; consumer named imports
118
+ now resolve.** The published `dist/index.d.ts` re-exported every public
119
+ symbol under a minified alias (`export { AccountRepository as A, CRM_EVENTS
120
+ as Rr, … }`), so downstream `import { AccountRepository, CRM_EVENTS } from
121
+ '@classytic/crm'` failed with TS2305 / TS2460. Root cause: the `./events`
122
+ entry re-exports a strict subset of the `index` barrel, which made
123
+ `rolldown-plugin-dts` alias every name on the superset (`index`) entry when
124
+ both were emitted in a single pass. Build now runs `index` and `events` as
125
+ two independent tsdown passes (array config) so each `.d.ts` exports real
126
+ names. `tsdown` bumped `^0.14.2` → `^0.21.10` to match sibling packages.
127
+ No runtime/API change.
128
+
5
129
  ## [0.5.0] — 2026-06-14
6
130
 
7
131
  Stack upgrade + verified correctness fixes + PACKAGE_RULES compliance. No
package/dist/events.d.ts CHANGED
@@ -1,2 +1,475 @@
1
- import { $n as ContactUpdated, Ar as PipelineArchived, Bn as ActivityOutcomeRecorded, Cr as OpportunityAssigned, Dr as OpportunityStageAdvanced, Er as OpportunityLost, Fn as AccountEnriched, Fr as SubscriptionCreated, Gn as CampaignCompleted, Hn as ActivityRescheduled, In as AccountMerged, Ir as SubscriptionUnsubscribed, Jn as CampaignResumed, Kn as CampaignCreated, Ln as AccountUpdated, Lr as crmEventDefinitions, Mr as SubscriptionBounced, Nn as AccountAssigned, Nr as SubscriptionComplained, Or as OpportunityStageRegressed, Pn as AccountCreated, Pr as SubscriptionConfirmed, Qn as ContactMerged, Rn as ActivityCancelled, Rr as CRM_EVENTS, Sr as OpportunityAmountChanged, Tr as OpportunityExtended, Un as CampaignActivated, Vn as ActivityPlanned, Wn as CampaignArchived, Xn as ContactCreated, Yn as ContactAssigned, Zn as ContactEnriched, _r as LeadStatusChanged, ar as CrmEventSchema, br as NoteAdded, cr as EmailEventComplained, dr as LeadAssigned, er as ConversationAssigned, fr as LeadConverted, gr as LeadScored, hr as LeadEnriched, ir as CrmEventDefinition, jr as PipelineCreated, kr as OpportunityWon, lr as EmailEventOpened, mr as LeadDisqualified, n as createEvent, nr as ConversationReopened, or as EmailEventBounced, pr as LeadCreated, qn as CampaignPaused, rr as ConversationResolved, sr as EmailEventClicked, t as InProcessCrmBus, tr as ConversationCreated, ur as EmailEventUnsubscribed, vr as MessageReceived, wr as OpportunityCreated, xr as OpportunityAbandoned, yr as MessageSent, zn as ActivityCompleted, zr as CrmEventName } from "./index.js";
2
- export { AccountAssigned, AccountCreated, AccountEnriched, AccountMerged, AccountUpdated, ActivityCancelled, ActivityCompleted, ActivityOutcomeRecorded, ActivityPlanned, ActivityRescheduled, CRM_EVENTS, CampaignActivated, CampaignArchived, CampaignCompleted, CampaignCreated, CampaignPaused, CampaignResumed, ContactAssigned, ContactCreated, ContactEnriched, ContactMerged, ContactUpdated, ConversationAssigned, ConversationCreated, ConversationReopened, ConversationResolved, CrmEventDefinition, CrmEventName, CrmEventSchema, EmailEventBounced, EmailEventClicked, EmailEventComplained, EmailEventOpened, EmailEventUnsubscribed, InProcessCrmBus, LeadAssigned, LeadConverted, LeadCreated, LeadDisqualified, LeadEnriched, LeadScored, LeadStatusChanged, MessageReceived, MessageSent, NoteAdded, OpportunityAbandoned, OpportunityAmountChanged, OpportunityAssigned, OpportunityCreated, OpportunityExtended, OpportunityLost, OpportunityStageAdvanced, OpportunityStageRegressed, OpportunityWon, PipelineArchived, PipelineCreated, SubscriptionBounced, SubscriptionComplained, SubscriptionConfirmed, SubscriptionCreated, SubscriptionUnsubscribed, createEvent, crmEventDefinitions };
1
+ import { z } from "zod";
2
+ import { DomainEvent, EventHandler, EventMeta, EventTransport } from "@classytic/primitives/events";
3
+ import * as _$mongoose from "mongoose";
4
+ import { OperationContext } from "@classytic/primitives/context";
5
+ //#region src/events/event-constants.d.ts
6
+ /** PACKAGE_RULES rule 12: `package:resource.verb`. */
7
+ declare const CRM_EVENTS: {
8
+ readonly LEAD_CREATED: "crm:lead.created";
9
+ readonly LEAD_STATUS_CHANGED: "crm:lead.status_changed";
10
+ readonly LEAD_SCORED: "crm:lead.scored";
11
+ readonly LEAD_CONVERTED: "crm:lead.converted";
12
+ readonly LEAD_DISQUALIFIED: "crm:lead.disqualified";
13
+ readonly ACCOUNT_CREATED: "crm:account.created";
14
+ readonly ACCOUNT_UPDATED: "crm:account.updated";
15
+ readonly CONTACT_CREATED: "crm:contact.created";
16
+ readonly CONTACT_UPDATED: "crm:contact.updated";
17
+ readonly OPPORTUNITY_CREATED: "crm:opportunity.created";
18
+ readonly OPPORTUNITY_STAGE_ADVANCED: "crm:opportunity.stage_advanced";
19
+ readonly OPPORTUNITY_STAGE_REGRESSED: "crm:opportunity.stage_regressed";
20
+ readonly OPPORTUNITY_WON: "crm:opportunity.won";
21
+ readonly OPPORTUNITY_LOST: "crm:opportunity.lost";
22
+ readonly OPPORTUNITY_ABANDONED: "crm:opportunity.abandoned";
23
+ readonly PIPELINE_CREATED: "crm:pipeline.created";
24
+ readonly PIPELINE_ARCHIVED: "crm:pipeline.archived";
25
+ readonly ACTIVITY_PLANNED: "crm:activity.planned";
26
+ readonly ACTIVITY_COMPLETED: "crm:activity.completed";
27
+ readonly ACTIVITY_CANCELLED: "crm:activity.cancelled";
28
+ readonly NOTE_ADDED: "crm:note.added";
29
+ readonly CAMPAIGN_CREATED: "crm:campaign.created";
30
+ readonly CAMPAIGN_ACTIVATED: "crm:campaign.activated";
31
+ readonly CAMPAIGN_PAUSED: "crm:campaign.paused";
32
+ readonly CAMPAIGN_RESUMED: "crm:campaign.resumed";
33
+ readonly CAMPAIGN_COMPLETED: "crm:campaign.completed";
34
+ readonly CAMPAIGN_ARCHIVED: "crm:campaign.archived";
35
+ readonly SUBSCRIPTION_CREATED: "crm:subscription.created";
36
+ readonly SUBSCRIPTION_CONFIRMED: "crm:subscription.confirmed";
37
+ readonly SUBSCRIPTION_UNSUBSCRIBED: "crm:subscription.unsubscribed";
38
+ readonly SUBSCRIPTION_BOUNCED: "crm:subscription.bounced";
39
+ readonly SUBSCRIPTION_COMPLAINED: "crm:subscription.complained";
40
+ readonly SEQUENCE_CREATED: "crm:sequence.created";
41
+ readonly SEQUENCE_ACTIVATED: "crm:sequence.active";
42
+ readonly SEQUENCE_PAUSED: "crm:sequence.paused";
43
+ readonly SEQUENCE_ARCHIVED: "crm:sequence.archived";
44
+ readonly ENROLLMENT_CREATED: "crm:enrollment.created";
45
+ readonly ENROLLMENT_STEP_SENT: "crm:enrollment.step_sent";
46
+ readonly ENROLLMENT_PAUSED: "crm:enrollment.paused";
47
+ readonly ENROLLMENT_RESUMED: "crm:enrollment.resumed";
48
+ readonly ENROLLMENT_COMPLETED: "crm:enrollment.completed";
49
+ readonly ENROLLMENT_EXITED: "crm:enrollment.exited";
50
+ readonly EMAIL_EVENT_OPENED: "crm:email_event.opened";
51
+ readonly EMAIL_EVENT_CLICKED: "crm:email_event.clicked";
52
+ readonly EMAIL_EVENT_BOUNCED: "crm:email_event.bounced";
53
+ readonly EMAIL_EVENT_COMPLAINED: "crm:email_event.complained";
54
+ readonly EMAIL_EVENT_UNSUBSCRIBED: "crm:email_event.unsubscribed";
55
+ readonly LEAD_ENRICHED: "crm:lead.enriched";
56
+ readonly LEAD_ASSIGNED: "crm:lead.assigned";
57
+ readonly CONTACT_ENRICHED: "crm:contact.enriched";
58
+ readonly CONTACT_ASSIGNED: "crm:contact.assigned";
59
+ readonly CONTACT_MERGED: "crm:contact.merged";
60
+ readonly ACCOUNT_ENRICHED: "crm:account.enriched";
61
+ readonly ACCOUNT_ASSIGNED: "crm:account.assigned";
62
+ readonly ACCOUNT_MERGED: "crm:account.merged";
63
+ readonly OPPORTUNITY_ASSIGNED: "crm:opportunity.assigned";
64
+ readonly OPPORTUNITY_AMOUNT_CHANGED: "crm:opportunity.amount_changed";
65
+ readonly OPPORTUNITY_EXTENDED: "crm:opportunity.extended";
66
+ readonly ACTIVITY_RESCHEDULED: "crm:activity.rescheduled";
67
+ readonly ACTIVITY_OUTCOME_RECORDED: "crm:activity.outcome_recorded";
68
+ readonly SUPPRESSION_ADDED: "crm:suppression.added";
69
+ readonly SUPPRESSION_REMOVED: "crm:suppression.removed";
70
+ readonly CONVERSATION_CREATED: "crm:conversation.created";
71
+ readonly CONVERSATION_ASSIGNED: "crm:conversation.assigned";
72
+ readonly CONVERSATION_RESOLVED: "crm:conversation.resolved";
73
+ readonly CONVERSATION_REOPENED: "crm:conversation.reopened";
74
+ readonly MESSAGE_RECEIVED: "crm:message.received";
75
+ readonly MESSAGE_SENT: "crm:message.sent";
76
+ };
77
+ type CrmEventName = (typeof CRM_EVENTS)[keyof typeof CRM_EVENTS];
78
+ //#endregion
79
+ //#region src/events/event-catalog.d.ts
80
+ /** JSON-Schema object produced by `z.toJSONSchema` — what arc's registry consumes. */
81
+ type CrmEventSchema = Record<string, unknown>;
82
+ /** Structurally identical to arc's `EventDefinitionOutput` — do NOT import arc. */
83
+ interface CrmEventDefinition<TSchema extends z.ZodType = z.ZodType> {
84
+ name: CrmEventName;
85
+ version: number;
86
+ description: string;
87
+ zodSchema: TSchema;
88
+ schema: CrmEventSchema;
89
+ create(payload: z.infer<TSchema>, meta?: Partial<EventMeta>): DomainEvent<z.infer<TSchema>>;
90
+ }
91
+ declare const LeadCreated: CrmEventDefinition<z.ZodObject<{
92
+ leadId: z.ZodString;
93
+ email: z.ZodOptional<z.ZodString>;
94
+ score: z.ZodNumber;
95
+ }, z.core.$strip>>;
96
+ declare const LeadStatusChanged: CrmEventDefinition<z.ZodObject<{
97
+ leadId: z.ZodString;
98
+ from: z.ZodString;
99
+ to: z.ZodString;
100
+ }, z.core.$strip>>;
101
+ declare const LeadScored: CrmEventDefinition<z.ZodObject<{
102
+ leadId: z.ZodString;
103
+ score: z.ZodNumber;
104
+ }, z.core.$strip>>;
105
+ declare const LeadConverted: CrmEventDefinition<z.ZodObject<{
106
+ leadId: z.ZodString;
107
+ contactId: z.ZodString;
108
+ accountId: z.ZodOptional<z.ZodString>;
109
+ opportunityId: z.ZodString;
110
+ }, z.core.$strip>>;
111
+ declare const LeadDisqualified: CrmEventDefinition<z.ZodObject<{
112
+ leadId: z.ZodString;
113
+ reason: z.ZodString;
114
+ }, z.core.$strip>>;
115
+ declare const LeadEnriched: CrmEventDefinition<z.ZodObject<{
116
+ leadId: z.ZodString;
117
+ fields: z.ZodArray<z.ZodString>;
118
+ provider: z.ZodOptional<z.ZodString>;
119
+ }, z.core.$strip>>;
120
+ declare const LeadAssigned: CrmEventDefinition<z.ZodObject<{
121
+ leadId: z.ZodString;
122
+ ownerId: z.ZodString;
123
+ previousOwnerId: z.ZodOptional<z.ZodString>;
124
+ }, z.core.$strip>>;
125
+ declare const AccountCreated: CrmEventDefinition<z.ZodObject<{
126
+ accountId: z.ZodString;
127
+ name: z.ZodString;
128
+ }, z.core.$strip>>;
129
+ declare const AccountUpdated: CrmEventDefinition<z.ZodObject<{
130
+ accountId: z.ZodString;
131
+ }, z.core.$strip>>;
132
+ declare const AccountEnriched: CrmEventDefinition<z.ZodObject<{
133
+ accountId: z.ZodString;
134
+ fields: z.ZodArray<z.ZodString>;
135
+ provider: z.ZodOptional<z.ZodString>;
136
+ }, z.core.$strip>>;
137
+ declare const AccountAssigned: CrmEventDefinition<z.ZodObject<{
138
+ accountId: z.ZodString;
139
+ ownerId: z.ZodString;
140
+ previousOwnerId: z.ZodOptional<z.ZodString>;
141
+ }, z.core.$strip>>;
142
+ declare const AccountMerged: CrmEventDefinition<z.ZodObject<{
143
+ primaryId: z.ZodString;
144
+ secondaryId: z.ZodString;
145
+ strategy: z.ZodEnum<{
146
+ preferPrimary: "preferPrimary";
147
+ preferSecondary: "preferSecondary";
148
+ }>;
149
+ }, z.core.$strip>>;
150
+ declare const ContactCreated: CrmEventDefinition<z.ZodObject<{
151
+ contactId: z.ZodString;
152
+ email: z.ZodOptional<z.ZodString>;
153
+ }, z.core.$strip>>;
154
+ declare const ContactUpdated: CrmEventDefinition<z.ZodObject<{
155
+ contactId: z.ZodString;
156
+ }, z.core.$strip>>;
157
+ declare const ContactEnriched: CrmEventDefinition<z.ZodObject<{
158
+ contactId: z.ZodString;
159
+ fields: z.ZodArray<z.ZodString>;
160
+ provider: z.ZodOptional<z.ZodString>;
161
+ }, z.core.$strip>>;
162
+ declare const ContactAssigned: CrmEventDefinition<z.ZodObject<{
163
+ contactId: z.ZodString;
164
+ ownerId: z.ZodString;
165
+ previousOwnerId: z.ZodOptional<z.ZodString>;
166
+ }, z.core.$strip>>;
167
+ declare const ContactMerged: CrmEventDefinition<z.ZodObject<{
168
+ primaryId: z.ZodString;
169
+ secondaryId: z.ZodString;
170
+ strategy: z.ZodEnum<{
171
+ preferPrimary: "preferPrimary";
172
+ preferSecondary: "preferSecondary";
173
+ }>;
174
+ }, z.core.$strip>>;
175
+ declare const OpportunityCreated: CrmEventDefinition<z.ZodObject<{
176
+ opportunityId: z.ZodString;
177
+ pipelineId: z.ZodString;
178
+ stageId: z.ZodString;
179
+ }, z.core.$strip>>;
180
+ declare const OpportunityStageAdvanced: CrmEventDefinition<z.ZodObject<{
181
+ opportunityId: z.ZodString;
182
+ from: z.ZodObject<{
183
+ stageId: z.ZodString;
184
+ sequence: z.ZodNumber;
185
+ }, z.core.$strip>;
186
+ to: z.ZodObject<{
187
+ stageId: z.ZodString;
188
+ sequence: z.ZodNumber;
189
+ }, z.core.$strip>;
190
+ }, z.core.$strip>>;
191
+ declare const OpportunityStageRegressed: CrmEventDefinition<z.ZodObject<{
192
+ opportunityId: z.ZodString;
193
+ from: z.ZodObject<{
194
+ stageId: z.ZodString;
195
+ sequence: z.ZodNumber;
196
+ }, z.core.$strip>;
197
+ to: z.ZodObject<{
198
+ stageId: z.ZodString;
199
+ sequence: z.ZodNumber;
200
+ }, z.core.$strip>;
201
+ }, z.core.$strip>>;
202
+ declare const OpportunityWon: CrmEventDefinition<z.ZodObject<{
203
+ opportunityId: z.ZodString;
204
+ amount: z.ZodOptional<z.ZodNumber>;
205
+ }, z.core.$strip>>;
206
+ declare const OpportunityLost: CrmEventDefinition<z.ZodObject<{
207
+ opportunityId: z.ZodString;
208
+ lostReasonId: z.ZodOptional<z.ZodString>;
209
+ }, z.core.$strip>>;
210
+ declare const OpportunityAbandoned: CrmEventDefinition<z.ZodObject<{
211
+ opportunityId: z.ZodString;
212
+ }, z.core.$strip>>;
213
+ declare const OpportunityAssigned: CrmEventDefinition<z.ZodObject<{
214
+ opportunityId: z.ZodString;
215
+ ownerId: z.ZodString;
216
+ previousOwnerId: z.ZodOptional<z.ZodString>;
217
+ }, z.core.$strip>>;
218
+ declare const OpportunityAmountChanged: CrmEventDefinition<z.ZodObject<{
219
+ opportunityId: z.ZodString;
220
+ amount: z.ZodNumber;
221
+ previousAmount: z.ZodOptional<z.ZodNumber>;
222
+ reason: z.ZodOptional<z.ZodString>;
223
+ by: z.ZodOptional<z.ZodString>;
224
+ }, z.core.$strip>>;
225
+ declare const OpportunityExtended: CrmEventDefinition<z.ZodObject<{
226
+ opportunityId: z.ZodString;
227
+ expectedCloseAt: z.ZodISODateTime;
228
+ previousExpectedCloseAt: z.ZodOptional<z.ZodISODateTime>;
229
+ reason: z.ZodOptional<z.ZodString>;
230
+ by: z.ZodOptional<z.ZodString>;
231
+ }, z.core.$strip>>;
232
+ declare const PipelineCreated: CrmEventDefinition<z.ZodObject<{
233
+ pipelineId: z.ZodString;
234
+ }, z.core.$strip>>;
235
+ declare const PipelineArchived: CrmEventDefinition<z.ZodObject<{
236
+ pipelineId: z.ZodString;
237
+ }, z.core.$strip>>;
238
+ declare const ActivityPlanned: CrmEventDefinition<z.ZodObject<{
239
+ activityId: z.ZodString;
240
+ type: z.ZodString;
241
+ subjectKind: z.ZodString;
242
+ subjectId: z.ZodString;
243
+ }, z.core.$strip>>;
244
+ declare const ActivityCompleted: CrmEventDefinition<z.ZodObject<{
245
+ activityId: z.ZodString;
246
+ completedAt: z.ZodISODateTime;
247
+ }, z.core.$strip>>;
248
+ declare const ActivityCancelled: CrmEventDefinition<z.ZodObject<{
249
+ activityId: z.ZodString;
250
+ reason: z.ZodOptional<z.ZodString>;
251
+ }, z.core.$strip>>;
252
+ declare const ActivityRescheduled: CrmEventDefinition<z.ZodObject<{
253
+ activityId: z.ZodString;
254
+ dueDate: z.ZodISODateTime;
255
+ previousDueDate: z.ZodOptional<z.ZodISODateTime>;
256
+ reason: z.ZodOptional<z.ZodString>;
257
+ by: z.ZodOptional<z.ZodString>;
258
+ }, z.core.$strip>>;
259
+ declare const ActivityOutcomeRecorded: CrmEventDefinition<z.ZodObject<{
260
+ activityId: z.ZodString;
261
+ outcome: z.ZodRecord<z.ZodString, z.ZodUnknown>;
262
+ }, z.core.$strip>>;
263
+ declare const NoteAdded: CrmEventDefinition<z.ZodObject<{
264
+ noteId: z.ZodString;
265
+ subjectKind: z.ZodString;
266
+ subjectId: z.ZodString;
267
+ }, z.core.$strip>>;
268
+ declare const CampaignCreated: CrmEventDefinition<z.ZodObject<{
269
+ campaignId: z.ZodString;
270
+ name: z.ZodString;
271
+ }, z.core.$strip>>;
272
+ declare const CampaignActivated: CrmEventDefinition<z.ZodObject<{
273
+ campaignId: z.ZodString;
274
+ }, z.core.$strip>>;
275
+ declare const CampaignPaused: CrmEventDefinition<z.ZodObject<{
276
+ campaignId: z.ZodString;
277
+ reason: z.ZodOptional<z.ZodString>;
278
+ }, z.core.$strip>>;
279
+ declare const CampaignResumed: CrmEventDefinition<z.ZodObject<{
280
+ campaignId: z.ZodString;
281
+ }, z.core.$strip>>;
282
+ declare const CampaignCompleted: CrmEventDefinition<z.ZodObject<{
283
+ campaignId: z.ZodString;
284
+ actualRevenueAmount: z.ZodOptional<z.ZodNumber>;
285
+ }, z.core.$strip>>;
286
+ declare const CampaignArchived: CrmEventDefinition<z.ZodObject<{
287
+ campaignId: z.ZodString;
288
+ }, z.core.$strip>>;
289
+ declare const SubscriptionCreated: CrmEventDefinition<z.ZodObject<{
290
+ subscriptionId: z.ZodString;
291
+ contactId: z.ZodString;
292
+ campaignId: z.ZodString;
293
+ requiresConfirmation: z.ZodBoolean;
294
+ }, z.core.$strip>>;
295
+ declare const SubscriptionConfirmed: CrmEventDefinition<z.ZodObject<{
296
+ subscriptionId: z.ZodString;
297
+ contactId: z.ZodString;
298
+ campaignId: z.ZodString;
299
+ confirmedAt: z.ZodISODateTime;
300
+ }, z.core.$strip>>;
301
+ declare const SubscriptionUnsubscribed: CrmEventDefinition<z.ZodObject<{
302
+ subscriptionId: z.ZodString;
303
+ contactId: z.ZodString;
304
+ campaignId: z.ZodString;
305
+ reason: z.ZodOptional<z.ZodString>;
306
+ }, z.core.$strip>>;
307
+ declare const SubscriptionBounced: CrmEventDefinition<z.ZodObject<{
308
+ subscriptionId: z.ZodString;
309
+ contactId: z.ZodString;
310
+ campaignId: z.ZodString;
311
+ reason: z.ZodOptional<z.ZodString>;
312
+ }, z.core.$strip>>;
313
+ declare const SubscriptionComplained: CrmEventDefinition<z.ZodObject<{
314
+ subscriptionId: z.ZodString;
315
+ contactId: z.ZodString;
316
+ campaignId: z.ZodString;
317
+ }, z.core.$strip>>;
318
+ declare const SuppressionAdded: CrmEventDefinition<z.ZodObject<{
319
+ email: z.ZodString;
320
+ reason: z.ZodEnum<{
321
+ bounce: "bounce";
322
+ complaint: "complaint";
323
+ unsubscribe: "unsubscribe";
324
+ manual: "manual";
325
+ }>;
326
+ source: z.ZodOptional<z.ZodString>;
327
+ }, z.core.$strip>>;
328
+ declare const SuppressionRemoved: CrmEventDefinition<z.ZodObject<{
329
+ email: z.ZodString;
330
+ }, z.core.$strip>>;
331
+ declare const EmailEventOpened: CrmEventDefinition<z.ZodObject<{
332
+ eventId: z.ZodString;
333
+ kind: z.ZodString;
334
+ subjectKind: z.ZodString;
335
+ subjectId: z.ZodString;
336
+ campaignId: z.ZodOptional<z.ZodString>;
337
+ }, z.core.$strip>>;
338
+ declare const EmailEventClicked: CrmEventDefinition<z.ZodObject<{
339
+ eventId: z.ZodString;
340
+ kind: z.ZodString;
341
+ subjectKind: z.ZodString;
342
+ subjectId: z.ZodString;
343
+ campaignId: z.ZodOptional<z.ZodString>;
344
+ }, z.core.$strip>>;
345
+ declare const EmailEventBounced: CrmEventDefinition<z.ZodObject<{
346
+ eventId: z.ZodString;
347
+ kind: z.ZodString;
348
+ subjectKind: z.ZodString;
349
+ subjectId: z.ZodString;
350
+ campaignId: z.ZodOptional<z.ZodString>;
351
+ }, z.core.$strip>>;
352
+ declare const EmailEventComplained: CrmEventDefinition<z.ZodObject<{
353
+ eventId: z.ZodString;
354
+ kind: z.ZodString;
355
+ subjectKind: z.ZodString;
356
+ subjectId: z.ZodString;
357
+ campaignId: z.ZodOptional<z.ZodString>;
358
+ }, z.core.$strip>>;
359
+ declare const EmailEventUnsubscribed: CrmEventDefinition<z.ZodObject<{
360
+ eventId: z.ZodString;
361
+ kind: z.ZodString;
362
+ subjectKind: z.ZodString;
363
+ subjectId: z.ZodString;
364
+ campaignId: z.ZodOptional<z.ZodString>;
365
+ }, z.core.$strip>>;
366
+ declare const ConversationCreated: CrmEventDefinition<z.ZodObject<{
367
+ conversationId: z.ZodString;
368
+ channel: z.ZodString;
369
+ participantKind: z.ZodString;
370
+ participantId: z.ZodString;
371
+ }, z.core.$strip>>;
372
+ declare const ConversationAssigned: CrmEventDefinition<z.ZodObject<{
373
+ conversationId: z.ZodString;
374
+ assigneeId: z.ZodString;
375
+ previousAssigneeId: z.ZodOptional<z.ZodString>;
376
+ }, z.core.$strip>>;
377
+ declare const ConversationResolved: CrmEventDefinition<z.ZodObject<{
378
+ conversationId: z.ZodString;
379
+ status: z.ZodString;
380
+ previousStatus: z.ZodString;
381
+ }, z.core.$strip>>;
382
+ declare const ConversationReopened: CrmEventDefinition<z.ZodObject<{
383
+ conversationId: z.ZodString;
384
+ status: z.ZodString;
385
+ previousStatus: z.ZodString;
386
+ }, z.core.$strip>>;
387
+ declare const MessageReceived: CrmEventDefinition<z.ZodObject<{
388
+ messageId: z.ZodString;
389
+ conversationId: z.ZodString;
390
+ direction: z.ZodString;
391
+ externalMessageId: z.ZodOptional<z.ZodString>;
392
+ }, z.core.$strip>>;
393
+ declare const MessageSent: CrmEventDefinition<z.ZodObject<{
394
+ messageId: z.ZodString;
395
+ conversationId: z.ZodString;
396
+ direction: z.ZodString;
397
+ externalMessageId: z.ZodOptional<z.ZodString>;
398
+ }, z.core.$strip>>;
399
+ declare const SequenceCreated: CrmEventDefinition<z.ZodObject<{
400
+ sequenceId: z.ZodString;
401
+ name: z.ZodOptional<z.ZodString>;
402
+ }, z.core.$strip>>;
403
+ declare const SequenceActivated: CrmEventDefinition<z.ZodObject<{
404
+ sequenceId: z.ZodString;
405
+ }, z.core.$strip>>;
406
+ declare const SequencePaused: CrmEventDefinition<z.ZodObject<{
407
+ sequenceId: z.ZodString;
408
+ }, z.core.$strip>>;
409
+ declare const SequenceArchived: CrmEventDefinition<z.ZodObject<{
410
+ sequenceId: z.ZodString;
411
+ }, z.core.$strip>>;
412
+ declare const EnrollmentCreated: CrmEventDefinition<z.ZodObject<{
413
+ enrollmentId: z.ZodString;
414
+ sequenceId: z.ZodString;
415
+ subjectId: z.ZodString;
416
+ subjectKind: z.ZodString;
417
+ }, z.core.$strip>>;
418
+ declare const EnrollmentStepSent: CrmEventDefinition<z.ZodObject<{
419
+ enrollmentId: z.ZodString;
420
+ sequenceId: z.ZodOptional<z.ZodString>;
421
+ stepIndex: z.ZodNumber;
422
+ channel: z.ZodOptional<z.ZodString>;
423
+ }, z.core.$strip>>;
424
+ declare const EnrollmentPaused: CrmEventDefinition<z.ZodObject<{
425
+ enrollmentId: z.ZodString;
426
+ }, z.core.$strip>>;
427
+ declare const EnrollmentResumed: CrmEventDefinition<z.ZodObject<{
428
+ enrollmentId: z.ZodString;
429
+ }, z.core.$strip>>;
430
+ declare const EnrollmentCompleted: CrmEventDefinition<z.ZodObject<{
431
+ enrollmentId: z.ZodString;
432
+ }, z.core.$strip>>;
433
+ declare const EnrollmentExited: CrmEventDefinition<z.ZodObject<{
434
+ enrollmentId: z.ZodString;
435
+ exitReason: z.ZodOptional<z.ZodString>;
436
+ }, z.core.$strip>>;
437
+ declare const crmEventDefinitions: ReadonlyArray<CrmEventDefinition>;
438
+ //#endregion
439
+ //#region src/engine/engine-types.d.ts
440
+ interface CrmLogger {
441
+ info?(msg: string, meta?: Record<string, unknown>): void;
442
+ warn?(msg: string, meta?: Record<string, unknown>): void;
443
+ error?(msg: string, meta?: Record<string, unknown>): void;
444
+ debug?(msg: string, meta?: Record<string, unknown>): void;
445
+ }
446
+ /**
447
+ * Operation context threaded through every domain verb. Extends
448
+ * primitives' `OperationContext` and narrows `IdLike` to types Mongoose
449
+ * stores cleanly. Host-specific extras go through the inherited
450
+ * `metadata?` field — keep the typed surface tight.
451
+ */
452
+ interface CrmContext extends OperationContext {
453
+ organizationId?: string | _$mongoose.Types.ObjectId;
454
+ actorId?: string | _$mongoose.Types.ObjectId;
455
+ /** Mongo transaction session (passed through to mongokit). */
456
+ session?: unknown;
457
+ }
458
+ //#endregion
459
+ //#region src/events/helpers.d.ts
460
+ declare function createEvent<T>(type: string, payload: T, ctx?: CrmContext, meta?: Partial<EventMeta>): DomainEvent<T>;
461
+ //#endregion
462
+ //#region src/events/in-process-bus.d.ts
463
+ declare class InProcessCrmBus implements EventTransport {
464
+ readonly name = "in-process-crm";
465
+ private subs;
466
+ private logger?;
467
+ constructor(options?: {
468
+ logger?: CrmLogger;
469
+ });
470
+ publish(event: DomainEvent): Promise<void>;
471
+ subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
472
+ close(): Promise<void>;
473
+ }
474
+ //#endregion
475
+ export { AccountAssigned, AccountCreated, AccountEnriched, AccountMerged, AccountUpdated, ActivityCancelled, ActivityCompleted, ActivityOutcomeRecorded, ActivityPlanned, ActivityRescheduled, CRM_EVENTS, CampaignActivated, CampaignArchived, CampaignCompleted, CampaignCreated, CampaignPaused, CampaignResumed, ContactAssigned, ContactCreated, ContactEnriched, ContactMerged, ContactUpdated, ConversationAssigned, ConversationCreated, ConversationReopened, ConversationResolved, CrmEventDefinition, CrmEventName, CrmEventSchema, EmailEventBounced, EmailEventClicked, EmailEventComplained, EmailEventOpened, EmailEventUnsubscribed, EnrollmentCompleted, EnrollmentCreated, EnrollmentExited, EnrollmentPaused, EnrollmentResumed, EnrollmentStepSent, InProcessCrmBus, LeadAssigned, LeadConverted, LeadCreated, LeadDisqualified, LeadEnriched, LeadScored, LeadStatusChanged, MessageReceived, MessageSent, NoteAdded, OpportunityAbandoned, OpportunityAmountChanged, OpportunityAssigned, OpportunityCreated, OpportunityExtended, OpportunityLost, OpportunityStageAdvanced, OpportunityStageRegressed, OpportunityWon, PipelineArchived, PipelineCreated, SequenceActivated, SequenceArchived, SequenceCreated, SequencePaused, SubscriptionBounced, SubscriptionComplained, SubscriptionConfirmed, SubscriptionCreated, SubscriptionUnsubscribed, SuppressionAdded, SuppressionRemoved, createEvent, crmEventDefinitions };