mailery 0.5.1 → 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/README.md +3 -1
- package/dist/admin/spa/{index-Dmsla2eL.js → index-CjQTOX9H.js} +8 -8
- package/dist/admin/spa/index-CjQTOX9H.js.map +1 -0
- package/dist/admin/spa/index.html +1 -1
- package/dist/admin/spa/{template-editor-Bn28OPMU.js → template-editor-yH0Oz4Ix.js} +105 -105
- package/dist/admin/spa/template-editor-yH0Oz4Ix.js.map +1 -0
- package/dist/index.cjs +453 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -4
- package/dist/index.d.ts +26 -4
- package/dist/index.js +451 -31
- package/dist/index.js.map +1 -1
- package/dist/{null-BYB6v4Iv.d.cts → null-B0rPgE5_.d.cts} +126 -3
- package/dist/{null-BYB6v4Iv.d.ts → null-B0rPgE5_.d.ts} +126 -3
- package/dist/testing.cjs +305 -17
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +305 -17
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/admin/spa/index-Dmsla2eL.js.map +0 -1
- package/dist/admin/spa/template-editor-Bn28OPMU.js.map +0 -1
|
@@ -47,6 +47,24 @@ interface ContactAdapter {
|
|
|
47
47
|
addTags?(externalId: string, tags: string[]): Promise<void>;
|
|
48
48
|
removeTags?(externalId: string, tags: string[]): Promise<void>;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Constrains WHEN a send step's email may go out. The flow's waits decide the
|
|
52
|
+
* earliest moment (T + N days); the window then pushes that moment forward —
|
|
53
|
+
* never backward — to the next allowed slot:
|
|
54
|
+
*
|
|
55
|
+
* - `timeOfDay` — deliver at this local wall-clock time ('HH:mm'). A send
|
|
56
|
+
* arriving after that time waits for the next day's slot (with a short
|
|
57
|
+
* grace period so tick jitter doesn't add 24h).
|
|
58
|
+
* - `weekdaysOnly` — a slot landing on Saturday/Sunday moves to Monday.
|
|
59
|
+
* - `useContactTimezone` — interpret times in `contact.timezone` when set,
|
|
60
|
+
* else fall back to `timezone` (IANA name, default UTC).
|
|
61
|
+
*/
|
|
62
|
+
interface DeliveryWindow {
|
|
63
|
+
weekdaysOnly?: boolean;
|
|
64
|
+
timeOfDay?: string;
|
|
65
|
+
useContactTimezone?: boolean;
|
|
66
|
+
timezone?: string;
|
|
67
|
+
}
|
|
50
68
|
type FlowStep = {
|
|
51
69
|
type: 'wait';
|
|
52
70
|
value: number;
|
|
@@ -65,6 +83,7 @@ type FlowStep = {
|
|
|
65
83
|
templateSlug: string;
|
|
66
84
|
providerOverride?: string;
|
|
67
85
|
vars?: Record<string, unknown>;
|
|
86
|
+
delivery?: DeliveryWindow;
|
|
68
87
|
} | {
|
|
69
88
|
type: 'tag';
|
|
70
89
|
addTags?: string[];
|
|
@@ -375,7 +394,7 @@ type QueueDriverConfig = {
|
|
|
375
394
|
* server-shaped interfaces.
|
|
376
395
|
*/
|
|
377
396
|
type SubscriptionStatus = 'subscribed' | 'pending_doi' | 'unsubscribed' | 'bounced' | 'complained';
|
|
378
|
-
type SendStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed' | 'suppressed';
|
|
397
|
+
type SendStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed' | 'suppressed' | 'cancelled';
|
|
379
398
|
type TemplateKind = 'transactional' | 'marketing';
|
|
380
399
|
type SuppressionScope = 'all' | 'marketing' | 'transactional';
|
|
381
400
|
type SuppressionReason = 'unsubscribed' | 'hard_bounce' | 'complaint' | 'manual' | 'list_cleaning' | 'gdpr_forget';
|
|
@@ -417,6 +436,63 @@ type SenderDomainValidation = {
|
|
|
417
436
|
};
|
|
418
437
|
declare function validateSenderDomain(fromEmail: string, templateKind: TemplateKind, registry: SenderDomainRegistry | undefined): SenderDomainValidation;
|
|
419
438
|
|
|
439
|
+
/**
|
|
440
|
+
* VarsAdapter — host-provided template variables, resolved at render time.
|
|
441
|
+
*
|
|
442
|
+
* The host declares a zod schema (the contract templates can rely on) plus a
|
|
443
|
+
* `resolve` function that loads those values from the host's own database for
|
|
444
|
+
* a given contact. Resolved keys are merged into the render context root, so
|
|
445
|
+
* a schema key `user` is referenced in templates as `{{user.name}}`.
|
|
446
|
+
*
|
|
447
|
+
* The schema does double duty: it is exposed to the admin SPA as JSON Schema
|
|
448
|
+
* (GET /vars-schema) to drive editor autocomplete, and the content linter
|
|
449
|
+
* uses it to flag `{{paths}}` that don't exist.
|
|
450
|
+
*/
|
|
451
|
+
|
|
452
|
+
interface VarsResolveInfo {
|
|
453
|
+
/** Why the vars are being resolved. Previews and tests should be side-effect free. */
|
|
454
|
+
reason: 'send' | 'preview' | 'test';
|
|
455
|
+
/** Slug of the template being rendered, when known. */
|
|
456
|
+
templateSlug?: string;
|
|
457
|
+
/** Slug of the flow the send belongs to, when the render is part of a flow run. */
|
|
458
|
+
flowSlug?: string;
|
|
459
|
+
/** Name of the event that triggered the flow run, when applicable. */
|
|
460
|
+
eventName?: string;
|
|
461
|
+
/**
|
|
462
|
+
* Properties of the triggering event (`mailer.fire(name, id, properties)`).
|
|
463
|
+
* This is how a resolver scopes lookups for account/topic flows:
|
|
464
|
+
* `info.eventProperties?.accountId` tells it WHICH account the run is about.
|
|
465
|
+
* Also available raw in templates as `{{event.*}}`.
|
|
466
|
+
*/
|
|
467
|
+
eventProperties?: Record<string, unknown>;
|
|
468
|
+
}
|
|
469
|
+
interface VarsAdapter<S extends z.ZodType = z.ZodType> {
|
|
470
|
+
/** Contract for what `resolve` returns. Root keys become root template variables. */
|
|
471
|
+
schema: S;
|
|
472
|
+
/** Load the variables for one contact from the host's data. */
|
|
473
|
+
resolve(contact: Contact, info: VarsResolveInfo): Promise<z.infer<S>> | z.infer<S>;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Identity helper that pins `resolve`'s return type to `z.infer<schema>` —
|
|
477
|
+
* without it, TypeScript widens the schema generic and the return type is
|
|
478
|
+
* unchecked.
|
|
479
|
+
*
|
|
480
|
+
* const varsAdapter = defineVars({
|
|
481
|
+
* schema: z.object({ user: z.object({ name: z.string() }) }),
|
|
482
|
+
* async resolve(contact) {
|
|
483
|
+
* return { user: { name: await lookupName(contact.externalId) } }
|
|
484
|
+
* },
|
|
485
|
+
* })
|
|
486
|
+
*/
|
|
487
|
+
declare function defineVars<S extends z.ZodType>(adapter: VarsAdapter<S>): VarsAdapter<S>;
|
|
488
|
+
/**
|
|
489
|
+
* Render-context keys mailery owns. Resolved vars never override these — a
|
|
490
|
+
* schema that declares one is rejected at Mailer.init.
|
|
491
|
+
*/
|
|
492
|
+
declare const RESERVED_VAR_KEYS: readonly ["contact", "vars", "event", "unsubscribeUrl", "viewInBrowserUrl", "preferenceCenterUrl", "senderAddress"];
|
|
493
|
+
/** JSON Schema for the adapter's zod schema (wire format for the admin SPA + linter). */
|
|
494
|
+
declare function varsJsonSchema(adapter: VarsAdapter): Record<string, unknown>;
|
|
495
|
+
|
|
420
496
|
/**
|
|
421
497
|
* Mailer configuration shape. Required + optional surfaces with sane defaults.
|
|
422
498
|
*/
|
|
@@ -531,6 +607,14 @@ interface MailerConfig {
|
|
|
531
607
|
db: Db;
|
|
532
608
|
collectionPrefix?: string;
|
|
533
609
|
adapter: ContactAdapter;
|
|
610
|
+
/**
|
|
611
|
+
* Optional host-provided template variables. `resolve(contact)` runs at
|
|
612
|
+
* send/preview/test render time; its result is merged into the template
|
|
613
|
+
* context root (schema key `user` → `{{user.name}}`). The zod schema
|
|
614
|
+
* drives admin-editor autocomplete and the `unknown_variable` lint rule.
|
|
615
|
+
* Build one with `defineVars({ schema, resolve })`.
|
|
616
|
+
*/
|
|
617
|
+
varsAdapter?: VarsAdapter<any>;
|
|
534
618
|
/**
|
|
535
619
|
* Queue driver selection. One of:
|
|
536
620
|
* - `{ driver: 'bull', redis: ... }` — BullMQ (default for prod; requires Redis)
|
|
@@ -734,7 +818,7 @@ interface FlowVersionDoc {
|
|
|
734
818
|
}
|
|
735
819
|
interface FlowRunHistoryEntry {
|
|
736
820
|
stepIndex: number;
|
|
737
|
-
action: 'entered' | 'wait_started' | 'wait_completed' | 'condition_evaluated' | 'branch_taken' | 'sent' | 'send_skipped' | 'tagged' | 'event_fired' | 'webhook_called' | 'exited' | 'failed';
|
|
821
|
+
action: 'entered' | 'wait_started' | 'wait_completed' | 'condition_evaluated' | 'branch_taken' | 'sent' | 'send_skipped' | 'send_deferred' | 'tagged' | 'event_fired' | 'webhook_called' | 'exited' | 'failed';
|
|
738
822
|
at: Date;
|
|
739
823
|
details?: Record<string, unknown>;
|
|
740
824
|
}
|
|
@@ -745,6 +829,17 @@ interface FlowRunDoc {
|
|
|
745
829
|
flowSlug: string;
|
|
746
830
|
flowVersion: number;
|
|
747
831
|
emailAtEntry: string;
|
|
832
|
+
/**
|
|
833
|
+
* Snapshot of the event that triggered this run. Properties surface in
|
|
834
|
+
* templates as `{{event.*}}` and in `varsAdapter.resolve` via
|
|
835
|
+
* `info.eventProperties` — this is how account/topic-scoped flows know
|
|
836
|
+
* which account or topic the run is about. Null for non-event entries.
|
|
837
|
+
*/
|
|
838
|
+
triggerEvent?: {
|
|
839
|
+
name: string;
|
|
840
|
+
properties: Record<string, unknown>;
|
|
841
|
+
occurredAt: Date;
|
|
842
|
+
} | null;
|
|
748
843
|
enteredAt: Date;
|
|
749
844
|
status: FlowRunStatus;
|
|
750
845
|
currentStepIndex: number;
|
|
@@ -1224,6 +1319,7 @@ interface RunnerContext {
|
|
|
1224
1319
|
db: Db;
|
|
1225
1320
|
collections: Collections;
|
|
1226
1321
|
adapter: ContactAdapter;
|
|
1322
|
+
varsAdapter?: VarsAdapter;
|
|
1227
1323
|
providers: Record<string, MailProvider>;
|
|
1228
1324
|
queues: Queues;
|
|
1229
1325
|
config: ResolvedConfig;
|
|
@@ -1297,6 +1393,33 @@ declare class Mailer {
|
|
|
1297
1393
|
suppress(email: string, opts: Omit<SuppressInput, 'email'>): Promise<void>;
|
|
1298
1394
|
tag(externalId: string, tag: string): Promise<void>;
|
|
1299
1395
|
untag(externalId: string, tag: string): Promise<void>;
|
|
1396
|
+
/**
|
|
1397
|
+
* Abort every active run of one flow for a contact, immediately. Runs parked
|
|
1398
|
+
* in a `wait` exit too — their delayed wake-up jobs find the run exited and
|
|
1399
|
+
* no-op. Also cancels any of the flow's emails still sitting in the send
|
|
1400
|
+
* queue for this contact (queued or awaiting retry), so an abort means no
|
|
1401
|
+
* further mail, not just no further steps.
|
|
1402
|
+
*
|
|
1403
|
+
* No-op (returns zero counts) when nothing is active. Safe to call from the
|
|
1404
|
+
* same handler that processes the business event ("user upgraded").
|
|
1405
|
+
*/
|
|
1406
|
+
abortFlow(flowSlug: string, externalId: string, opts?: {
|
|
1407
|
+
reason?: string;
|
|
1408
|
+
}): Promise<{
|
|
1409
|
+
abortedRuns: number;
|
|
1410
|
+
cancelledSends: number;
|
|
1411
|
+
}>;
|
|
1412
|
+
/**
|
|
1413
|
+
* Abort every active flow run for a contact across all flows. Same semantics
|
|
1414
|
+
* as `abortFlow` — for "stop everything" events (account deleted, churned).
|
|
1415
|
+
*/
|
|
1416
|
+
abortAllFlows(externalId: string, opts?: {
|
|
1417
|
+
reason?: string;
|
|
1418
|
+
}): Promise<{
|
|
1419
|
+
abortedRuns: number;
|
|
1420
|
+
cancelledSends: number;
|
|
1421
|
+
}>;
|
|
1422
|
+
private abortActiveRuns;
|
|
1300
1423
|
/**
|
|
1301
1424
|
* GDPR right-to-erasure. Hard-deletes the contact's PII and leaves a hashed
|
|
1302
1425
|
* suppression row to block re-import. INVARIANT 9.
|
|
@@ -1346,4 +1469,4 @@ declare class NullProvider implements MailProvider {
|
|
|
1346
1469
|
reset(): void;
|
|
1347
1470
|
}
|
|
1348
1471
|
|
|
1349
|
-
export { type AdapterFilter as A, type BroadcastDoc as B, type ContactAdapter as C, type
|
|
1472
|
+
export { getCollections as $, type AdapterFilter as A, type BroadcastDoc as B, type ContactAdapter as C, type DeliveryWindow as D, type EventDoc as E, type FlowStep as F, type SenderDomainValidation as G, type HealthDoc as H, type SubscriptionDoc as I, type SubscriptionStatus as J, type SuppressionDoc as K, type LeadDoc as L, type MailProvider as M, type NormalizedEvent as N, type OutboxDoc as O, type Predicate as P, type SuppressionReason as Q, type RunnerContext as R, type SendArgs as S, type TemplateDoc as T, type TemplateKind as U, type TemplateVersionDoc as V, type VarsAdapter as W, type VarsResolveInfo as X, type WebhookEventDoc as Y, defineVars as Z, ensureIndexes as _, type Contact as a, validateSenderDomain as a0, varsJsonSchema as a1, type SendResult as b, type MailTesterFeedback as c, Mailer as d, type SuppressionScope as e, type SegmentFilter as f, type AuditLogDoc as g, type BroadcastStatus as h, type CircuitBreakerThresholds as i, type Collections as j, type ContactTagDoc as k, type FlowDoc as l, type FlowGoal as m, type FlowRunDoc as n, type FlowRunStatus as o, type FlowVersionDoc as p, type HealthStatus as q, type MailerConfig as r, NullProvider as s, RESERVED_VAR_KEYS as t, type RedisOptions as u, type SegmentDefinition as v, type SendDoc as w, type SendStatus as x, type SenderDomainConfig as y, type SenderDomainRegistry as z };
|
|
@@ -47,6 +47,24 @@ interface ContactAdapter {
|
|
|
47
47
|
addTags?(externalId: string, tags: string[]): Promise<void>;
|
|
48
48
|
removeTags?(externalId: string, tags: string[]): Promise<void>;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Constrains WHEN a send step's email may go out. The flow's waits decide the
|
|
52
|
+
* earliest moment (T + N days); the window then pushes that moment forward —
|
|
53
|
+
* never backward — to the next allowed slot:
|
|
54
|
+
*
|
|
55
|
+
* - `timeOfDay` — deliver at this local wall-clock time ('HH:mm'). A send
|
|
56
|
+
* arriving after that time waits for the next day's slot (with a short
|
|
57
|
+
* grace period so tick jitter doesn't add 24h).
|
|
58
|
+
* - `weekdaysOnly` — a slot landing on Saturday/Sunday moves to Monday.
|
|
59
|
+
* - `useContactTimezone` — interpret times in `contact.timezone` when set,
|
|
60
|
+
* else fall back to `timezone` (IANA name, default UTC).
|
|
61
|
+
*/
|
|
62
|
+
interface DeliveryWindow {
|
|
63
|
+
weekdaysOnly?: boolean;
|
|
64
|
+
timeOfDay?: string;
|
|
65
|
+
useContactTimezone?: boolean;
|
|
66
|
+
timezone?: string;
|
|
67
|
+
}
|
|
50
68
|
type FlowStep = {
|
|
51
69
|
type: 'wait';
|
|
52
70
|
value: number;
|
|
@@ -65,6 +83,7 @@ type FlowStep = {
|
|
|
65
83
|
templateSlug: string;
|
|
66
84
|
providerOverride?: string;
|
|
67
85
|
vars?: Record<string, unknown>;
|
|
86
|
+
delivery?: DeliveryWindow;
|
|
68
87
|
} | {
|
|
69
88
|
type: 'tag';
|
|
70
89
|
addTags?: string[];
|
|
@@ -375,7 +394,7 @@ type QueueDriverConfig = {
|
|
|
375
394
|
* server-shaped interfaces.
|
|
376
395
|
*/
|
|
377
396
|
type SubscriptionStatus = 'subscribed' | 'pending_doi' | 'unsubscribed' | 'bounced' | 'complained';
|
|
378
|
-
type SendStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed' | 'suppressed';
|
|
397
|
+
type SendStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed' | 'suppressed' | 'cancelled';
|
|
379
398
|
type TemplateKind = 'transactional' | 'marketing';
|
|
380
399
|
type SuppressionScope = 'all' | 'marketing' | 'transactional';
|
|
381
400
|
type SuppressionReason = 'unsubscribed' | 'hard_bounce' | 'complaint' | 'manual' | 'list_cleaning' | 'gdpr_forget';
|
|
@@ -417,6 +436,63 @@ type SenderDomainValidation = {
|
|
|
417
436
|
};
|
|
418
437
|
declare function validateSenderDomain(fromEmail: string, templateKind: TemplateKind, registry: SenderDomainRegistry | undefined): SenderDomainValidation;
|
|
419
438
|
|
|
439
|
+
/**
|
|
440
|
+
* VarsAdapter — host-provided template variables, resolved at render time.
|
|
441
|
+
*
|
|
442
|
+
* The host declares a zod schema (the contract templates can rely on) plus a
|
|
443
|
+
* `resolve` function that loads those values from the host's own database for
|
|
444
|
+
* a given contact. Resolved keys are merged into the render context root, so
|
|
445
|
+
* a schema key `user` is referenced in templates as `{{user.name}}`.
|
|
446
|
+
*
|
|
447
|
+
* The schema does double duty: it is exposed to the admin SPA as JSON Schema
|
|
448
|
+
* (GET /vars-schema) to drive editor autocomplete, and the content linter
|
|
449
|
+
* uses it to flag `{{paths}}` that don't exist.
|
|
450
|
+
*/
|
|
451
|
+
|
|
452
|
+
interface VarsResolveInfo {
|
|
453
|
+
/** Why the vars are being resolved. Previews and tests should be side-effect free. */
|
|
454
|
+
reason: 'send' | 'preview' | 'test';
|
|
455
|
+
/** Slug of the template being rendered, when known. */
|
|
456
|
+
templateSlug?: string;
|
|
457
|
+
/** Slug of the flow the send belongs to, when the render is part of a flow run. */
|
|
458
|
+
flowSlug?: string;
|
|
459
|
+
/** Name of the event that triggered the flow run, when applicable. */
|
|
460
|
+
eventName?: string;
|
|
461
|
+
/**
|
|
462
|
+
* Properties of the triggering event (`mailer.fire(name, id, properties)`).
|
|
463
|
+
* This is how a resolver scopes lookups for account/topic flows:
|
|
464
|
+
* `info.eventProperties?.accountId` tells it WHICH account the run is about.
|
|
465
|
+
* Also available raw in templates as `{{event.*}}`.
|
|
466
|
+
*/
|
|
467
|
+
eventProperties?: Record<string, unknown>;
|
|
468
|
+
}
|
|
469
|
+
interface VarsAdapter<S extends z.ZodType = z.ZodType> {
|
|
470
|
+
/** Contract for what `resolve` returns. Root keys become root template variables. */
|
|
471
|
+
schema: S;
|
|
472
|
+
/** Load the variables for one contact from the host's data. */
|
|
473
|
+
resolve(contact: Contact, info: VarsResolveInfo): Promise<z.infer<S>> | z.infer<S>;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Identity helper that pins `resolve`'s return type to `z.infer<schema>` —
|
|
477
|
+
* without it, TypeScript widens the schema generic and the return type is
|
|
478
|
+
* unchecked.
|
|
479
|
+
*
|
|
480
|
+
* const varsAdapter = defineVars({
|
|
481
|
+
* schema: z.object({ user: z.object({ name: z.string() }) }),
|
|
482
|
+
* async resolve(contact) {
|
|
483
|
+
* return { user: { name: await lookupName(contact.externalId) } }
|
|
484
|
+
* },
|
|
485
|
+
* })
|
|
486
|
+
*/
|
|
487
|
+
declare function defineVars<S extends z.ZodType>(adapter: VarsAdapter<S>): VarsAdapter<S>;
|
|
488
|
+
/**
|
|
489
|
+
* Render-context keys mailery owns. Resolved vars never override these — a
|
|
490
|
+
* schema that declares one is rejected at Mailer.init.
|
|
491
|
+
*/
|
|
492
|
+
declare const RESERVED_VAR_KEYS: readonly ["contact", "vars", "event", "unsubscribeUrl", "viewInBrowserUrl", "preferenceCenterUrl", "senderAddress"];
|
|
493
|
+
/** JSON Schema for the adapter's zod schema (wire format for the admin SPA + linter). */
|
|
494
|
+
declare function varsJsonSchema(adapter: VarsAdapter): Record<string, unknown>;
|
|
495
|
+
|
|
420
496
|
/**
|
|
421
497
|
* Mailer configuration shape. Required + optional surfaces with sane defaults.
|
|
422
498
|
*/
|
|
@@ -531,6 +607,14 @@ interface MailerConfig {
|
|
|
531
607
|
db: Db;
|
|
532
608
|
collectionPrefix?: string;
|
|
533
609
|
adapter: ContactAdapter;
|
|
610
|
+
/**
|
|
611
|
+
* Optional host-provided template variables. `resolve(contact)` runs at
|
|
612
|
+
* send/preview/test render time; its result is merged into the template
|
|
613
|
+
* context root (schema key `user` → `{{user.name}}`). The zod schema
|
|
614
|
+
* drives admin-editor autocomplete and the `unknown_variable` lint rule.
|
|
615
|
+
* Build one with `defineVars({ schema, resolve })`.
|
|
616
|
+
*/
|
|
617
|
+
varsAdapter?: VarsAdapter<any>;
|
|
534
618
|
/**
|
|
535
619
|
* Queue driver selection. One of:
|
|
536
620
|
* - `{ driver: 'bull', redis: ... }` — BullMQ (default for prod; requires Redis)
|
|
@@ -734,7 +818,7 @@ interface FlowVersionDoc {
|
|
|
734
818
|
}
|
|
735
819
|
interface FlowRunHistoryEntry {
|
|
736
820
|
stepIndex: number;
|
|
737
|
-
action: 'entered' | 'wait_started' | 'wait_completed' | 'condition_evaluated' | 'branch_taken' | 'sent' | 'send_skipped' | 'tagged' | 'event_fired' | 'webhook_called' | 'exited' | 'failed';
|
|
821
|
+
action: 'entered' | 'wait_started' | 'wait_completed' | 'condition_evaluated' | 'branch_taken' | 'sent' | 'send_skipped' | 'send_deferred' | 'tagged' | 'event_fired' | 'webhook_called' | 'exited' | 'failed';
|
|
738
822
|
at: Date;
|
|
739
823
|
details?: Record<string, unknown>;
|
|
740
824
|
}
|
|
@@ -745,6 +829,17 @@ interface FlowRunDoc {
|
|
|
745
829
|
flowSlug: string;
|
|
746
830
|
flowVersion: number;
|
|
747
831
|
emailAtEntry: string;
|
|
832
|
+
/**
|
|
833
|
+
* Snapshot of the event that triggered this run. Properties surface in
|
|
834
|
+
* templates as `{{event.*}}` and in `varsAdapter.resolve` via
|
|
835
|
+
* `info.eventProperties` — this is how account/topic-scoped flows know
|
|
836
|
+
* which account or topic the run is about. Null for non-event entries.
|
|
837
|
+
*/
|
|
838
|
+
triggerEvent?: {
|
|
839
|
+
name: string;
|
|
840
|
+
properties: Record<string, unknown>;
|
|
841
|
+
occurredAt: Date;
|
|
842
|
+
} | null;
|
|
748
843
|
enteredAt: Date;
|
|
749
844
|
status: FlowRunStatus;
|
|
750
845
|
currentStepIndex: number;
|
|
@@ -1224,6 +1319,7 @@ interface RunnerContext {
|
|
|
1224
1319
|
db: Db;
|
|
1225
1320
|
collections: Collections;
|
|
1226
1321
|
adapter: ContactAdapter;
|
|
1322
|
+
varsAdapter?: VarsAdapter;
|
|
1227
1323
|
providers: Record<string, MailProvider>;
|
|
1228
1324
|
queues: Queues;
|
|
1229
1325
|
config: ResolvedConfig;
|
|
@@ -1297,6 +1393,33 @@ declare class Mailer {
|
|
|
1297
1393
|
suppress(email: string, opts: Omit<SuppressInput, 'email'>): Promise<void>;
|
|
1298
1394
|
tag(externalId: string, tag: string): Promise<void>;
|
|
1299
1395
|
untag(externalId: string, tag: string): Promise<void>;
|
|
1396
|
+
/**
|
|
1397
|
+
* Abort every active run of one flow for a contact, immediately. Runs parked
|
|
1398
|
+
* in a `wait` exit too — their delayed wake-up jobs find the run exited and
|
|
1399
|
+
* no-op. Also cancels any of the flow's emails still sitting in the send
|
|
1400
|
+
* queue for this contact (queued or awaiting retry), so an abort means no
|
|
1401
|
+
* further mail, not just no further steps.
|
|
1402
|
+
*
|
|
1403
|
+
* No-op (returns zero counts) when nothing is active. Safe to call from the
|
|
1404
|
+
* same handler that processes the business event ("user upgraded").
|
|
1405
|
+
*/
|
|
1406
|
+
abortFlow(flowSlug: string, externalId: string, opts?: {
|
|
1407
|
+
reason?: string;
|
|
1408
|
+
}): Promise<{
|
|
1409
|
+
abortedRuns: number;
|
|
1410
|
+
cancelledSends: number;
|
|
1411
|
+
}>;
|
|
1412
|
+
/**
|
|
1413
|
+
* Abort every active flow run for a contact across all flows. Same semantics
|
|
1414
|
+
* as `abortFlow` — for "stop everything" events (account deleted, churned).
|
|
1415
|
+
*/
|
|
1416
|
+
abortAllFlows(externalId: string, opts?: {
|
|
1417
|
+
reason?: string;
|
|
1418
|
+
}): Promise<{
|
|
1419
|
+
abortedRuns: number;
|
|
1420
|
+
cancelledSends: number;
|
|
1421
|
+
}>;
|
|
1422
|
+
private abortActiveRuns;
|
|
1300
1423
|
/**
|
|
1301
1424
|
* GDPR right-to-erasure. Hard-deletes the contact's PII and leaves a hashed
|
|
1302
1425
|
* suppression row to block re-import. INVARIANT 9.
|
|
@@ -1346,4 +1469,4 @@ declare class NullProvider implements MailProvider {
|
|
|
1346
1469
|
reset(): void;
|
|
1347
1470
|
}
|
|
1348
1471
|
|
|
1349
|
-
export { type AdapterFilter as A, type BroadcastDoc as B, type ContactAdapter as C, type
|
|
1472
|
+
export { getCollections as $, type AdapterFilter as A, type BroadcastDoc as B, type ContactAdapter as C, type DeliveryWindow as D, type EventDoc as E, type FlowStep as F, type SenderDomainValidation as G, type HealthDoc as H, type SubscriptionDoc as I, type SubscriptionStatus as J, type SuppressionDoc as K, type LeadDoc as L, type MailProvider as M, type NormalizedEvent as N, type OutboxDoc as O, type Predicate as P, type SuppressionReason as Q, type RunnerContext as R, type SendArgs as S, type TemplateDoc as T, type TemplateKind as U, type TemplateVersionDoc as V, type VarsAdapter as W, type VarsResolveInfo as X, type WebhookEventDoc as Y, defineVars as Z, ensureIndexes as _, type Contact as a, validateSenderDomain as a0, varsJsonSchema as a1, type SendResult as b, type MailTesterFeedback as c, Mailer as d, type SuppressionScope as e, type SegmentFilter as f, type AuditLogDoc as g, type BroadcastStatus as h, type CircuitBreakerThresholds as i, type Collections as j, type ContactTagDoc as k, type FlowDoc as l, type FlowGoal as m, type FlowRunDoc as n, type FlowRunStatus as o, type FlowVersionDoc as p, type HealthStatus as q, type MailerConfig as r, NullProvider as s, RESERVED_VAR_KEYS as t, type RedisOptions as u, type SegmentDefinition as v, type SendDoc as w, type SendStatus as x, type SenderDomainConfig as y, type SenderDomainRegistry as z };
|