@classytic/crm 0.9.0 → 1.1.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 +500 -363
- package/LICENSE +75 -21
- package/README.md +52 -3
- package/dist/events.d.ts +20 -12
- package/dist/events.js +41 -31
- package/dist/index.d.ts +506 -136
- package/dist/index.js +1143 -429
- package/package.json +79 -73
- package/scripts/lead-contact-email-key-drift.mjs +218 -0
- package/scripts/suppression-key-drift.mjs +143 -0
- /package/dist/{chunk.js → rolldown-runtime.js} +0 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Classytic
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Classytic Source-Available License (Community & Commercial), Version 1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Classytic LLC. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software is source-available, not open source. Please read this License
|
|
6
|
+
before using it.
|
|
7
|
+
|
|
8
|
+
1. DEFINITIONS
|
|
9
|
+
"Software" means the contents of this package and any accompanying source
|
|
10
|
+
code, object code, or documentation, in any form.
|
|
11
|
+
"Licensor" means Classytic LLC, a limited liability company organized in the
|
|
12
|
+
United States.
|
|
13
|
+
"You" means the individual or legal entity exercising rights under this
|
|
14
|
+
License.
|
|
15
|
+
"Evaluation Use" means use for evaluation, development, testing,
|
|
16
|
+
experimentation, or internal non-commercial purposes only.
|
|
17
|
+
"Production Use" means any use of the Software that is live, commercial,
|
|
18
|
+
revenue-generating, or customer-facing, or any use other than Evaluation Use.
|
|
19
|
+
"Commercial License" means a separate written agreement executed with
|
|
20
|
+
Licensor that grants Production Use rights.
|
|
21
|
+
|
|
22
|
+
2. OWNERSHIP
|
|
23
|
+
The Software is licensed, not sold. Licensor retains all right, title, and
|
|
24
|
+
interest in and to the Software, including all intellectual property rights.
|
|
25
|
+
All rights not expressly granted in this License are reserved by Licensor.
|
|
26
|
+
|
|
27
|
+
3. EVALUATION GRANT
|
|
28
|
+
Subject to Your compliance with this License, Licensor grants You a
|
|
29
|
+
worldwide, royalty-free, non-exclusive, non-transferable, revocable license
|
|
30
|
+
to download, install, run, and modify the Software solely for Evaluation Use.
|
|
31
|
+
|
|
32
|
+
4. PRODUCTION USE REQUIRES A COMMERCIAL LICENSE
|
|
33
|
+
Production Use of the Software is NOT permitted under this License and
|
|
34
|
+
requires a Commercial License from Licensor. A Commercial License may be
|
|
35
|
+
granted at Licensor's discretion, with or without a fee, and may confer
|
|
36
|
+
perpetual, irrevocable, and transferable Production Use rights as set out in
|
|
37
|
+
that agreement. Contact licensing@classytic.com to obtain one.
|
|
38
|
+
|
|
39
|
+
5. RESTRICTIONS
|
|
40
|
+
You may not:
|
|
41
|
+
(a) make any Production Use of the Software without a Commercial License;
|
|
42
|
+
(b) redistribute, resell, rent, sublicense, or otherwise make the Software
|
|
43
|
+
(in whole or in part, original or modified) available to third parties as
|
|
44
|
+
a stand-alone product, framework, library, or hosted/managed service that
|
|
45
|
+
competes with the Software or with Licensor;
|
|
46
|
+
(c) remove, obscure, or alter any copyright, license, or attribution notice.
|
|
47
|
+
|
|
48
|
+
6. FEEDBACK AND CONTRIBUTIONS
|
|
49
|
+
Any feedback, suggestions, or contributions You provide relating to the
|
|
50
|
+
Software may be used by Licensor for any purpose without obligation to You.
|
|
51
|
+
|
|
52
|
+
7. TERMINATION
|
|
53
|
+
This License and the Evaluation Grant terminate automatically if You breach
|
|
54
|
+
any term. Upon termination You must cease all use of the Software and destroy
|
|
55
|
+
all copies in Your possession. Rights under a Commercial License are governed
|
|
56
|
+
by that agreement's own terms and survive termination of this License to the
|
|
57
|
+
extent stated there.
|
|
58
|
+
|
|
59
|
+
8. DISCLAIMER OF WARRANTY
|
|
60
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
61
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
62
|
+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
63
|
+
|
|
64
|
+
9. LIMITATION OF LIABILITY
|
|
65
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL LICENSOR BE LIABLE
|
|
66
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
67
|
+
TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE
|
|
68
|
+
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
69
|
+
|
|
70
|
+
10. GOVERNING LAW
|
|
71
|
+
This License is governed by the laws of the State of Delaware, United States,
|
|
72
|
+
without regard to its conflict-of-laws principles. (Adjust to Your LLC's state
|
|
73
|
+
of formation.)
|
|
74
|
+
|
|
75
|
+
For commercial licensing, contact: licensing@classytic.com
|
package/README.md
CHANGED
|
@@ -39,8 +39,57 @@ and conversation/message threads. Built on **Mongoose + @classytic/mongokit
|
|
|
39
39
|
npm install @classytic/crm
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
Peers: `@classytic/
|
|
43
|
-
`@classytic/
|
|
42
|
+
Peers: `@classytic/contact >=0.1.0`, `@classytic/mongokit >=3.30.0`,
|
|
43
|
+
`@classytic/repo-core >=0.13.0`, `@classytic/primitives >=0.14.0`,
|
|
44
|
+
`mongoose >=9.4.1`, `zod >=4.0.0`.
|
|
45
|
+
|
|
46
|
+
`@classytic/contact` is the email/phone identity kernel. It is a **peer**, not a
|
|
47
|
+
dependency, so npm cannot nest a second copy and break `instanceof` across the
|
|
48
|
+
boundary — the same reason `@classytic/party` declares it that way. This package
|
|
49
|
+
imports `@classytic/contact/email` directly at one place, the suppression list.
|
|
50
|
+
|
|
51
|
+
## The suppression list is keyed CANONICALLY
|
|
52
|
+
|
|
53
|
+
`SuppressionRepository` is the org-wide do-not-contact list a host consults before
|
|
54
|
+
every outbound email. Its key is whatever `normalizeEmail` from
|
|
55
|
+
`@classytic/contact/email` returns: trimmed, both sides lowercased, **and the
|
|
56
|
+
domain IDNA-folded to punycode**. `ada@bücher.de` is stored, matched and returned
|
|
57
|
+
as `ada@xn--bcher-kva.de`.
|
|
58
|
+
|
|
59
|
+
Two consequences for a host:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { suppressionEmailKey } from '@classytic/crm';
|
|
63
|
+
|
|
64
|
+
// filterSuppressed() returns CANONICAL keys — canonicalise your own recipient
|
|
65
|
+
// before testing membership. Matching on the raw spelling is the original bug.
|
|
66
|
+
const blocked = await crm.repositories.suppression.filterSuppressed(recipients, ctx);
|
|
67
|
+
const sendable = recipients.filter((e) => !blocked.has(suppressionEmailKey(e) ?? e));
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- **Writes refuse what they cannot canonicalise.** `suppress()` and `unsuppress()`
|
|
71
|
+
throw `SuppressionEmailFormatError` (400). A malformed address stored verbatim is
|
|
72
|
+
a do-not-contact record that can never match a send — it suppresses nothing while
|
|
73
|
+
reporting success.
|
|
74
|
+
- **Reads fail closed.** `isSuppressed()` answers `true`, and `filterSuppressed()`
|
|
75
|
+
reports as blocked, for an address with no canonical form. The permissive answer
|
|
76
|
+
would send mail to an address we could not parse; the conservative answer costs
|
|
77
|
+
one undeliverable message. They do not throw, because one malformed recipient must
|
|
78
|
+
not abort a fanout to thousands of valid ones. `suppressionEmailKey()` returns
|
|
79
|
+
`null` for such an address if you need to tell it apart from a real suppression.
|
|
80
|
+
|
|
81
|
+
**Upgrading from a version before this rule:** rows written under the old
|
|
82
|
+
`trim().toLowerCase()` key may no longer be reachable. Report — do not migrate —
|
|
83
|
+
with the read-only script:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
node node_modules/@classytic/crm/scripts/suppression-key-drift.mjs "$MONGO_URI"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
It classifies every row as `unchanged` / `rekey` / `collision` / `uncanonicalisable`
|
|
90
|
+
and writes nothing. `collision` rows cannot be moved by an `updateOne` at all — the
|
|
91
|
+
`(organizationId, email)` index is unique and another row already holds the target
|
|
92
|
+
key, so which `reason` and `suppressedAt` survive is a human decision.
|
|
44
93
|
|
|
45
94
|
## Quick start
|
|
46
95
|
|
|
@@ -50,7 +99,7 @@ import { createCrm, LeadService } from '@classytic/crm';
|
|
|
50
99
|
|
|
51
100
|
const crm = await createCrm({
|
|
52
101
|
connection: mongoose.connection,
|
|
53
|
-
|
|
102
|
+
tenant: { fieldType: 'objectId' }, // matches Better Auth orgs; 'string' for UUID hosts
|
|
54
103
|
});
|
|
55
104
|
|
|
56
105
|
const ctx = { organizationId: orgId };
|
package/dist/events.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { DomainEvent,
|
|
3
|
-
import
|
|
2
|
+
import { DomainEvent, EventMeta } from "@classytic/primitives/events";
|
|
3
|
+
import { InProcessEventBus } from "@classytic/primitives/event-infra";
|
|
4
|
+
import "mongoose";
|
|
5
|
+
import "@classytic/mongokit";
|
|
4
6
|
import { OperationContext } from "@classytic/primitives/context";
|
|
7
|
+
import "@classytic/primitives/outbox";
|
|
8
|
+
import "@classytic/repo-core/tenant";
|
|
5
9
|
//#region src/events/event-constants.d.ts
|
|
6
10
|
/** PACKAGE_RULES rule 12: `package:resource.verb`. */
|
|
7
11
|
declare const CRM_EVENTS: {
|
|
@@ -54,9 +58,11 @@ declare const CRM_EVENTS: {
|
|
|
54
58
|
readonly EMAIL_EVENT_UNSUBSCRIBED: "crm:email_event.unsubscribed";
|
|
55
59
|
readonly LEAD_ENRICHED: "crm:lead.enriched";
|
|
56
60
|
readonly LEAD_ASSIGNED: "crm:lead.assigned";
|
|
61
|
+
readonly LEAD_ANONYMIZED: "crm:lead.anonymized";
|
|
57
62
|
readonly CONTACT_ENRICHED: "crm:contact.enriched";
|
|
58
63
|
readonly CONTACT_ASSIGNED: "crm:contact.assigned";
|
|
59
64
|
readonly CONTACT_MERGED: "crm:contact.merged";
|
|
65
|
+
readonly CONTACT_ANONYMIZED: "crm:contact.anonymized";
|
|
60
66
|
readonly ACCOUNT_ENRICHED: "crm:account.enriched";
|
|
61
67
|
readonly ACCOUNT_ASSIGNED: "crm:account.assigned";
|
|
62
68
|
readonly ACCOUNT_MERGED: "crm:account.merged";
|
|
@@ -122,6 +128,10 @@ declare const LeadAssigned: CrmEventDefinition<z.ZodObject<{
|
|
|
122
128
|
ownerId: z.ZodString;
|
|
123
129
|
previousOwnerId: z.ZodOptional<z.ZodString>;
|
|
124
130
|
}, z.core.$strip>>;
|
|
131
|
+
declare const LeadAnonymized: CrmEventDefinition<z.ZodObject<{
|
|
132
|
+
leadId: z.ZodString;
|
|
133
|
+
fields: z.ZodArray<z.ZodString>;
|
|
134
|
+
}, z.core.$strip>>;
|
|
125
135
|
declare const AccountCreated: CrmEventDefinition<z.ZodObject<{
|
|
126
136
|
accountId: z.ZodString;
|
|
127
137
|
name: z.ZodString;
|
|
@@ -172,6 +182,10 @@ declare const ContactMerged: CrmEventDefinition<z.ZodObject<{
|
|
|
172
182
|
preferSecondary: "preferSecondary";
|
|
173
183
|
}>;
|
|
174
184
|
}, z.core.$strip>>;
|
|
185
|
+
declare const ContactAnonymized: CrmEventDefinition<z.ZodObject<{
|
|
186
|
+
contactId: z.ZodString;
|
|
187
|
+
fields: z.ZodArray<z.ZodString>;
|
|
188
|
+
}, z.core.$strip>>;
|
|
175
189
|
declare const OpportunityCreated: CrmEventDefinition<z.ZodObject<{
|
|
176
190
|
opportunityId: z.ZodString;
|
|
177
191
|
pipelineId: z.ZodString;
|
|
@@ -450,8 +464,8 @@ interface CrmLogger {
|
|
|
450
464
|
* `metadata?` field — keep the typed surface tight.
|
|
451
465
|
*/
|
|
452
466
|
interface CrmContext extends OperationContext {
|
|
453
|
-
organizationId?: string |
|
|
454
|
-
actorId?: string |
|
|
467
|
+
organizationId?: string | import('mongoose').Types.ObjectId;
|
|
468
|
+
actorId?: string | import('mongoose').Types.ObjectId;
|
|
455
469
|
/** Mongo transaction session (passed through to mongokit). */
|
|
456
470
|
session?: unknown;
|
|
457
471
|
}
|
|
@@ -460,16 +474,10 @@ interface CrmContext extends OperationContext {
|
|
|
460
474
|
declare function createEvent<T>(type: string, payload: T, ctx?: CrmContext, meta?: Partial<EventMeta>): DomainEvent<T>;
|
|
461
475
|
//#endregion
|
|
462
476
|
//#region src/events/in-process-bus.d.ts
|
|
463
|
-
declare class InProcessCrmBus
|
|
464
|
-
readonly name = "in-process-crm";
|
|
465
|
-
private subs;
|
|
466
|
-
private logger?;
|
|
477
|
+
declare class InProcessCrmBus extends InProcessEventBus {
|
|
467
478
|
constructor(options?: {
|
|
468
479
|
logger?: CrmLogger;
|
|
469
480
|
});
|
|
470
|
-
publish(event: DomainEvent): Promise<void>;
|
|
471
|
-
subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
|
|
472
|
-
close(): Promise<void>;
|
|
473
481
|
}
|
|
474
482
|
//#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 };
|
|
483
|
+
export { AccountAssigned, AccountCreated, AccountEnriched, AccountMerged, AccountUpdated, ActivityCancelled, ActivityCompleted, ActivityOutcomeRecorded, ActivityPlanned, ActivityRescheduled, CRM_EVENTS, CampaignActivated, CampaignArchived, CampaignCompleted, CampaignCreated, CampaignPaused, CampaignResumed, ContactAnonymized, ContactAssigned, ContactCreated, ContactEnriched, ContactMerged, ContactUpdated, ConversationAssigned, ConversationCreated, ConversationReopened, ConversationResolved, CrmEventDefinition, CrmEventName, CrmEventSchema, EmailEventBounced, EmailEventClicked, EmailEventComplained, EmailEventOpened, EmailEventUnsubscribed, EnrollmentCompleted, EnrollmentCreated, EnrollmentExited, EnrollmentPaused, EnrollmentResumed, EnrollmentStepSent, InProcessCrmBus, LeadAnonymized, 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 };
|
package/dist/events.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { createEvent as createEvent$1
|
|
2
|
+
import { createEvent as createEvent$1 } from "@classytic/primitives/events";
|
|
3
|
+
import { InProcessEventBus } from "@classytic/primitives/event-infra";
|
|
3
4
|
//#region src/events/event-constants.ts
|
|
4
5
|
/** PACKAGE_RULES rule 12: `package:resource.verb`. */
|
|
5
6
|
const CRM_EVENTS = {
|
|
@@ -52,9 +53,11 @@ const CRM_EVENTS = {
|
|
|
52
53
|
EMAIL_EVENT_UNSUBSCRIBED: "crm:email_event.unsubscribed",
|
|
53
54
|
LEAD_ENRICHED: "crm:lead.enriched",
|
|
54
55
|
LEAD_ASSIGNED: "crm:lead.assigned",
|
|
56
|
+
LEAD_ANONYMIZED: "crm:lead.anonymized",
|
|
55
57
|
CONTACT_ENRICHED: "crm:contact.enriched",
|
|
56
58
|
CONTACT_ASSIGNED: "crm:contact.assigned",
|
|
57
59
|
CONTACT_MERGED: "crm:contact.merged",
|
|
60
|
+
CONTACT_ANONYMIZED: "crm:contact.anonymized",
|
|
58
61
|
ACCOUNT_ENRICHED: "crm:account.enriched",
|
|
59
62
|
ACCOUNT_ASSIGNED: "crm:account.assigned",
|
|
60
63
|
ACCOUNT_MERGED: "crm:account.merged",
|
|
@@ -194,6 +197,15 @@ const LeadAssigned = defineCrmEvent({
|
|
|
194
197
|
description: "assign() (re)assigned the lead owner.",
|
|
195
198
|
zodSchema: z.object({ leadId: z.string() }).extend(ownerChangeSchema.shape)
|
|
196
199
|
});
|
|
200
|
+
const LeadAnonymized = defineCrmEvent({
|
|
201
|
+
name: CRM_EVENTS.LEAD_ANONYMIZED,
|
|
202
|
+
resource: "lead",
|
|
203
|
+
description: "anonymize() scrubbed a lead's PII (name/email/phone) in place — GDPR right-to-erasure. Non-PII aggregates (score/status/engagement) and the id are preserved; `anonymizedAt` tombstones the row.",
|
|
204
|
+
zodSchema: z.object({
|
|
205
|
+
leadId: z.string(),
|
|
206
|
+
fields: z.array(z.string())
|
|
207
|
+
})
|
|
208
|
+
});
|
|
197
209
|
const AccountCreated = defineCrmEvent({
|
|
198
210
|
name: CRM_EVENTS.ACCOUNT_CREATED,
|
|
199
211
|
resource: "account",
|
|
@@ -260,6 +272,15 @@ const ContactMerged = defineCrmEvent({
|
|
|
260
272
|
description: "merge() folded a secondary contact into the primary; secondary deleted.",
|
|
261
273
|
zodSchema: mergeSchema
|
|
262
274
|
});
|
|
275
|
+
const ContactAnonymized = defineCrmEvent({
|
|
276
|
+
name: CRM_EVENTS.CONTACT_ANONYMIZED,
|
|
277
|
+
resource: "contact",
|
|
278
|
+
description: "anonymize() scrubbed a contact's PII (name + every contact channel) in place — GDPR right-to-erasure. Non-PII aggregates (accountId, ownerId, tags) and the id are preserved; `anonymizedAt` tombstones the row.",
|
|
279
|
+
zodSchema: z.object({
|
|
280
|
+
contactId: z.string(),
|
|
281
|
+
fields: z.array(z.string())
|
|
282
|
+
})
|
|
283
|
+
});
|
|
263
284
|
const OpportunityCreated = defineCrmEvent({
|
|
264
285
|
name: CRM_EVENTS.OPPORTUNITY_CREATED,
|
|
265
286
|
resource: "opportunity",
|
|
@@ -715,6 +736,7 @@ const crmEventDefinitions = [
|
|
|
715
736
|
LeadDisqualified,
|
|
716
737
|
LeadEnriched,
|
|
717
738
|
LeadAssigned,
|
|
739
|
+
LeadAnonymized,
|
|
718
740
|
AccountCreated,
|
|
719
741
|
AccountUpdated,
|
|
720
742
|
AccountEnriched,
|
|
@@ -725,6 +747,7 @@ const crmEventDefinitions = [
|
|
|
725
747
|
ContactEnriched,
|
|
726
748
|
ContactAssigned,
|
|
727
749
|
ContactMerged,
|
|
750
|
+
ContactAnonymized,
|
|
728
751
|
OpportunityCreated,
|
|
729
752
|
OpportunityStageAdvanced,
|
|
730
753
|
OpportunityStageRegressed,
|
|
@@ -800,38 +823,25 @@ function createEvent(type, payload, ctx, meta) {
|
|
|
800
823
|
//#region src/events/in-process-bus.ts
|
|
801
824
|
/**
|
|
802
825
|
* In-process event bus — default fallback when no `eventTransport` is
|
|
803
|
-
* provided to `
|
|
804
|
-
*
|
|
805
|
-
*
|
|
826
|
+
* provided to `blueprint.bind(connection, runtime)`.
|
|
827
|
+
*
|
|
828
|
+
* A thin subclass of `@classytic/primitives/event-infra`'s shared
|
|
829
|
+
* `InProcessEventBus`. Prior semantics preserved: glob matching via
|
|
830
|
+
* `matchEventPattern`, per-handler error isolation, idempotent `close()`.
|
|
831
|
+
* CRM historically SWALLOWED handler errors when no logger was supplied —
|
|
832
|
+
* that default is preserved by passing `logger: null` unless the host
|
|
833
|
+
* injects a `CrmLogger`, whose structured `error(msg, meta)` slot is
|
|
834
|
+
* bridged onto the shared error-logger contract.
|
|
806
835
|
*/
|
|
807
|
-
var InProcessCrmBus = class {
|
|
808
|
-
name = "in-process-crm";
|
|
809
|
-
subs = [];
|
|
810
|
-
logger;
|
|
836
|
+
var InProcessCrmBus = class extends InProcessEventBus {
|
|
811
837
|
constructor(options) {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
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 = [];
|
|
838
|
+
const crmLogger = options?.logger;
|
|
839
|
+
super({
|
|
840
|
+
name: "in-process-crm",
|
|
841
|
+
logLabel: "crm",
|
|
842
|
+
logger: crmLogger?.error ? { error: (message, ...args) => crmLogger.error?.(message, { args }) } : null
|
|
843
|
+
});
|
|
834
844
|
}
|
|
835
845
|
};
|
|
836
846
|
//#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 };
|
|
847
|
+
export { AccountAssigned, AccountCreated, AccountEnriched, AccountMerged, AccountUpdated, ActivityCancelled, ActivityCompleted, ActivityOutcomeRecorded, ActivityPlanned, ActivityRescheduled, CRM_EVENTS, CampaignActivated, CampaignArchived, CampaignCompleted, CampaignCreated, CampaignPaused, CampaignResumed, ContactAnonymized, ContactAssigned, ContactCreated, ContactEnriched, ContactMerged, ContactUpdated, ConversationAssigned, ConversationCreated, ConversationReopened, ConversationResolved, EmailEventBounced, EmailEventClicked, EmailEventComplained, EmailEventOpened, EmailEventUnsubscribed, EnrollmentCompleted, EnrollmentCreated, EnrollmentExited, EnrollmentPaused, EnrollmentResumed, EnrollmentStepSent, InProcessCrmBus, LeadAnonymized, 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 };
|