@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/dist/events.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createEvent as createEvent$1, matchEventPattern } from "@classytic/primitives/events";
2
1
  import { z } from "zod";
2
+ import { createEvent as createEvent$1, matchEventPattern } from "@classytic/primitives/events";
3
3
  //#region src/events/event-constants.ts
4
4
  /** PACKAGE_RULES rule 12: `package:resource.verb`. */
5
5
  const CRM_EVENTS = {
@@ -35,6 +35,16 @@ const CRM_EVENTS = {
35
35
  SUBSCRIPTION_UNSUBSCRIBED: "crm:subscription.unsubscribed",
36
36
  SUBSCRIPTION_BOUNCED: "crm:subscription.bounced",
37
37
  SUBSCRIPTION_COMPLAINED: "crm:subscription.complained",
38
+ SEQUENCE_CREATED: "crm:sequence.created",
39
+ SEQUENCE_ACTIVATED: "crm:sequence.active",
40
+ SEQUENCE_PAUSED: "crm:sequence.paused",
41
+ SEQUENCE_ARCHIVED: "crm:sequence.archived",
42
+ ENROLLMENT_CREATED: "crm:enrollment.created",
43
+ ENROLLMENT_STEP_SENT: "crm:enrollment.step_sent",
44
+ ENROLLMENT_PAUSED: "crm:enrollment.paused",
45
+ ENROLLMENT_RESUMED: "crm:enrollment.resumed",
46
+ ENROLLMENT_COMPLETED: "crm:enrollment.completed",
47
+ ENROLLMENT_EXITED: "crm:enrollment.exited",
38
48
  EMAIL_EVENT_OPENED: "crm:email_event.opened",
39
49
  EMAIL_EVENT_CLICKED: "crm:email_event.clicked",
40
50
  EMAIL_EVENT_BOUNCED: "crm:email_event.bounced",
@@ -53,6 +63,8 @@ const CRM_EVENTS = {
53
63
  OPPORTUNITY_EXTENDED: "crm:opportunity.extended",
54
64
  ACTIVITY_RESCHEDULED: "crm:activity.rescheduled",
55
65
  ACTIVITY_OUTCOME_RECORDED: "crm:activity.outcome_recorded",
66
+ SUPPRESSION_ADDED: "crm:suppression.added",
67
+ SUPPRESSION_REMOVED: "crm:suppression.removed",
56
68
  CONVERSATION_CREATED: "crm:conversation.created",
57
69
  CONVERSATION_ASSIGNED: "crm:conversation.assigned",
58
70
  CONVERSATION_RESOLVED: "crm:conversation.resolved",
@@ -60,62 +72,11 @@ const CRM_EVENTS = {
60
72
  MESSAGE_RECEIVED: "crm:message.received",
61
73
  MESSAGE_SENT: "crm:message.sent"
62
74
  };
63
- //#endregion
64
- //#region src/events/helpers.ts
65
- /**
66
- * Event creation helper.
67
- *
68
- * Thin wrapper around `@classytic/primitives`' `createEvent` that fills the
69
- * shared `EventMeta` from a `CrmContext` (userId/actorId, organizationId,
70
- * correlationId). Use this instead of importing `createEvent` directly so
71
- * the `source: 'crm'` stamp + tenant scoping stay consistent.
72
- */
73
- function createEvent(type, payload, ctx, meta) {
74
- return createEvent$1(type, payload, {
75
- source: "crm",
76
- ...ctx?.actorId !== void 0 ? { actorId: String(ctx.actorId) } : {},
77
- ...ctx?.organizationId !== void 0 ? { organizationId: String(ctx.organizationId) } : {},
78
- ...ctx?.correlationId !== void 0 ? { correlationId: ctx.correlationId } : {},
79
- ...meta
80
- });
81
- }
82
- //#endregion
83
- //#region src/events/in-process-bus.ts
84
- /**
85
- * In-process event bus — default fallback when no `eventTransport` is
86
- * provided to `createCrm`. Structurally identical to arc's
87
- * `MemoryEventTransport`; pattern matching is delegated to primitives.
88
- * Handler errors are swallowed — event emission never blocks writes.
89
- */
90
- var InProcessCrmBus = class {
91
- name = "in-process-crm";
92
- subs = [];
93
- logger;
94
- constructor(options) {
95
- if (options?.logger) this.logger = options.logger;
96
- }
97
- async publish(event) {
98
- const matching = this.subs.filter((s) => matchEventPattern(s.pattern, event.type));
99
- for (const sub of matching) try {
100
- await sub.handler(event);
101
- } catch (err) {
102
- this.logger?.error?.(`[crm] event handler error [${event.type}]`, { error: err instanceof Error ? err.message : String(err) });
103
- }
104
- }
105
- async subscribe(pattern, handler) {
106
- const sub = {
107
- pattern,
108
- handler
109
- };
110
- this.subs.push(sub);
111
- return () => {
112
- this.subs = this.subs.filter((s) => s !== sub);
113
- };
114
- }
115
- async close() {
116
- this.subs = [];
117
- }
118
- };
75
+ const SUPPRESSION_REASONS = [...[
76
+ "bounce",
77
+ "complaint",
78
+ "unsubscribe"
79
+ ], "manual"];
119
80
  //#endregion
120
81
  //#region src/events/event-catalog.ts
121
82
  /**
@@ -554,6 +515,22 @@ const SubscriptionComplained = defineCrmEvent({
554
515
  campaignId: z.string()
555
516
  })
556
517
  });
518
+ const SuppressionAdded = defineCrmEvent({
519
+ name: CRM_EVENTS.SUPPRESSION_ADDED,
520
+ resource: "suppression",
521
+ description: "suppress() inserted a NEW row on the org-wide suppression list (idempotent re-suppress of an existing email emits nothing). organizationId rides event meta.",
522
+ zodSchema: z.object({
523
+ email: z.string(),
524
+ reason: z.enum(SUPPRESSION_REASONS),
525
+ source: z.string().optional()
526
+ })
527
+ });
528
+ const SuppressionRemoved = defineCrmEvent({
529
+ name: CRM_EVENTS.SUPPRESSION_REMOVED,
530
+ resource: "suppression",
531
+ description: "unsuppress() removed an email from the org-wide suppression list.",
532
+ zodSchema: z.object({ email: z.string() })
533
+ });
557
534
  const emailEventSchema = z.object({
558
535
  eventId: z.string(),
559
536
  kind: z.string(),
@@ -654,6 +631,82 @@ const MessageSent = defineCrmEvent({
654
631
  externalMessageId: z.string().optional()
655
632
  })
656
633
  });
634
+ const SequenceCreated = defineCrmEvent({
635
+ name: CRM_EVENTS.SEQUENCE_CREATED,
636
+ resource: "sequence",
637
+ description: "A sequence draft was created. Emitted by the HOST after repo.create() (the package ships no createSequence verb) — defined here so registries validate the payload.",
638
+ zodSchema: z.object({
639
+ sequenceId: z.string(),
640
+ name: z.string().optional()
641
+ })
642
+ });
643
+ const SequenceActivated = defineCrmEvent({
644
+ name: CRM_EVENTS.SEQUENCE_ACTIVATED,
645
+ resource: "sequence",
646
+ description: "activate() moved a sequence draft/paused → active.",
647
+ zodSchema: z.object({ sequenceId: z.string() })
648
+ });
649
+ const SequencePaused = defineCrmEvent({
650
+ name: CRM_EVENTS.SEQUENCE_PAUSED,
651
+ resource: "sequence",
652
+ description: "pause() suspended an active sequence (existing enrollments hold).",
653
+ zodSchema: z.object({ sequenceId: z.string() })
654
+ });
655
+ const SequenceArchived = defineCrmEvent({
656
+ name: CRM_EVENTS.SEQUENCE_ARCHIVED,
657
+ resource: "sequence",
658
+ description: "archive() retired a sequence — no new enrollments.",
659
+ zodSchema: z.object({ sequenceId: z.string() })
660
+ });
661
+ const EnrollmentCreated = defineCrmEvent({
662
+ name: CRM_EVENTS.ENROLLMENT_CREATED,
663
+ resource: "enrollment",
664
+ description: "enroll() attached a subject to a sequence.",
665
+ zodSchema: z.object({
666
+ enrollmentId: z.string(),
667
+ sequenceId: z.string(),
668
+ subjectId: z.string(),
669
+ subjectKind: z.string()
670
+ })
671
+ });
672
+ const EnrollmentStepSent = defineCrmEvent({
673
+ name: CRM_EVENTS.ENROLLMENT_STEP_SENT,
674
+ resource: "enrollment",
675
+ description: "A sequence step was delivered. Emitted by the HOST outreach layer after its send adapter succeeds + advanceStep() commits (Buffer-style pattern in CLAUDE.md) — defined here so registries validate the payload.",
676
+ zodSchema: z.object({
677
+ enrollmentId: z.string(),
678
+ sequenceId: z.string().optional(),
679
+ stepIndex: z.number(),
680
+ channel: z.string().optional()
681
+ })
682
+ });
683
+ const EnrollmentPaused = defineCrmEvent({
684
+ name: CRM_EVENTS.ENROLLMENT_PAUSED,
685
+ resource: "enrollment",
686
+ description: "pause() held an active enrollment.",
687
+ zodSchema: z.object({ enrollmentId: z.string() })
688
+ });
689
+ const EnrollmentResumed = defineCrmEvent({
690
+ name: CRM_EVENTS.ENROLLMENT_RESUMED,
691
+ resource: "enrollment",
692
+ description: "resume() reactivated a paused enrollment.",
693
+ zodSchema: z.object({ enrollmentId: z.string() })
694
+ });
695
+ const EnrollmentCompleted = defineCrmEvent({
696
+ name: CRM_EVENTS.ENROLLMENT_COMPLETED,
697
+ resource: "enrollment",
698
+ description: "complete() finished the final step of an enrollment.",
699
+ zodSchema: z.object({ enrollmentId: z.string() })
700
+ });
701
+ const EnrollmentExited = defineCrmEvent({
702
+ name: CRM_EVENTS.ENROLLMENT_EXITED,
703
+ resource: "enrollment",
704
+ description: "exit() removed a subject before completion (reply/unsubscribe/manual/goal).",
705
+ zodSchema: z.object({
706
+ enrollmentId: z.string(),
707
+ exitReason: z.string().optional()
708
+ })
709
+ });
657
710
  const crmEventDefinitions = [
658
711
  LeadCreated,
659
712
  LeadStatusChanged,
@@ -700,6 +753,8 @@ const crmEventDefinitions = [
700
753
  SubscriptionUnsubscribed,
701
754
  SubscriptionBounced,
702
755
  SubscriptionComplained,
756
+ SuppressionAdded,
757
+ SuppressionRemoved,
703
758
  EmailEventOpened,
704
759
  EmailEventClicked,
705
760
  EmailEventBounced,
@@ -710,7 +765,73 @@ const crmEventDefinitions = [
710
765
  ConversationResolved,
711
766
  ConversationReopened,
712
767
  MessageReceived,
713
- MessageSent
768
+ MessageSent,
769
+ SequenceCreated,
770
+ SequenceActivated,
771
+ SequencePaused,
772
+ SequenceArchived,
773
+ EnrollmentCreated,
774
+ EnrollmentStepSent,
775
+ EnrollmentPaused,
776
+ EnrollmentResumed,
777
+ EnrollmentCompleted,
778
+ EnrollmentExited
714
779
  ];
715
780
  //#endregion
716
- 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, 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 };
781
+ //#region src/events/helpers.ts
782
+ /**
783
+ * Event creation helper.
784
+ *
785
+ * Thin wrapper around `@classytic/primitives`' `createEvent` that fills the
786
+ * shared `EventMeta` from a `CrmContext` (userId/actorId, organizationId,
787
+ * correlationId). Use this instead of importing `createEvent` directly so
788
+ * the `source: 'crm'` stamp + tenant scoping stay consistent.
789
+ */
790
+ function createEvent(type, payload, ctx, meta) {
791
+ return createEvent$1(type, payload, {
792
+ source: "crm",
793
+ ...ctx?.actorId !== void 0 ? { actorId: String(ctx.actorId) } : {},
794
+ ...ctx?.organizationId !== void 0 ? { organizationId: String(ctx.organizationId) } : {},
795
+ ...ctx?.correlationId !== void 0 ? { correlationId: ctx.correlationId } : {},
796
+ ...meta
797
+ });
798
+ }
799
+ //#endregion
800
+ //#region src/events/in-process-bus.ts
801
+ /**
802
+ * In-process event bus — default fallback when no `eventTransport` is
803
+ * provided to `createCrm`. Structurally identical to arc's
804
+ * `MemoryEventTransport`; pattern matching is delegated to primitives.
805
+ * Handler errors are swallowed — event emission never blocks writes.
806
+ */
807
+ var InProcessCrmBus = class {
808
+ name = "in-process-crm";
809
+ subs = [];
810
+ logger;
811
+ constructor(options) {
812
+ if (options?.logger) this.logger = options.logger;
813
+ }
814
+ async publish(event) {
815
+ const matching = this.subs.filter((s) => matchEventPattern(s.pattern, event.type));
816
+ for (const sub of matching) try {
817
+ await sub.handler(event);
818
+ } catch (err) {
819
+ this.logger?.error?.(`[crm] event handler error [${event.type}]`, { error: err instanceof Error ? err.message : String(err) });
820
+ }
821
+ }
822
+ async subscribe(pattern, handler) {
823
+ const sub = {
824
+ pattern,
825
+ handler
826
+ };
827
+ this.subs.push(sub);
828
+ return () => {
829
+ this.subs = this.subs.filter((s) => s !== sub);
830
+ };
831
+ }
832
+ async close() {
833
+ this.subs = [];
834
+ }
835
+ };
836
+ //#endregion
837
+ 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, 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 };