@classytic/crm 0.3.0 → 0.5.1

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/dist/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { t as __exportAll } from "./chunk.js";
2
- import * as mongoose0 from "mongoose";
1
+ import * as _$mongoose from "mongoose";
3
2
  import { Connection, Model, Schema, SchemaDefinitionProperty } from "mongoose";
4
3
  import { PaginationConfig, PluginType, Repository } from "@classytic/mongokit";
5
4
  import { DomainEvent, EventHandler, EventMeta, EventTransport } from "@classytic/primitives/events";
6
- import * as _classytic_primitives_state_machine0 from "@classytic/primitives/state-machine";
5
+ import * as _$_classytic_primitives_state_machine0 from "@classytic/primitives/state-machine";
7
6
  import { z } from "zod";
8
7
  import { StatusChangeEntry, StatusHistory, appendStatus, lastTransitionTo, latestEntry, timeInStatus } from "@classytic/primitives/status-history";
9
8
  import { OperationContext } from "@classytic/primitives/context";
@@ -23,7 +22,7 @@ declare function tenantFieldDef(config: SchemaBuildConfig): SchemaDefinitionProp
23
22
  //#region src/models/pipeline.schema.d.ts
24
23
  /** Mongoose document shape for a single embedded stage. */
25
24
  interface IStageDocument {
26
- _id: mongoose0.Types.ObjectId;
25
+ _id: _$mongoose.Types.ObjectId;
27
26
  name: string;
28
27
  /** Ascending order in the pipeline. Treated as identifier on `moveToStage`. */
29
28
  sequence: number;
@@ -34,8 +33,8 @@ interface IStageDocument {
34
33
  }
35
34
  /** Mongoose document shape for a Pipeline. */
36
35
  interface IPipelineDocument {
37
- _id: mongoose0.Types.ObjectId;
38
- organizationId: mongoose0.Types.ObjectId | string;
36
+ _id: _$mongoose.Types.ObjectId;
37
+ organizationId: _$mongoose.Types.ObjectId | string;
39
38
  name: string;
40
39
  /** Deprecates the pipeline — existing opps still move, no new ones created. */
41
40
  isArchived: boolean;
@@ -74,8 +73,8 @@ interface ILeadStatusEntry {
74
73
  note?: string;
75
74
  }
76
75
  interface ILeadDocument {
77
- _id: mongoose0.Types.ObjectId;
78
- organizationId: mongoose0.Types.ObjectId | string;
76
+ _id: _$mongoose.Types.ObjectId;
77
+ organizationId: _$mongoose.Types.ObjectId | string;
79
78
  fullName: string;
80
79
  firstName?: string;
81
80
  lastName?: string;
@@ -90,9 +89,9 @@ interface ILeadDocument {
90
89
  statusHistory: ILeadStatusEntry[];
91
90
  ownerId?: string;
92
91
  tags: string[];
93
- convertedContactId?: mongoose0.Types.ObjectId | string;
94
- convertedAccountId?: mongoose0.Types.ObjectId | string;
95
- convertedOpportunityId?: mongoose0.Types.ObjectId | string;
92
+ convertedContactId?: _$mongoose.Types.ObjectId | string;
93
+ convertedAccountId?: _$mongoose.Types.ObjectId | string;
94
+ convertedOpportunityId?: _$mongoose.Types.ObjectId | string;
96
95
  convertedAt?: Date;
97
96
  disqualifyReason?: string;
98
97
  metadata?: Record<string, unknown>;
@@ -124,12 +123,12 @@ interface IOpportunityStatusEntry {
124
123
  note?: string;
125
124
  }
126
125
  interface IOpportunityDocument {
127
- _id: mongoose0.Types.ObjectId;
128
- organizationId: mongoose0.Types.ObjectId | string;
126
+ _id: _$mongoose.Types.ObjectId;
127
+ organizationId: _$mongoose.Types.ObjectId | string;
129
128
  name: string;
130
- accountId?: mongoose0.Types.ObjectId | string;
131
- primaryContactId?: mongoose0.Types.ObjectId | string;
132
- pipelineId: mongoose0.Types.ObjectId | string;
129
+ accountId?: _$mongoose.Types.ObjectId | string;
130
+ primaryContactId?: _$mongoose.Types.ObjectId | string;
131
+ pipelineId: _$mongoose.Types.ObjectId | string;
133
132
  stageId: string;
134
133
  status: OpportunityStatus;
135
134
  statusHistory: IOpportunityStatusEntry[];
@@ -138,9 +137,9 @@ interface IOpportunityDocument {
138
137
  probability: number;
139
138
  expectedCloseAt?: Date;
140
139
  closedAt?: Date;
141
- lostReasonId?: mongoose0.Types.ObjectId | string;
140
+ lostReasonId?: _$mongoose.Types.ObjectId | string;
142
141
  ownerId?: string;
143
- sourceLeadId?: mongoose0.Types.ObjectId | string;
142
+ sourceLeadId?: _$mongoose.Types.ObjectId | string;
144
143
  tags: string[];
145
144
  metadata?: Record<string, unknown>;
146
145
  createdAt: Date;
@@ -163,14 +162,18 @@ interface IContactInfoEmbedded {
163
162
  personalEmail?: string;
164
163
  phone?: string;
165
164
  alternatePhone?: string;
165
+ whatsapp?: string;
166
+ telegram?: string;
167
+ linkedin?: string;
168
+ instagram?: string;
166
169
  }
167
170
  interface IContactDocument {
168
- _id: mongoose0.Types.ObjectId;
169
- organizationId: mongoose0.Types.ObjectId | string;
171
+ _id: _$mongoose.Types.ObjectId;
172
+ organizationId: _$mongoose.Types.ObjectId | string;
170
173
  name: IContactName;
171
174
  contact: IContactInfoEmbedded;
172
175
  jobTitle?: string;
173
- accountId?: mongoose0.Types.ObjectId | string;
176
+ accountId?: _$mongoose.Types.ObjectId | string;
174
177
  ownerId?: string;
175
178
  tags: string[];
176
179
  metadata?: Record<string, unknown>;
@@ -182,8 +185,8 @@ declare function createContactModel(connection: Connection, config: SchemaBuildC
182
185
  //#endregion
183
186
  //#region src/models/account.schema.d.ts
184
187
  interface IAccountDocument {
185
- _id: mongoose0.Types.ObjectId;
186
- organizationId: mongoose0.Types.ObjectId | string;
188
+ _id: _$mongoose.Types.ObjectId;
189
+ organizationId: _$mongoose.Types.ObjectId | string;
187
190
  name: string;
188
191
  domain?: string;
189
192
  industry?: string;
@@ -222,8 +225,8 @@ interface ICampaignStatusEntry {
222
225
  note?: string;
223
226
  }
224
227
  interface ICampaignDocument {
225
- _id: mongoose0.Types.ObjectId;
226
- organizationId: mongoose0.Types.ObjectId | string;
228
+ _id: _$mongoose.Types.ObjectId;
229
+ organizationId: _$mongoose.Types.ObjectId | string;
227
230
  name: string;
228
231
  description?: string;
229
232
  status: CampaignStatus;
@@ -273,10 +276,10 @@ interface ISubscriptionStatusEntry {
273
276
  note?: string;
274
277
  }
275
278
  interface ISubscriptionDocument {
276
- _id: mongoose0.Types.ObjectId;
277
- organizationId: mongoose0.Types.ObjectId | string;
278
- contactId: mongoose0.Types.ObjectId | string;
279
- campaignId: mongoose0.Types.ObjectId | string;
279
+ _id: _$mongoose.Types.ObjectId;
280
+ organizationId: _$mongoose.Types.ObjectId | string;
281
+ contactId: _$mongoose.Types.ObjectId | string;
282
+ campaignId: _$mongoose.Types.ObjectId | string;
280
283
  status: SubscriptionStatus;
281
284
  statusHistory: ISubscriptionStatusEntry[];
282
285
  source?: string;
@@ -321,12 +324,12 @@ type SubjectKind = (typeof SUBJECT_KINDS)[number];
321
324
  //#endregion
322
325
  //#region src/models/activity.schema.d.ts
323
326
  interface IActivityDocument {
324
- _id: mongoose0.Types.ObjectId;
325
- organizationId: mongoose0.Types.ObjectId | string;
327
+ _id: _$mongoose.Types.ObjectId;
328
+ organizationId: _$mongoose.Types.ObjectId | string;
326
329
  type: ActivityType;
327
330
  status: ActivityStatus;
328
331
  subjectKind: SubjectKind;
329
- subjectId: mongoose0.Types.ObjectId | string;
332
+ subjectId: _$mongoose.Types.ObjectId | string;
330
333
  title: string;
331
334
  description?: string;
332
335
  ownerId?: string;
@@ -343,10 +346,10 @@ declare function createActivityModel(connection: Connection, config: SchemaBuild
343
346
  //#endregion
344
347
  //#region src/models/note.schema.d.ts
345
348
  interface INoteDocument {
346
- _id: mongoose0.Types.ObjectId;
347
- organizationId: mongoose0.Types.ObjectId | string;
349
+ _id: _$mongoose.Types.ObjectId;
350
+ organizationId: _$mongoose.Types.ObjectId | string;
348
351
  subjectKind: SubjectKind;
349
- subjectId: mongoose0.Types.ObjectId | string;
352
+ subjectId: _$mongoose.Types.ObjectId | string;
350
353
  body: string;
351
354
  authorId?: string;
352
355
  pinned: boolean;
@@ -359,8 +362,8 @@ declare function createNoteModel(connection: Connection, config: SchemaBuildConf
359
362
  //#endregion
360
363
  //#region src/models/loss-reason.schema.d.ts
361
364
  interface ILossReasonDocument {
362
- _id: mongoose0.Types.ObjectId;
363
- organizationId: mongoose0.Types.ObjectId | string;
365
+ _id: _$mongoose.Types.ObjectId;
366
+ organizationId: _$mongoose.Types.ObjectId | string;
364
367
  name: string;
365
368
  description?: string;
366
369
  isActive: boolean;
@@ -402,18 +405,17 @@ declare function createLossReasonModel(connection: Connection, config: SchemaBui
402
405
  */
403
406
  declare const EMAIL_EVENT_KINDS: readonly ["open", "click", "bounce", "complaint", "unsubscribe"];
404
407
  type EmailEventKind = (typeof EMAIL_EVENT_KINDS)[number];
405
- /** Engagement (positive signal). */
406
408
  //#endregion
407
409
  //#region src/models/email-event.schema.d.ts
408
410
  declare const EMAIL_EVENT_SUBJECT_KINDS: readonly ["contact", "subscription"];
409
411
  type EmailEventSubjectKind = (typeof EMAIL_EVENT_SUBJECT_KINDS)[number];
410
412
  interface IEmailEventDocument {
411
- _id: mongoose0.Types.ObjectId;
412
- organizationId: mongoose0.Types.ObjectId | string;
413
+ _id: _$mongoose.Types.ObjectId;
414
+ organizationId: _$mongoose.Types.ObjectId | string;
413
415
  kind: EmailEventKind;
414
416
  subjectKind: EmailEventSubjectKind;
415
- subjectId: mongoose0.Types.ObjectId | string;
416
- campaignId?: mongoose0.Types.ObjectId | string;
417
+ subjectId: _$mongoose.Types.ObjectId | string;
418
+ campaignId?: _$mongoose.Types.ObjectId | string;
417
419
  messageId?: string;
418
420
  url?: string;
419
421
  userAgent?: string;
@@ -424,6 +426,82 @@ interface IEmailEventDocument {
424
426
  declare function buildEmailEventSchema(config: SchemaBuildConfig): Schema<IEmailEventDocument>;
425
427
  declare function createEmailEventModel(connection: Connection, config: SchemaBuildConfig): Model<IEmailEventDocument>;
426
428
  //#endregion
429
+ //#region src/enums/conversation.d.ts
430
+ /**
431
+ * Conversation / Message vocabulary.
432
+ *
433
+ * Conversations unify a contact's (or pre-conversion lead's) message
434
+ * thread across channels (WhatsApp / Telegram / Email / IG-DM / SMS).
435
+ * The host's webhook adapters write to this surface — the CRM does not
436
+ * dial outward.
437
+ */
438
+ declare const CONVERSATION_CHANNELS: readonly ["whatsapp", "telegram", "email", "instagram_dm", "sms", "web_chat"];
439
+ type ConversationChannel = (typeof CONVERSATION_CHANNELS)[number];
440
+ declare const CONVERSATION_STATUSES: readonly ["open", "snoozed", "resolved"];
441
+ type ConversationStatus = (typeof CONVERSATION_STATUSES)[number];
442
+ /** Conversations attach to either a Contact or a (yet-unconverted) Lead. */
443
+ declare const CONVERSATION_PARTICIPANT_KINDS: readonly ["contact", "lead"];
444
+ type ConversationParticipantKind = (typeof CONVERSATION_PARTICIPANT_KINDS)[number];
445
+ declare const MESSAGE_DIRECTIONS: readonly ["inbound", "outbound"];
446
+ type MessageDirection = (typeof MESSAGE_DIRECTIONS)[number];
447
+ declare const MESSAGE_DELIVERY_STATUSES: readonly ["queued", "sent", "delivered", "read", "failed"];
448
+ type MessageDeliveryStatus = (typeof MESSAGE_DELIVERY_STATUSES)[number];
449
+ //#endregion
450
+ //#region src/models/conversation.schema.d.ts
451
+ interface IConversationDocument {
452
+ _id: _$mongoose.Types.ObjectId;
453
+ organizationId: _$mongoose.Types.ObjectId | string;
454
+ channel: ConversationChannel;
455
+ participantKind: ConversationParticipantKind;
456
+ participantId: _$mongoose.Types.ObjectId | string;
457
+ /** Channel-side identifier (e.g. WhatsApp wa_id, Telegram chat id). */
458
+ channelUserId?: string;
459
+ status: ConversationStatus;
460
+ /** Last message timestamp — surfaced for inbox sort + idle SLAs. */
461
+ lastMessageAt?: Date;
462
+ /** Unread inbound count. Reset to 0 on `markRead`. */
463
+ unreadCount: number;
464
+ /** Assignee. Stored as a string so hosts can use either userId or a queue id. */
465
+ assigneeId?: string;
466
+ /** Free-form bag — channel-specific settings (preview text, IMAP folder). */
467
+ metadata?: Record<string, unknown>;
468
+ createdAt: Date;
469
+ updatedAt: Date;
470
+ }
471
+ declare function buildConversationSchema(config: SchemaBuildConfig): Schema<IConversationDocument>;
472
+ declare function createConversationModel(connection: Connection, config: SchemaBuildConfig): Model<IConversationDocument>;
473
+ //#endregion
474
+ //#region src/models/message.schema.d.ts
475
+ interface IMessageAttachment {
476
+ type: string;
477
+ url: string;
478
+ name?: string;
479
+ size?: number;
480
+ mimeType?: string;
481
+ }
482
+ interface IMessageDocument {
483
+ _id: _$mongoose.Types.ObjectId;
484
+ organizationId: _$mongoose.Types.ObjectId | string;
485
+ conversationId: _$mongoose.Types.ObjectId | string;
486
+ direction: MessageDirection;
487
+ body: string;
488
+ attachments: IMessageAttachment[];
489
+ /** Provider-side id — webhook dedup key. */
490
+ externalMessageId?: string;
491
+ status: MessageDeliveryStatus;
492
+ /** Channel id of the sender (phone number, email, telegram id). */
493
+ senderRef?: string;
494
+ /** Channel id of the recipient. */
495
+ recipientRef?: string;
496
+ /** When the wire said it left / arrived; falls back to createdAt. */
497
+ sentAt?: Date;
498
+ metadata?: Record<string, unknown>;
499
+ createdAt: Date;
500
+ updatedAt: Date;
501
+ }
502
+ declare function buildMessageSchema(config: SchemaBuildConfig): Schema<IMessageDocument>;
503
+ declare function createMessageModel(connection: Connection, config: SchemaBuildConfig): Model<IMessageDocument>;
504
+ //#endregion
427
505
  //#region src/models/create-models.d.ts
428
506
  interface CrmModels {
429
507
  Pipeline: Model<IPipelineDocument>;
@@ -437,8 +515,22 @@ interface CrmModels {
437
515
  Note: Model<INoteDocument>;
438
516
  LossReason: Model<ILossReasonDocument>;
439
517
  EmailEvent: Model<IEmailEventDocument>;
518
+ Conversation: Model<IConversationDocument>;
519
+ Message: Model<IMessageDocument>;
440
520
  }
441
- declare function createCrmModels(connection: Connection, config: SchemaBuildConfig): CrmModels;
521
+ /** Mongoose model names this package registers — drives the §21 collision check. */
522
+ declare const CRM_MODEL_NAMES: readonly ["Pipeline", "Lead", "Opportunity", "Contact", "Account", "Campaign", "EmailSubscription", "Activity", "Note", "LossReason", "EmailEvent", "Conversation", "Message"];
523
+ interface CreateModelsOptions extends SchemaBuildConfig {
524
+ /**
525
+ * On a model-name collision: `false` (default) throws
526
+ * `CrmModelCollisionError`; `true` deletes + re-registers (test
527
+ * fixtures / hot reload only).
528
+ */
529
+ forceRecreate?: boolean;
530
+ /** Mongoose auto-index builds. Default `true` (dev); `false` in prod. */
531
+ autoIndex?: boolean;
532
+ }
533
+ declare function createCrmModels(connection: Connection, config: CreateModelsOptions): CrmModels;
442
534
  //#endregion
443
535
  //#region src/repositories/pipeline.repository.d.ts
444
536
  interface PipelineRepositoryDeps {
@@ -506,12 +598,38 @@ declare class LeadRepository extends Repository<ILeadDocument> {
506
598
  qualify(id: string, extras?: TransitionExtras, ctx?: CrmContext): Promise<ILeadDocument>;
507
599
  disqualify(id: string, reason: string, extras?: Omit<TransitionExtras, 'patch'>, ctx?: CrmContext): Promise<ILeadDocument>;
508
600
  nurture(id: string, extras?: TransitionExtras, ctx?: CrmContext): Promise<ILeadDocument>;
601
+ /**
602
+ * Merge enrichment payload (3rd-party provider response or manual
603
+ * patch) into the lead doc, then re-score. Emits `crm:lead.enriched`
604
+ * with the field set written so subscribers can fan out (e.g. push a
605
+ * `recompute_segment` job) without re-reading the doc.
606
+ *
607
+ * The `provider` tag flows into the event for attribution; the package
608
+ * is provider-agnostic so the actual enrichment call lives at the host.
609
+ */
610
+ enrich(id: string, patch: Partial<ILeadDocument>, extras?: {
611
+ provider?: string;
612
+ }, ctx?: CrmContext): Promise<ILeadDocument>;
613
+ /**
614
+ * Assign / re-assign the lead's owner. Emits `crm:lead.assigned` with
615
+ * the previous owner so audit consumers can compute hand-off chains.
616
+ */
617
+ assign(id: string, ownerId: string, ctx?: CrmContext): Promise<ILeadDocument>;
509
618
  /**
510
619
  * Recompute + persist the lead's score. Called from `createLead`
511
620
  * automatically; hosts also call this after enrichment writes.
512
621
  */
513
622
  recomputeScore(id: string, ctx?: CrmContext): Promise<ILeadDocument>;
514
623
  private _transition;
624
+ /**
625
+ * Count leads created on or after `since`. Used by dashboard KPI tiles.
626
+ * Goes through the inherited tenant-scoped `count()` — the plugin
627
+ * injects `organizationId` (never a manual `if (ctx)` filter, which
628
+ * silently reads ALL tenants when ctx is absent).
629
+ */
630
+ countCreatedSince(since: Date, ctx?: CrmContext): Promise<number>;
631
+ /** Latest `limit` leads — lightweight projection for the activity feed. */
632
+ findRecentForFeed(limit: number, ctx?: CrmContext): Promise<ILeadDocument[]>;
515
633
  }
516
634
  //#endregion
517
635
  //#region src/repositories/opportunity.repository.d.ts
@@ -564,14 +682,65 @@ declare class OpportunityRepository extends Repository<IOpportunityDocument> {
564
682
  moveToStage(id: string, input: MoveStageInput, ctx?: CrmContext): Promise<IOpportunityDocument>;
565
683
  win(id: string, input?: CloseInput, ctx?: CrmContext): Promise<IOpportunityDocument>;
566
684
  lose(id: string, input?: CloseInput, ctx?: CrmContext): Promise<IOpportunityDocument>;
685
+ /**
686
+ * Re-assign opportunity owner. Mutates `ownerId` only; no status
687
+ * transition. Emits `crm:opportunity.assigned` with the previous owner.
688
+ */
689
+ assign(id: string, ownerId: string, ctx?: CrmContext): Promise<IOpportunityDocument>;
690
+ /**
691
+ * Adjust the deal amount on an open opportunity. Rejected after
692
+ * win/lose/abandon — closed-deal amounts are immutable history.
693
+ * Emits `crm:opportunity.amount_changed` with the delta so forecast
694
+ * subscribers can re-bucket.
695
+ */
696
+ updateAmount(id: string, amount: number, extras?: {
697
+ reason?: string;
698
+ by?: string;
699
+ }, ctx?: CrmContext): Promise<IOpportunityDocument>;
700
+ /**
701
+ * Push `expectedCloseAt` further out. Only valid on open opps —
702
+ * extending a closed deal is meaningless. The new date must be later
703
+ * than the current one; pulling the date in is silently accepted
704
+ * (no event is meaningful there).
705
+ */
706
+ extendCloseDate(id: string, newDate: Date, extras?: {
707
+ reason?: string;
708
+ by?: string;
709
+ }, ctx?: CrmContext): Promise<IOpportunityDocument>;
567
710
  abandon(id: string, by?: string, note?: string, ctx?: CrmContext): Promise<IOpportunityDocument>;
568
711
  private _closeStatus;
712
+ /** Count opportunities with status `open`. Used by dashboard KPI tiles. */
713
+ countOpen(ctx?: CrmContext): Promise<number>;
714
+ /**
715
+ * Sum `amount` on won opportunities updated within `since`.
716
+ * Goes through the tenant-scoped `findAll()` — the multiTenant plugin
717
+ * injects `organizationId`, so a missing ctx can't leak other tenants'
718
+ * revenue (a manual `if (ctx)` filter would).
719
+ */
720
+ sumWonSince(since: Date, ctx?: CrmContext): Promise<{
721
+ total: number;
722
+ currency?: string;
723
+ } | null>;
724
+ /** Latest `limit` opportunities — lightweight projection for the activity feed. */
725
+ findRecentForFeed(limit: number, ctx?: CrmContext): Promise<IOpportunityDocument[]>;
569
726
  }
570
727
  //#endregion
571
728
  //#region src/repositories/contact.repository.d.ts
572
729
  interface ContactRepositoryDeps {
573
730
  events: EventTransport;
574
731
  }
732
+ interface MergeContactInput {
733
+ /** Surviving contact id. Receives merged fields. */
734
+ primaryId: string;
735
+ /** Secondary contact id. Deleted after merge. */
736
+ secondaryId: string;
737
+ /**
738
+ * Per-field strategy. Defaults to `'preferPrimary'` — primary's
739
+ * non-empty fields win, secondary fills the gaps. Use `'preferSecondary'`
740
+ * for the reverse. `tags` are always unioned.
741
+ */
742
+ strategy?: 'preferPrimary' | 'preferSecondary';
743
+ }
575
744
  declare class ContactRepository extends Repository<IContactDocument> {
576
745
  private readonly events;
577
746
  constructor(model: Model<IContactDocument>, plugins: PluginType[], deps: ContactRepositoryDeps, pagination?: PaginationConfig);
@@ -580,16 +749,49 @@ declare class ContactRepository extends Repository<IContactDocument> {
580
749
  * `create()` when they want the event side-effect (e.g. webhook fan-out).
581
750
  */
582
751
  createContact(input: Partial<IContactDocument>, ctx?: CrmContext): Promise<IContactDocument>;
752
+ /**
753
+ * Merge enrichment payload into the contact. The `patch` is applied
754
+ * verbatim; deep-merge of `contact.*` channels is the caller's job
755
+ * (they own the provider response shape).
756
+ */
757
+ enrich(id: string, patch: Partial<IContactDocument>, extras?: {
758
+ provider?: string;
759
+ }, ctx?: CrmContext): Promise<IContactDocument>;
760
+ /** Set / re-assign the contact's owner. Atomic; no-op when unchanged. */
761
+ assign(id: string, ownerId: string, ctx?: CrmContext): Promise<IContactDocument>;
762
+ /**
763
+ * Merge two contacts. Secondary's non-conflicting fields are folded
764
+ * into primary, tags are unioned, then secondary is deleted.
765
+ *
766
+ * Hosts wanting transactional safety can pass `ctx.session` —
767
+ * mongokit threads it through `update` + `delete`.
768
+ *
769
+ * Re-pointing related Activities / Notes / Opportunities is the host's
770
+ * job (they own those relationships) — subscribe to
771
+ * `crm:contact.merged` and rewrite `subjectId` / `primaryContactId`
772
+ * from there.
773
+ */
774
+ merge(input: MergeContactInput, ctx?: CrmContext): Promise<IContactDocument>;
583
775
  }
584
776
  //#endregion
585
777
  //#region src/repositories/account.repository.d.ts
586
778
  interface AccountRepositoryDeps {
587
779
  events: EventTransport;
588
780
  }
781
+ interface MergeAccountInput {
782
+ primaryId: string;
783
+ secondaryId: string;
784
+ strategy?: 'preferPrimary' | 'preferSecondary';
785
+ }
589
786
  declare class AccountRepository extends Repository<IAccountDocument> {
590
787
  private readonly events;
591
788
  constructor(model: Model<IAccountDocument>, plugins: PluginType[], deps: AccountRepositoryDeps, pagination?: PaginationConfig);
592
789
  createAccount(input: Partial<IAccountDocument>, ctx?: CrmContext): Promise<IAccountDocument>;
790
+ enrich(id: string, patch: Partial<IAccountDocument>, extras?: {
791
+ provider?: string;
792
+ }, ctx?: CrmContext): Promise<IAccountDocument>;
793
+ assign(id: string, ownerId: string, ctx?: CrmContext): Promise<IAccountDocument>;
794
+ merge(input: MergeAccountInput, ctx?: CrmContext): Promise<IAccountDocument>;
593
795
  }
594
796
  //#endregion
595
797
  //#region src/repositories/campaign.repository.d.ts
@@ -655,7 +857,30 @@ declare class ActivityRepository extends Repository<IActivityDocument> {
655
857
  start(id: string, ctx?: CrmContext): Promise<IActivityDocument>;
656
858
  complete(id: string, completedAt?: Date, ctx?: CrmContext): Promise<IActivityDocument>;
657
859
  cancel(id: string, reason?: string, ctx?: CrmContext): Promise<IActivityDocument>;
860
+ /**
861
+ * Push an activity's `dueDate`. Allowed on planned / in_progress only;
862
+ * rescheduling a completed or cancelled activity makes no sense.
863
+ * Emits `crm:activity.rescheduled` with the previous date for audit.
864
+ */
865
+ reschedule(id: string, newDueDate: Date, extras?: {
866
+ reason?: string;
867
+ by?: string;
868
+ }, ctx?: CrmContext): Promise<IActivityDocument>;
869
+ /**
870
+ * Record the outcome of an activity (call result, email engagement,
871
+ * meeting confirmation). Stored under `metadata.outcome` so it stays
872
+ * polymorphic — the shape is the channel's concern, not this package's.
873
+ *
874
+ * Does NOT transition status — call `complete()` separately when the
875
+ * outcome implies completion. This split lets agents log partial
876
+ * outcomes (e.g. "left voicemail") without forcing terminal state.
877
+ */
878
+ recordOutcome(id: string, outcome: Record<string, unknown>, ctx?: CrmContext): Promise<IActivityDocument>;
658
879
  private _transition;
880
+ /** Count `planned` activities with `dueDate` before `asOf`. Dashboard KPI. */
881
+ countOverduePlanned(asOf: Date, ctx?: CrmContext): Promise<number>;
882
+ /** Latest `limit` activities — lightweight projection for the activity feed. */
883
+ findRecentForFeed(limit: number, ctx?: CrmContext): Promise<IActivityDocument[]>;
659
884
  }
660
885
  //#endregion
661
886
  //#region src/repositories/note.repository.d.ts
@@ -704,6 +929,68 @@ declare class EmailEventRepository extends Repository<IEmailEventDocument> {
704
929
  private _record;
705
930
  }
706
931
  //#endregion
932
+ //#region src/repositories/conversation.repository.d.ts
933
+ interface ConversationRepositoryDeps {
934
+ events: EventTransport;
935
+ }
936
+ interface OpenConversationInput {
937
+ channel: ConversationChannel;
938
+ participantKind: ConversationParticipantKind;
939
+ participantId: string;
940
+ channelUserId?: string;
941
+ assigneeId?: string;
942
+ metadata?: Record<string, unknown>;
943
+ }
944
+ declare class ConversationRepository extends Repository<IConversationDocument> {
945
+ private readonly events;
946
+ constructor(model: Model<IConversationDocument>, plugins: PluginType[], deps: ConversationRepositoryDeps, pagination?: PaginationConfig);
947
+ openConversation(input: OpenConversationInput, ctx?: CrmContext): Promise<IConversationDocument>;
948
+ assign(id: string, assigneeId: string, ctx?: CrmContext): Promise<IConversationDocument>;
949
+ resolve(id: string, ctx?: CrmContext): Promise<IConversationDocument>;
950
+ reopen(id: string, ctx?: CrmContext): Promise<IConversationDocument>;
951
+ /** Reset unread badge. Pure UI affordance, no event. */
952
+ markRead(id: string, ctx?: CrmContext): Promise<IConversationDocument>;
953
+ /**
954
+ * Bump `lastMessageAt` and (for inbound) increment `unreadCount`.
955
+ * Called by `MessageRepository` when a message is recorded — not part
956
+ * of the public surface. Returns the conversation for the caller's
957
+ * follow-up writes.
958
+ */
959
+ touch(id: string, args: {
960
+ direction: 'inbound' | 'outbound';
961
+ sentAt: Date;
962
+ }, ctx?: CrmContext): Promise<IConversationDocument | null>;
963
+ private _setStatus;
964
+ }
965
+ //#endregion
966
+ //#region src/repositories/message.repository.d.ts
967
+ interface MessageRepositoryDeps {
968
+ events: EventTransport;
969
+ conversations: ConversationRepository;
970
+ }
971
+ interface RecordMessageInput {
972
+ conversationId: string;
973
+ body: string;
974
+ attachments?: IMessageAttachment[];
975
+ externalMessageId?: string;
976
+ senderRef?: string;
977
+ recipientRef?: string;
978
+ sentAt?: Date;
979
+ metadata?: Record<string, unknown>;
980
+ }
981
+ declare class MessageRepository extends Repository<IMessageDocument> {
982
+ private readonly events;
983
+ private readonly conversations;
984
+ constructor(model: Model<IMessageDocument>, plugins: PluginType[], deps: MessageRepositoryDeps, pagination?: PaginationConfig);
985
+ recordInbound(input: RecordMessageInput, ctx?: CrmContext): Promise<IMessageDocument>;
986
+ recordOutbound(input: RecordMessageInput, ctx?: CrmContext): Promise<IMessageDocument>;
987
+ /** Wire delivery callback (e.g. WhatsApp `status` webhook). */
988
+ updateStatus(id: string, status: MessageDeliveryStatus, ctx?: CrmContext): Promise<IMessageDocument>;
989
+ private _record;
990
+ /** Latest `limit` messages — lightweight projection for the activity feed. */
991
+ findRecentForFeed(limit: number, ctx?: CrmContext): Promise<IMessageDocument[]>;
992
+ }
993
+ //#endregion
707
994
  //#region src/engine/engine-types.d.ts
708
995
  interface CrmLogger {
709
996
  info?(msg: string, meta?: Record<string, unknown>): void;
@@ -735,11 +1022,31 @@ interface CrmConfig {
735
1022
  pagination?: PaginationConfig;
736
1023
  /** Extra mongokit plugins applied to every repository (after defaults). */
737
1024
  plugins?: PluginType[];
1025
+ /**
1026
+ * On a Mongoose model-name collision (another engine / hot reload owns
1027
+ * the name): `false` (default) throws `CrmModelCollisionError`; `true`
1028
+ * deletes + re-registers. Test fixtures / hot reload only (§21).
1029
+ */
1030
+ forceRecreate?: boolean;
1031
+ /**
1032
+ * Mongoose auto-index builds. Default `true` (dev). Set `false` in
1033
+ * production and run `engine.syncIndexes()` from a deploy script so
1034
+ * cold-boot index builds don't blow Fastify's plugin timeout (§35).
1035
+ */
1036
+ autoIndex?: boolean;
1037
+ /**
1038
+ * Skip the boot-time `transactions` capability requirement, downgrading
1039
+ * it to a warning. Set only when the host never calls
1040
+ * `LeadService.convert()` inside a transaction (standalone Mongo).
1041
+ */
1042
+ allowNonTransactional?: boolean;
738
1043
  }
739
1044
  interface ResolvedCrmConfig extends SchemaBuildConfig {
740
1045
  connection: Connection;
741
1046
  tenantFieldType: TenantFieldType;
742
1047
  multiTenant: boolean;
1048
+ forceRecreate: boolean;
1049
+ autoIndex: boolean;
743
1050
  logger?: CrmLogger;
744
1051
  pagination?: PaginationConfig;
745
1052
  plugins: PluginType[];
@@ -756,6 +1063,8 @@ interface CrmRepositories {
756
1063
  note: NoteRepository;
757
1064
  lossReason: LossReasonRepository;
758
1065
  emailEvent: EmailEventRepository;
1066
+ conversation: ConversationRepository;
1067
+ message: MessageRepository;
759
1068
  }
760
1069
  interface CrmEngine {
761
1070
  /** Repositories ARE the API surface (PACKAGE_RULES §1). */
@@ -766,6 +1075,11 @@ interface CrmEngine {
766
1075
  readonly models: Readonly<CrmModels>;
767
1076
  /** Resolved configuration (frozen). */
768
1077
  readonly config: Readonly<ResolvedCrmConfig>;
1078
+ /**
1079
+ * Build/align every model's indexes against its schema. Call once per
1080
+ * deploy when booted with `autoIndex: false` (§35). Idempotent.
1081
+ */
1082
+ syncIndexes(): Promise<void>;
769
1083
  /** Release resources. Safe to call multiple times. */
770
1084
  dispose(): Promise<void>;
771
1085
  }
@@ -776,8 +1090,8 @@ interface CrmEngine {
776
1090
  * `metadata?` field — keep the typed surface tight.
777
1091
  */
778
1092
  interface CrmContext extends OperationContext {
779
- organizationId?: string | mongoose0.Types.ObjectId;
780
- actorId?: string | mongoose0.Types.ObjectId;
1093
+ organizationId?: string | _$mongoose.Types.ObjectId;
1094
+ actorId?: string | _$mongoose.Types.ObjectId;
781
1095
  /** Mongo transaction session (passed through to mongokit). */
782
1096
  session?: unknown;
783
1097
  }
@@ -809,11 +1123,11 @@ interface ConvertResult {
809
1123
  contact: IContactDocument;
810
1124
  account?: IAccountDocument;
811
1125
  opportunity: IOpportunityDocument;
812
- /** @deprecated use contact._id */
1126
+ /** Convenience string id — same as `String(contact._id)`. */
813
1127
  contactId: string;
814
- /** @deprecated use account._id */
1128
+ /** Convenience string id — present only when an account was created. */
815
1129
  accountId?: string;
816
- /** @deprecated use opportunity._id */
1130
+ /** Convenience string id — same as `String(opportunity._id)`. */
817
1131
  opportunityId: string;
818
1132
  }
819
1133
  interface LeadServiceDeps {
@@ -899,9 +1213,337 @@ declare const CRM_EVENTS: {
899
1213
  readonly EMAIL_EVENT_BOUNCED: "crm:email_event.bounced";
900
1214
  readonly EMAIL_EVENT_COMPLAINED: "crm:email_event.complained";
901
1215
  readonly EMAIL_EVENT_UNSUBSCRIBED: "crm:email_event.unsubscribed";
1216
+ readonly LEAD_ENRICHED: "crm:lead.enriched";
1217
+ readonly LEAD_ASSIGNED: "crm:lead.assigned";
1218
+ readonly CONTACT_ENRICHED: "crm:contact.enriched";
1219
+ readonly CONTACT_ASSIGNED: "crm:contact.assigned";
1220
+ readonly CONTACT_MERGED: "crm:contact.merged";
1221
+ readonly ACCOUNT_ENRICHED: "crm:account.enriched";
1222
+ readonly ACCOUNT_ASSIGNED: "crm:account.assigned";
1223
+ readonly ACCOUNT_MERGED: "crm:account.merged";
1224
+ readonly OPPORTUNITY_ASSIGNED: "crm:opportunity.assigned";
1225
+ readonly OPPORTUNITY_AMOUNT_CHANGED: "crm:opportunity.amount_changed";
1226
+ readonly OPPORTUNITY_EXTENDED: "crm:opportunity.extended";
1227
+ readonly ACTIVITY_RESCHEDULED: "crm:activity.rescheduled";
1228
+ readonly ACTIVITY_OUTCOME_RECORDED: "crm:activity.outcome_recorded";
1229
+ readonly CONVERSATION_CREATED: "crm:conversation.created";
1230
+ readonly CONVERSATION_ASSIGNED: "crm:conversation.assigned";
1231
+ readonly CONVERSATION_RESOLVED: "crm:conversation.resolved";
1232
+ readonly CONVERSATION_REOPENED: "crm:conversation.reopened";
1233
+ readonly MESSAGE_RECEIVED: "crm:message.received";
1234
+ readonly MESSAGE_SENT: "crm:message.sent";
902
1235
  };
903
1236
  type CrmEventName = (typeof CRM_EVENTS)[keyof typeof CRM_EVENTS];
904
1237
  //#endregion
1238
+ //#region src/events/event-catalog.d.ts
1239
+ /** JSON-Schema object produced by `z.toJSONSchema` — what arc's registry consumes. */
1240
+ type CrmEventSchema = Record<string, unknown>;
1241
+ /** Structurally identical to arc's `EventDefinitionOutput` — do NOT import arc. */
1242
+ interface CrmEventDefinition<TSchema extends z.ZodType = z.ZodType> {
1243
+ name: CrmEventName;
1244
+ version: number;
1245
+ description: string;
1246
+ zodSchema: TSchema;
1247
+ schema: CrmEventSchema;
1248
+ create(payload: z.infer<TSchema>, meta?: Partial<EventMeta>): DomainEvent<z.infer<TSchema>>;
1249
+ }
1250
+ declare const LeadCreated: CrmEventDefinition<z.ZodObject<{
1251
+ leadId: z.ZodString;
1252
+ email: z.ZodOptional<z.ZodString>;
1253
+ score: z.ZodNumber;
1254
+ }, z.core.$strip>>;
1255
+ declare const LeadStatusChanged: CrmEventDefinition<z.ZodObject<{
1256
+ leadId: z.ZodString;
1257
+ from: z.ZodString;
1258
+ to: z.ZodString;
1259
+ }, z.core.$strip>>;
1260
+ declare const LeadScored: CrmEventDefinition<z.ZodObject<{
1261
+ leadId: z.ZodString;
1262
+ score: z.ZodNumber;
1263
+ }, z.core.$strip>>;
1264
+ declare const LeadConverted: CrmEventDefinition<z.ZodObject<{
1265
+ leadId: z.ZodString;
1266
+ contactId: z.ZodString;
1267
+ accountId: z.ZodOptional<z.ZodString>;
1268
+ opportunityId: z.ZodString;
1269
+ }, z.core.$strip>>;
1270
+ declare const LeadDisqualified: CrmEventDefinition<z.ZodObject<{
1271
+ leadId: z.ZodString;
1272
+ reason: z.ZodString;
1273
+ }, z.core.$strip>>;
1274
+ declare const LeadEnriched: CrmEventDefinition<z.ZodObject<{
1275
+ leadId: z.ZodString;
1276
+ fields: z.ZodArray<z.ZodString>;
1277
+ provider: z.ZodOptional<z.ZodString>;
1278
+ }, z.core.$strip>>;
1279
+ declare const LeadAssigned: CrmEventDefinition<z.ZodObject<{
1280
+ leadId: z.ZodString;
1281
+ ownerId: z.ZodString;
1282
+ previousOwnerId: z.ZodOptional<z.ZodString>;
1283
+ }, z.core.$strip>>;
1284
+ declare const AccountCreated: CrmEventDefinition<z.ZodObject<{
1285
+ accountId: z.ZodString;
1286
+ name: z.ZodString;
1287
+ }, z.core.$strip>>;
1288
+ declare const AccountUpdated: CrmEventDefinition<z.ZodObject<{
1289
+ accountId: z.ZodString;
1290
+ }, z.core.$strip>>;
1291
+ declare const AccountEnriched: CrmEventDefinition<z.ZodObject<{
1292
+ accountId: z.ZodString;
1293
+ fields: z.ZodArray<z.ZodString>;
1294
+ provider: z.ZodOptional<z.ZodString>;
1295
+ }, z.core.$strip>>;
1296
+ declare const AccountAssigned: CrmEventDefinition<z.ZodObject<{
1297
+ accountId: z.ZodString;
1298
+ ownerId: z.ZodString;
1299
+ previousOwnerId: z.ZodOptional<z.ZodString>;
1300
+ }, z.core.$strip>>;
1301
+ declare const AccountMerged: CrmEventDefinition<z.ZodObject<{
1302
+ primaryId: z.ZodString;
1303
+ secondaryId: z.ZodString;
1304
+ strategy: z.ZodEnum<{
1305
+ preferPrimary: "preferPrimary";
1306
+ preferSecondary: "preferSecondary";
1307
+ }>;
1308
+ }, z.core.$strip>>;
1309
+ declare const ContactCreated: CrmEventDefinition<z.ZodObject<{
1310
+ contactId: z.ZodString;
1311
+ email: z.ZodOptional<z.ZodString>;
1312
+ }, z.core.$strip>>;
1313
+ declare const ContactUpdated: CrmEventDefinition<z.ZodObject<{
1314
+ contactId: z.ZodString;
1315
+ }, z.core.$strip>>;
1316
+ declare const ContactEnriched: CrmEventDefinition<z.ZodObject<{
1317
+ contactId: z.ZodString;
1318
+ fields: z.ZodArray<z.ZodString>;
1319
+ provider: z.ZodOptional<z.ZodString>;
1320
+ }, z.core.$strip>>;
1321
+ declare const ContactAssigned: CrmEventDefinition<z.ZodObject<{
1322
+ contactId: z.ZodString;
1323
+ ownerId: z.ZodString;
1324
+ previousOwnerId: z.ZodOptional<z.ZodString>;
1325
+ }, z.core.$strip>>;
1326
+ declare const ContactMerged: CrmEventDefinition<z.ZodObject<{
1327
+ primaryId: z.ZodString;
1328
+ secondaryId: z.ZodString;
1329
+ strategy: z.ZodEnum<{
1330
+ preferPrimary: "preferPrimary";
1331
+ preferSecondary: "preferSecondary";
1332
+ }>;
1333
+ }, z.core.$strip>>;
1334
+ declare const OpportunityCreated: CrmEventDefinition<z.ZodObject<{
1335
+ opportunityId: z.ZodString;
1336
+ pipelineId: z.ZodString;
1337
+ stageId: z.ZodString;
1338
+ }, z.core.$strip>>;
1339
+ declare const OpportunityStageAdvanced: CrmEventDefinition<z.ZodObject<{
1340
+ opportunityId: z.ZodString;
1341
+ from: z.ZodObject<{
1342
+ stageId: z.ZodString;
1343
+ sequence: z.ZodNumber;
1344
+ }, z.core.$strip>;
1345
+ to: z.ZodObject<{
1346
+ stageId: z.ZodString;
1347
+ sequence: z.ZodNumber;
1348
+ }, z.core.$strip>;
1349
+ }, z.core.$strip>>;
1350
+ declare const OpportunityStageRegressed: CrmEventDefinition<z.ZodObject<{
1351
+ opportunityId: z.ZodString;
1352
+ from: z.ZodObject<{
1353
+ stageId: z.ZodString;
1354
+ sequence: z.ZodNumber;
1355
+ }, z.core.$strip>;
1356
+ to: z.ZodObject<{
1357
+ stageId: z.ZodString;
1358
+ sequence: z.ZodNumber;
1359
+ }, z.core.$strip>;
1360
+ }, z.core.$strip>>;
1361
+ declare const OpportunityWon: CrmEventDefinition<z.ZodObject<{
1362
+ opportunityId: z.ZodString;
1363
+ amount: z.ZodOptional<z.ZodNumber>;
1364
+ }, z.core.$strip>>;
1365
+ declare const OpportunityLost: CrmEventDefinition<z.ZodObject<{
1366
+ opportunityId: z.ZodString;
1367
+ lostReasonId: z.ZodOptional<z.ZodString>;
1368
+ }, z.core.$strip>>;
1369
+ declare const OpportunityAbandoned: CrmEventDefinition<z.ZodObject<{
1370
+ opportunityId: z.ZodString;
1371
+ }, z.core.$strip>>;
1372
+ declare const OpportunityAssigned: CrmEventDefinition<z.ZodObject<{
1373
+ opportunityId: z.ZodString;
1374
+ ownerId: z.ZodString;
1375
+ previousOwnerId: z.ZodOptional<z.ZodString>;
1376
+ }, z.core.$strip>>;
1377
+ declare const OpportunityAmountChanged: CrmEventDefinition<z.ZodObject<{
1378
+ opportunityId: z.ZodString;
1379
+ amount: z.ZodNumber;
1380
+ previousAmount: z.ZodOptional<z.ZodNumber>;
1381
+ reason: z.ZodOptional<z.ZodString>;
1382
+ by: z.ZodOptional<z.ZodString>;
1383
+ }, z.core.$strip>>;
1384
+ declare const OpportunityExtended: CrmEventDefinition<z.ZodObject<{
1385
+ opportunityId: z.ZodString;
1386
+ expectedCloseAt: z.ZodISODateTime;
1387
+ previousExpectedCloseAt: z.ZodOptional<z.ZodISODateTime>;
1388
+ reason: z.ZodOptional<z.ZodString>;
1389
+ by: z.ZodOptional<z.ZodString>;
1390
+ }, z.core.$strip>>;
1391
+ declare const PipelineCreated: CrmEventDefinition<z.ZodObject<{
1392
+ pipelineId: z.ZodString;
1393
+ }, z.core.$strip>>;
1394
+ declare const PipelineArchived: CrmEventDefinition<z.ZodObject<{
1395
+ pipelineId: z.ZodString;
1396
+ }, z.core.$strip>>;
1397
+ declare const ActivityPlanned: CrmEventDefinition<z.ZodObject<{
1398
+ activityId: z.ZodString;
1399
+ type: z.ZodString;
1400
+ subjectKind: z.ZodString;
1401
+ subjectId: z.ZodString;
1402
+ }, z.core.$strip>>;
1403
+ declare const ActivityCompleted: CrmEventDefinition<z.ZodObject<{
1404
+ activityId: z.ZodString;
1405
+ completedAt: z.ZodISODateTime;
1406
+ }, z.core.$strip>>;
1407
+ declare const ActivityCancelled: CrmEventDefinition<z.ZodObject<{
1408
+ activityId: z.ZodString;
1409
+ reason: z.ZodOptional<z.ZodString>;
1410
+ }, z.core.$strip>>;
1411
+ declare const ActivityRescheduled: CrmEventDefinition<z.ZodObject<{
1412
+ activityId: z.ZodString;
1413
+ dueDate: z.ZodISODateTime;
1414
+ previousDueDate: z.ZodOptional<z.ZodISODateTime>;
1415
+ reason: z.ZodOptional<z.ZodString>;
1416
+ by: z.ZodOptional<z.ZodString>;
1417
+ }, z.core.$strip>>;
1418
+ declare const ActivityOutcomeRecorded: CrmEventDefinition<z.ZodObject<{
1419
+ activityId: z.ZodString;
1420
+ outcome: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1421
+ }, z.core.$strip>>;
1422
+ declare const NoteAdded: CrmEventDefinition<z.ZodObject<{
1423
+ noteId: z.ZodString;
1424
+ subjectKind: z.ZodString;
1425
+ subjectId: z.ZodString;
1426
+ }, z.core.$strip>>;
1427
+ declare const CampaignCreated: CrmEventDefinition<z.ZodObject<{
1428
+ campaignId: z.ZodString;
1429
+ name: z.ZodString;
1430
+ }, z.core.$strip>>;
1431
+ declare const CampaignActivated: CrmEventDefinition<z.ZodObject<{
1432
+ campaignId: z.ZodString;
1433
+ }, z.core.$strip>>;
1434
+ declare const CampaignPaused: CrmEventDefinition<z.ZodObject<{
1435
+ campaignId: z.ZodString;
1436
+ reason: z.ZodOptional<z.ZodString>;
1437
+ }, z.core.$strip>>;
1438
+ declare const CampaignResumed: CrmEventDefinition<z.ZodObject<{
1439
+ campaignId: z.ZodString;
1440
+ }, z.core.$strip>>;
1441
+ declare const CampaignCompleted: CrmEventDefinition<z.ZodObject<{
1442
+ campaignId: z.ZodString;
1443
+ actualRevenueAmount: z.ZodOptional<z.ZodNumber>;
1444
+ }, z.core.$strip>>;
1445
+ declare const CampaignArchived: CrmEventDefinition<z.ZodObject<{
1446
+ campaignId: z.ZodString;
1447
+ }, z.core.$strip>>;
1448
+ declare const SubscriptionCreated: CrmEventDefinition<z.ZodObject<{
1449
+ subscriptionId: z.ZodString;
1450
+ contactId: z.ZodString;
1451
+ campaignId: z.ZodString;
1452
+ requiresConfirmation: z.ZodBoolean;
1453
+ }, z.core.$strip>>;
1454
+ declare const SubscriptionConfirmed: CrmEventDefinition<z.ZodObject<{
1455
+ subscriptionId: z.ZodString;
1456
+ contactId: z.ZodString;
1457
+ campaignId: z.ZodString;
1458
+ confirmedAt: z.ZodISODateTime;
1459
+ }, z.core.$strip>>;
1460
+ declare const SubscriptionUnsubscribed: CrmEventDefinition<z.ZodObject<{
1461
+ subscriptionId: z.ZodString;
1462
+ contactId: z.ZodString;
1463
+ campaignId: z.ZodString;
1464
+ reason: z.ZodOptional<z.ZodString>;
1465
+ }, z.core.$strip>>;
1466
+ declare const SubscriptionBounced: CrmEventDefinition<z.ZodObject<{
1467
+ subscriptionId: z.ZodString;
1468
+ contactId: z.ZodString;
1469
+ campaignId: z.ZodString;
1470
+ reason: z.ZodOptional<z.ZodString>;
1471
+ }, z.core.$strip>>;
1472
+ declare const SubscriptionComplained: CrmEventDefinition<z.ZodObject<{
1473
+ subscriptionId: z.ZodString;
1474
+ contactId: z.ZodString;
1475
+ campaignId: z.ZodString;
1476
+ }, z.core.$strip>>;
1477
+ declare const EmailEventOpened: CrmEventDefinition<z.ZodObject<{
1478
+ eventId: z.ZodString;
1479
+ kind: z.ZodString;
1480
+ subjectKind: z.ZodString;
1481
+ subjectId: z.ZodString;
1482
+ campaignId: z.ZodOptional<z.ZodString>;
1483
+ }, z.core.$strip>>;
1484
+ declare const EmailEventClicked: CrmEventDefinition<z.ZodObject<{
1485
+ eventId: z.ZodString;
1486
+ kind: z.ZodString;
1487
+ subjectKind: z.ZodString;
1488
+ subjectId: z.ZodString;
1489
+ campaignId: z.ZodOptional<z.ZodString>;
1490
+ }, z.core.$strip>>;
1491
+ declare const EmailEventBounced: CrmEventDefinition<z.ZodObject<{
1492
+ eventId: z.ZodString;
1493
+ kind: z.ZodString;
1494
+ subjectKind: z.ZodString;
1495
+ subjectId: z.ZodString;
1496
+ campaignId: z.ZodOptional<z.ZodString>;
1497
+ }, z.core.$strip>>;
1498
+ declare const EmailEventComplained: CrmEventDefinition<z.ZodObject<{
1499
+ eventId: z.ZodString;
1500
+ kind: z.ZodString;
1501
+ subjectKind: z.ZodString;
1502
+ subjectId: z.ZodString;
1503
+ campaignId: z.ZodOptional<z.ZodString>;
1504
+ }, z.core.$strip>>;
1505
+ declare const EmailEventUnsubscribed: CrmEventDefinition<z.ZodObject<{
1506
+ eventId: z.ZodString;
1507
+ kind: z.ZodString;
1508
+ subjectKind: z.ZodString;
1509
+ subjectId: z.ZodString;
1510
+ campaignId: z.ZodOptional<z.ZodString>;
1511
+ }, z.core.$strip>>;
1512
+ declare const ConversationCreated: CrmEventDefinition<z.ZodObject<{
1513
+ conversationId: z.ZodString;
1514
+ channel: z.ZodString;
1515
+ participantKind: z.ZodString;
1516
+ participantId: z.ZodString;
1517
+ }, z.core.$strip>>;
1518
+ declare const ConversationAssigned: CrmEventDefinition<z.ZodObject<{
1519
+ conversationId: z.ZodString;
1520
+ assigneeId: z.ZodString;
1521
+ previousAssigneeId: z.ZodOptional<z.ZodString>;
1522
+ }, z.core.$strip>>;
1523
+ declare const ConversationResolved: CrmEventDefinition<z.ZodObject<{
1524
+ conversationId: z.ZodString;
1525
+ status: z.ZodString;
1526
+ previousStatus: z.ZodString;
1527
+ }, z.core.$strip>>;
1528
+ declare const ConversationReopened: CrmEventDefinition<z.ZodObject<{
1529
+ conversationId: z.ZodString;
1530
+ status: z.ZodString;
1531
+ previousStatus: z.ZodString;
1532
+ }, z.core.$strip>>;
1533
+ declare const MessageReceived: CrmEventDefinition<z.ZodObject<{
1534
+ messageId: z.ZodString;
1535
+ conversationId: z.ZodString;
1536
+ direction: z.ZodString;
1537
+ externalMessageId: z.ZodOptional<z.ZodString>;
1538
+ }, z.core.$strip>>;
1539
+ declare const MessageSent: CrmEventDefinition<z.ZodObject<{
1540
+ messageId: z.ZodString;
1541
+ conversationId: z.ZodString;
1542
+ direction: z.ZodString;
1543
+ externalMessageId: z.ZodOptional<z.ZodString>;
1544
+ }, z.core.$strip>>;
1545
+ declare const crmEventDefinitions: ReadonlyArray<CrmEventDefinition>;
1546
+ //#endregion
905
1547
  //#region src/events/helpers.d.ts
906
1548
  declare function createEvent<T>(type: string, payload: T, ctx?: CrmContext, meta?: Partial<EventMeta>): DomainEvent<T>;
907
1549
  //#endregion
@@ -934,11 +1576,11 @@ declare class InProcessCrmBus implements EventTransport {
934
1576
  * Built on `@classytic/primitives/state-machine` so the same shape lights
935
1577
  * up across kits (mongokit's `claim()` pairing, sqlitekit follow-ups).
936
1578
  */
937
- declare const LEAD_MACHINE: _classytic_primitives_state_machine0.StateMachine<"new" | "contacted" | "qualified" | "converted" | "disqualified" | "nurturing">;
938
- declare const OPPORTUNITY_MACHINE: _classytic_primitives_state_machine0.StateMachine<"open" | "won" | "lost" | "abandoned">;
939
- declare const CAMPAIGN_MACHINE: _classytic_primitives_state_machine0.StateMachine<"draft" | "active" | "paused" | "completed" | "archived">;
940
- declare const SUBSCRIPTION_MACHINE: _classytic_primitives_state_machine0.StateMachine<"pending" | "confirmed" | "unsubscribed" | "bounced" | "complained">;
941
- declare const ACTIVITY_MACHINE: _classytic_primitives_state_machine0.StateMachine<"completed" | "planned" | "in_progress" | "cancelled">;
1579
+ declare const LEAD_MACHINE: _$_classytic_primitives_state_machine0.StateMachine<"new" | "contacted" | "qualified" | "converted" | "disqualified" | "nurturing">;
1580
+ declare const OPPORTUNITY_MACHINE: _$_classytic_primitives_state_machine0.StateMachine<"open" | "won" | "lost" | "abandoned">;
1581
+ declare const CAMPAIGN_MACHINE: _$_classytic_primitives_state_machine0.StateMachine<"draft" | "active" | "paused" | "completed" | "archived">;
1582
+ declare const SUBSCRIPTION_MACHINE: _$_classytic_primitives_state_machine0.StateMachine<"pending" | "confirmed" | "unsubscribed" | "bounced" | "complained">;
1583
+ declare const ACTIVITY_MACHINE: _$_classytic_primitives_state_machine0.StateMachine<"completed" | "planned" | "in_progress" | "cancelled">;
942
1584
  //#endregion
943
1585
  //#region src/core/errors.d.ts
944
1586
  /**
@@ -1241,6 +1883,10 @@ declare const createContactSchema: z.ZodObject<{
1241
1883
  personalEmail: z.ZodOptional<z.ZodString>;
1242
1884
  phone: z.ZodOptional<z.ZodString>;
1243
1885
  alternatePhone: z.ZodOptional<z.ZodString>;
1886
+ whatsapp: z.ZodOptional<z.ZodString>;
1887
+ telegram: z.ZodOptional<z.ZodString>;
1888
+ linkedin: z.ZodOptional<z.ZodString>;
1889
+ instagram: z.ZodOptional<z.ZodString>;
1244
1890
  }, z.core.$strip>>;
1245
1891
  jobTitle: z.ZodOptional<z.ZodString>;
1246
1892
  accountId: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodString]>>;
@@ -1262,6 +1908,10 @@ declare const updateContactSchema: z.ZodObject<{
1262
1908
  personalEmail: z.ZodOptional<z.ZodString>;
1263
1909
  phone: z.ZodOptional<z.ZodString>;
1264
1910
  alternatePhone: z.ZodOptional<z.ZodString>;
1911
+ whatsapp: z.ZodOptional<z.ZodString>;
1912
+ telegram: z.ZodOptional<z.ZodString>;
1913
+ linkedin: z.ZodOptional<z.ZodString>;
1914
+ instagram: z.ZodOptional<z.ZodString>;
1265
1915
  }, z.core.$strip>>>;
1266
1916
  jobTitle: z.ZodOptional<z.ZodOptional<z.ZodString>>;
1267
1917
  accountId: z.ZodOptional<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodString]>>>;
@@ -1570,6 +2220,8 @@ declare const emailEventFilterSchema: z.ZodObject<{
1570
2220
  messageId: z.ZodOptional<z.ZodString>;
1571
2221
  }, z.core.$strip>;
1572
2222
  type RecordEmailEventDto = z.infer<typeof recordEmailEventSchema>;
2223
+ declare namespace index_d_exports {
2224
+ export { AddNoteDto, CancelActivityDto, CloseLossDto, CloseWinDto, CompleteCampaignDto, ConfirmSubscriptionDto, ConvertLeadDto, CreateAccountDto, CreateCampaignDto, CreateContactDto, CreateLeadDto, CreateLossReasonDto, CreatePipelineDto, LeadFilterDto, MoveStageDto, OpenOpportunityDto, OpportunityFilterDto, PlanActivityDto, RecordEmailEventDto, StageInputDto, SubscribeDto, UnsubscribeDto, UpdateAccountDto, UpdateCampaignDto, UpdateContactDto, UpdateLeadDto, UpdateLossReasonDto, UpdateNoteDto, UpdatePipelineDto, accountFilterSchema, activityFilterSchema, addNoteSchema, campaignFilterSchema, cancelActivitySchema, closeLossSchema, closeWinSchema, completeCampaignSchema, confirmSubscriptionSchema, contactFilterSchema, convertLeadSchema, createAccountSchema, createCampaignSchema, createContactSchema, createLeadSchema, createLossReasonSchema, createPipelineSchema, currencyCodeSchema, emailEventFilterSchema, leadFilterSchema, lossReasonFilterSchema, metadataSchema, moneyAmountSchema, moveStageSchema, noteFilterSchema, objectIdLike, openOpportunitySchema, opportunityFilterSchema, pipelineFilterSchema, planActivitySchema, recordEmailEventSchema, stageInputSchemaExport, subscribeSchema, subscriptionFilterSchema, tagsSchema, unsubscribeSchema, updateAccountSchema, updateActivitySchema, updateCampaignSchema, updateContactSchema, updateLeadSchema, updateLossReasonSchema, updateNoteSchema, updatePipelineSchema };
2225
+ }
1573
2226
  //#endregion
1574
- export { ACTIVITY_MACHINE, ACTIVITY_STATUSES, ACTIVITY_TRANSITIONS, ACTIVITY_TYPES, AccountRepository, AccountRepositoryDeps, ActivityRepository, ActivityRepositoryDeps, type ActivityStatus, type ActivityType, CAMPAIGN_MACHINE, CAMPAIGN_STATUSES, CAMPAIGN_TRANSITIONS, CRM_EVENTS, CampaignRepository, CampaignRepositoryDeps, type CampaignStatus, CloseInput, ContactRepository, ContactRepositoryDeps, ConversionRow, ConvertLeadInput, ConvertResult, CreateCrmRepositoriesDeps, CrmConfig, CrmContext, CrmEngine, CrmError, CrmEventName, CrmLogger, CrmModels, CrmRepositories, DuplicateCampaignError, DuplicateLeadError, DuplicateSubscriptionError, EMAIL_EVENT_KINDS, EMAIL_EVENT_SUBJECT_KINDS, type EmailEventKind, EmailEventRepository, EmailEventRepositoryDeps, EmailEventSubjectKind, EmptyPipelineError, ForecastOptions, ForecastRow, type IAccountDocument, type IActivityDocument, type ICampaignDocument, ICampaignStatusEntry, type IContactDocument, IContactInfoEmbedded, IContactName, type IEmailEventDocument, type ILeadDocument, ILeadStatusEntry, type ILossReasonDocument, type INoteDocument, type IOpportunityDocument, IOpportunityStatusEntry, type IPipelineDocument, IStageDocument, type ISubscriptionDocument, ISubscriptionStatusEntry, InProcessCrmBus, InvalidActivityTransitionError, InvalidCampaignTransitionError, InvalidConfirmationTokenError, InvalidLeadTransitionError, InvalidOpportunityTransitionError, InvalidSubscriptionTransitionError, InvalidUnsubscribeTokenError, LEAD_MACHINE, LEAD_STATUSES, LEAD_TRANSITIONS, LeadAlreadyConvertedError, LeadInput, LeadRepository, LeadRepositoryDeps, LeadScorer, LeadService, LeadServiceDeps, type LeadStatus, LossReasonRepository, LossReasonRepositoryDeps, MoveStageInput, NotFoundError, NoteRepository, NoteRepositoryDeps, OPPORTUNITY_MACHINE, OPPORTUNITY_STATUSES, OPPORTUNITY_TRANSITIONS, OpenOpportunityInput, OpportunityForecast, OpportunityRepository, OpportunityRepositoryDeps, type OpportunityStatus, PipelineRepository, PipelineRepositoryDeps, RecordEmailEventInput, ResolvedCrmConfig, SUBJECT_KINDS, SUBSCRIPTION_MACHINE, SUBSCRIPTION_STATUSES, SUBSCRIPTION_TRANSITIONS, SchemaBuildConfig, StageNotInPipelineError, type StatusChangeEntry, type StatusHistory, type SubjectKind, SubscribeInput, SubscriptionRepository, SubscriptionRepositoryDeps, type SubscriptionStatus, TenantFieldType, _ModelTypes, appendStatus, buildAccountSchema, buildActivitySchema, buildCampaignSchema, buildContactSchema, buildEmailEventSchema, buildLeadSchema, buildLossReasonSchema, buildNoteSchema, buildOpportunitySchema, buildPipelineSchema, buildSubscriptionSchema, canTransitionActivity, canTransitionCampaign, canTransitionLead, canTransitionOpportunity, canTransitionSubscription, composeScorers, createAccountModel, createActivityModel, createCampaignModel, createContactModel, createCrm, createCrmModels, createCrmRepositories, createEmailEventModel, createEvent, createLeadModel, createLossReasonModel, createNoteModel, createOpportunityModel, createPipelineModel, createSubscriptionModel, defaultLeadScorer, forecast, lastTransitionTo, latestEntry, pipelineConversion, tenantFieldDef, timeInStatus, index_d_exports as validators };
1575
- //# sourceMappingURL=index.d.ts.map
2227
+ export { ACTIVITY_MACHINE, ACTIVITY_STATUSES, ACTIVITY_TRANSITIONS, ACTIVITY_TYPES, AccountAssigned, AccountCreated, AccountEnriched, AccountMerged, AccountRepository, AccountRepositoryDeps, AccountUpdated, ActivityCancelled, ActivityCompleted, ActivityOutcomeRecorded, ActivityPlanned, ActivityRepository, ActivityRepositoryDeps, ActivityRescheduled, type ActivityStatus, type ActivityType, CAMPAIGN_MACHINE, CAMPAIGN_STATUSES, CAMPAIGN_TRANSITIONS, CONVERSATION_CHANNELS, CONVERSATION_PARTICIPANT_KINDS, CONVERSATION_STATUSES, CRM_EVENTS, CRM_MODEL_NAMES, CampaignActivated, CampaignArchived, CampaignCompleted, CampaignCreated, CampaignPaused, CampaignRepository, CampaignRepositoryDeps, CampaignResumed, type CampaignStatus, CloseInput, ContactAssigned, ContactCreated, ContactEnriched, ContactMerged, ContactRepository, ContactRepositoryDeps, ContactUpdated, ConversationAssigned, type ConversationChannel, ConversationCreated, type ConversationParticipantKind, ConversationReopened, ConversationRepository, ConversationRepositoryDeps, ConversationResolved, type ConversationStatus, ConversionRow, ConvertLeadInput, ConvertResult, CreateCrmRepositoriesDeps, CreateModelsOptions, CrmConfig, CrmContext, CrmEngine, CrmError, CrmEventDefinition, CrmEventName, CrmEventSchema, CrmLogger, CrmModels, CrmRepositories, DuplicateCampaignError, DuplicateLeadError, DuplicateSubscriptionError, EMAIL_EVENT_KINDS, EMAIL_EVENT_SUBJECT_KINDS, EmailEventBounced, EmailEventClicked, EmailEventComplained, type EmailEventKind, EmailEventOpened, EmailEventRepository, EmailEventRepositoryDeps, EmailEventSubjectKind, EmailEventUnsubscribed, EmptyPipelineError, ForecastOptions, ForecastRow, type IAccountDocument, type IActivityDocument, type ICampaignDocument, ICampaignStatusEntry, type IContactDocument, IContactInfoEmbedded, IContactName, type IConversationDocument, type IEmailEventDocument, type ILeadDocument, ILeadStatusEntry, type ILossReasonDocument, IMessageAttachment, type IMessageDocument, type INoteDocument, type IOpportunityDocument, IOpportunityStatusEntry, type IPipelineDocument, IStageDocument, type ISubscriptionDocument, ISubscriptionStatusEntry, InProcessCrmBus, InvalidActivityTransitionError, InvalidCampaignTransitionError, InvalidConfirmationTokenError, InvalidLeadTransitionError, InvalidOpportunityTransitionError, InvalidSubscriptionTransitionError, InvalidUnsubscribeTokenError, LEAD_MACHINE, LEAD_STATUSES, LEAD_TRANSITIONS, LeadAlreadyConvertedError, LeadAssigned, LeadConverted, LeadCreated, LeadDisqualified, LeadEnriched, LeadInput, LeadRepository, LeadRepositoryDeps, LeadScored, LeadScorer, LeadService, LeadServiceDeps, type LeadStatus, LeadStatusChanged, LossReasonRepository, LossReasonRepositoryDeps, MESSAGE_DELIVERY_STATUSES, MESSAGE_DIRECTIONS, MergeAccountInput, MergeContactInput, type MessageDeliveryStatus, type MessageDirection, MessageReceived, MessageRepository, MessageRepositoryDeps, MessageSent, MoveStageInput, NotFoundError, NoteAdded, NoteRepository, NoteRepositoryDeps, OPPORTUNITY_MACHINE, OPPORTUNITY_STATUSES, OPPORTUNITY_TRANSITIONS, OpenConversationInput, OpenOpportunityInput, OpportunityAbandoned, OpportunityAmountChanged, OpportunityAssigned, OpportunityCreated, OpportunityExtended, OpportunityForecast, OpportunityLost, OpportunityRepository, OpportunityRepositoryDeps, OpportunityStageAdvanced, OpportunityStageRegressed, type OpportunityStatus, OpportunityWon, PipelineArchived, PipelineCreated, PipelineRepository, PipelineRepositoryDeps, RecordEmailEventInput, RecordMessageInput, ResolvedCrmConfig, SUBJECT_KINDS, SUBSCRIPTION_MACHINE, SUBSCRIPTION_STATUSES, SUBSCRIPTION_TRANSITIONS, SchemaBuildConfig, StageNotInPipelineError, type StatusChangeEntry, type StatusHistory, type SubjectKind, SubscribeInput, SubscriptionBounced, SubscriptionComplained, SubscriptionConfirmed, SubscriptionCreated, SubscriptionRepository, SubscriptionRepositoryDeps, type SubscriptionStatus, SubscriptionUnsubscribed, TenantFieldType, _ModelTypes, appendStatus, buildAccountSchema, buildActivitySchema, buildCampaignSchema, buildContactSchema, buildConversationSchema, buildEmailEventSchema, buildLeadSchema, buildLossReasonSchema, buildMessageSchema, buildNoteSchema, buildOpportunitySchema, buildPipelineSchema, buildSubscriptionSchema, canTransitionActivity, canTransitionCampaign, canTransitionLead, canTransitionOpportunity, canTransitionSubscription, composeScorers, createAccountModel, createActivityModel, createCampaignModel, createContactModel, createConversationModel, createCrm, createCrmModels, createCrmRepositories, createEmailEventModel, createEvent, createLeadModel, createLossReasonModel, createMessageModel, createNoteModel, createOpportunityModel, createPipelineModel, createSubscriptionModel, crmEventDefinitions, defaultLeadScorer, forecast, lastTransitionTo, latestEntry, pipelineConversion, tenantFieldDef, timeInStatus, index_d_exports as validators };