mailery 0.0.0 → 0.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/dist/index.d.cts CHANGED
@@ -1,3 +1,243 @@
1
- declare const VERSION = "0.0.0";
1
+ import { C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, N as NormalizedEvent, c as Mailer, T as TemplateDoc, d as SuppressionScope } from './null-7gnz1V98.cjs';
2
+ export { e as AuditLogDoc, B as BroadcastDoc, f as BroadcastStatus, g as CircuitBreakerThresholds, h as Collections, i as ContactTagDoc, E as EventDoc, F as FlowDoc, j as FlowGoal, k as FlowRunDoc, l as FlowRunStatus, m as FlowStep, n as FlowVersionDoc, H as HealthDoc, o as HealthStatus, L as LeadDoc, p as MailerConfig, q as NullProvider, O as OutboxDoc, P as Predicate, R as RedisOptions, r as SegmentDefinition, s as SegmentFilter, t as SendDoc, u as SendStatus, v as SubscriptionDoc, w as SubscriptionStatus, x as SuppressionDoc, y as SuppressionReason, z as TemplateKind, D as TemplateVersionDoc, W as WebhookEventDoc, G as ensureIndexes, I as getCollections } from './null-7gnz1V98.cjs';
3
+ import { Db, Filter } from 'mongodb';
4
+ import { Request, Router } from 'express';
5
+ import Handlebars from 'handlebars';
6
+ import 'ioredis';
7
+ import 'zod';
2
8
 
3
- export { VERSION };
9
+ /**
10
+ * MongoContactAdapter — reads contacts directly from the host's `users`
11
+ * collection (read-mostly; optional narrow tag writes). Mailer never
12
+ * duplicates identity data — the host is the source of truth.
13
+ */
14
+
15
+ interface MongoContactAdapterOptions {
16
+ db: Db;
17
+ collection: string;
18
+ emailField?: string;
19
+ idField?: string;
20
+ /** Path to the tags array on the user document. */
21
+ tagsField?: string;
22
+ /** When true, mailer writes tags via `$addToSet` / `$pull` on the user doc. */
23
+ tagsWritable?: boolean;
24
+ /** 'strings' = ['vip','beta'], 'objects' = [{ name: 'vip' }]. */
25
+ tagsArrayShape?: 'strings' | 'objects';
26
+ /** Customize the projection mailer sees. Defaults pick up email + tags + a few common fields. */
27
+ toContact?: (userDoc: any) => Contact;
28
+ /** Customize how AdapterFilter becomes a Mongo query. */
29
+ translateFilter?: (filter: AdapterFilter) => Filter<any>;
30
+ /** Per-call default for query() limit. */
31
+ batchSize?: number;
32
+ }
33
+ declare class MongoContactAdapter implements ContactAdapter {
34
+ private readonly col;
35
+ private readonly emailField;
36
+ private readonly idField;
37
+ private readonly tagsField;
38
+ private readonly tagsWritable;
39
+ private readonly tagsArrayShape;
40
+ private readonly toContactFn;
41
+ private readonly translateFilterFn;
42
+ private readonly batchSize;
43
+ constructor(opts: MongoContactAdapterOptions);
44
+ getById(externalId: string): Promise<Contact | null>;
45
+ getByEmail(email: string): Promise<Contact | null>;
46
+ getBatch(externalIds: string[]): Promise<Map<string, Contact>>;
47
+ query(filter: AdapterFilter, opts: {
48
+ limit: number;
49
+ cursor?: string;
50
+ }): Promise<{
51
+ contacts: Contact[];
52
+ nextCursor?: string;
53
+ }>;
54
+ count(filter: AdapterFilter): Promise<number>;
55
+ addTags?: (externalId: string, tags: string[]) => Promise<void>;
56
+ removeTags?: (externalId: string, tags: string[]) => Promise<void>;
57
+ private idFilter;
58
+ private defaultToContact;
59
+ private defaultTranslateFilter;
60
+ private addTagsImpl;
61
+ private removeTagsImpl;
62
+ }
63
+
64
+ /**
65
+ * SendGridProvider — sends mail through @sendgrid/mail, verifies the Event
66
+ * Webhook signature with the ECDSA public key configured in SendGrid, and
67
+ * normalizes inbound event payloads into our shared shape.
68
+ *
69
+ * Setup steps required on the SendGrid side (one-time):
70
+ * 1. Authenticate sender domain (SPF, DKIM, DMARC).
71
+ * 2. Configure event webhook → POST to https://your.host/m/webhooks/sendgrid
72
+ * 3. Enable: delivered, open, click, bounce, dropped, spamreport, unsubscribe
73
+ * 4. Generate Signed Event Webhook key → store as webhookVerificationKey
74
+ */
75
+
76
+ interface SendGridProviderOptions {
77
+ apiKey: string;
78
+ /** ECDSA public key (PEM) from SendGrid → Settings → Mail Settings → Signed Event Webhook. */
79
+ webhookVerificationKey?: string;
80
+ /** Send-rate cap per second (BullMQ group limiter consults this). */
81
+ sendRatePerSecond?: number;
82
+ /** Sandbox mode bypasses actual delivery — useful in dev/test. */
83
+ sandbox?: boolean;
84
+ }
85
+ declare class SendGridProvider implements MailProvider {
86
+ private readonly opts;
87
+ readonly name = "sendgrid";
88
+ readonly sendRatePerSecond: number;
89
+ constructor(opts: SendGridProviderOptions);
90
+ send(args: SendArgs): Promise<SendResult>;
91
+ verifyWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<boolean>;
92
+ parseWebhookEvents(payload: unknown): NormalizedEvent[];
93
+ }
94
+
95
+ /**
96
+ * Admin router — serves the prebuilt React SPA + REST endpoints the SPA
97
+ * consumes. Mount inside a host Express app, gated by host auth.
98
+ *
99
+ * app.use('/admin/mailer', requireAdmin, createAdminRouter(mailer))
100
+ *
101
+ * REST routes under /api/* are documented in plans/14-admin-api.md.
102
+ */
103
+
104
+ interface AdminRouterOptions {
105
+ /** Override path to the built SPA. Defaults to `dist/admin/spa` shipped with the package. */
106
+ spaDir?: string;
107
+ /** Resolve actor metadata from a Request. Defaults to `human:${req.user?.email || 'anonymous'}`. */
108
+ getActor?: (req: Request) => string;
109
+ }
110
+ declare function createAdminRouter(mailer: Mailer, opts?: AdminRouterOptions): Router;
111
+
112
+ /**
113
+ * Public router — endpoints that must be reachable by email clients and
114
+ * provider webhooks. Mount under your tracking base path (default `/m`).
115
+ *
116
+ * app.use('/m', createPublicRouter(mailer))
117
+ *
118
+ * Routes:
119
+ * GET /open/:sendId.png — open pixel (records open, returns 1×1 PNG)
120
+ * GET /click/:sendId/:linkId — click redirect (records click, 302 → target)
121
+ * GET /unsub/:token — confirmation page (one-click POST link)
122
+ * POST /unsub/:token — RFC 8058 one-click unsubscribe
123
+ * POST /webhooks/:provider — inbound provider event webhook
124
+ */
125
+
126
+ interface PublicRouterOptions {
127
+ /**
128
+ * Path on disk where unsubscribe events fall back to when Mongo is degraded.
129
+ * Defaults to /tmp/mailery-pending-unsubs.jsonl.
130
+ */
131
+ pendingUnsubsPath?: string;
132
+ }
133
+ declare function createPublicRouter(mailer: Mailer, opts?: PublicRouterOptions): Router;
134
+
135
+ /**
136
+ * Template render pipeline.
137
+ *
138
+ * authorMjml + handlebarsContext
139
+ * ↓ Handlebars render → MJML with substituted vars
140
+ * ↓ mjml-core compile → HTML
141
+ * ↓ html-to-text derive → plain text alternative
142
+ * ↓ applyTracking(sendId) → tracked HTML with rewritten links + open pixel
143
+ *
144
+ * Subject and preheader run through Handlebars too. Plain text is auto-derived
145
+ * unless the template explicitly overrides it.
146
+ */
147
+
148
+ interface CompileResult {
149
+ html: string;
150
+ plainText: string;
151
+ errors: Array<{
152
+ line?: number;
153
+ message: string;
154
+ tagName?: string;
155
+ formattedMessage?: string;
156
+ }>;
157
+ }
158
+ /** Compile MJML → HTML, then derive plain text. Called at template publish time. */
159
+ declare function compileTemplate(mjml: string): Promise<CompileResult>;
160
+ /** Auto-derive plain text from compiled HTML. */
161
+ declare function derivePlaintext(html: string): string;
162
+ interface RenderContext {
163
+ contact: Contact;
164
+ vars: Record<string, unknown>;
165
+ /** URL the recipient hits to one-click unsubscribe. */
166
+ unsubscribeUrl: string;
167
+ /** URL to view this email in a browser (when implemented). */
168
+ viewInBrowserUrl?: string;
169
+ /** URL for the preference center (when implemented). */
170
+ preferenceCenterUrl?: string;
171
+ /** Configured sender postal address (CAN-SPAM). */
172
+ senderAddress?: string;
173
+ }
174
+ interface RenderedTemplate {
175
+ subject: string;
176
+ preheader: string;
177
+ html: string;
178
+ plainText: string;
179
+ fromName: string;
180
+ fromEmail: string;
181
+ replyTo: string | null;
182
+ }
183
+ interface RenderOptions {
184
+ /** Extra Handlebars helpers contributed by the host. */
185
+ helpers?: Record<string, Handlebars.HelperDelegate>;
186
+ }
187
+ /**
188
+ * Render a published template against a contact + vars context. Returns the
189
+ * substituted subject/preheader/html/plainText. Tracking is NOT applied here —
190
+ * that step needs the send id and runs separately via `applyTracking`.
191
+ */
192
+ declare function renderTemplate(template: TemplateDoc, ctx: RenderContext, opts?: RenderOptions): Promise<RenderedTemplate>;
193
+ interface TrackingOptions {
194
+ sendId: string;
195
+ publicUrl: string;
196
+ trackOpens: boolean;
197
+ trackClicks: boolean;
198
+ /** URL that must NOT be rewritten (e.g. the resolved unsubscribe URL). */
199
+ preserveUrls?: string[];
200
+ }
201
+ interface TrackingResult {
202
+ html: string;
203
+ /** linkId → original URL map; persist on `mailer_sends.links` for click resolution. */
204
+ links: Array<{
205
+ linkId: string;
206
+ url: string;
207
+ }>;
208
+ }
209
+ /**
210
+ * Rewrite `<a href>` in `html` to /m/click/<sendId>/<linkId>?... and append an
211
+ * open pixel. Returns the modified HTML plus the link map to persist on the
212
+ * send document.
213
+ */
214
+ declare function applyTracking(html: string, opts: TrackingOptions): TrackingResult;
215
+
216
+ /**
217
+ * HMAC-signed tokens for unsubscribe + preference-center URLs.
218
+ *
219
+ * Format: base64url(payload) '.' base64url(hmac)
220
+ * payload = JSON.stringify({ e: email, s: scope, x: expiresAtMs })
221
+ * hmac = HMAC-SHA256(secret, payload)
222
+ *
223
+ * Tokens expire because long-lived signed URLs are a liability.
224
+ */
225
+
226
+ interface UnsubscribeTokenPayload {
227
+ email: string;
228
+ scope: SuppressionScope;
229
+ expiresAt: Date;
230
+ }
231
+ declare function signUnsubscribeToken(payload: UnsubscribeTokenPayload, secret: string): string;
232
+ declare function verifyUnsubscribeToken(token: string, secret: string, now?: Date): UnsubscribeTokenPayload | null;
233
+ /**
234
+ * sha256 hex digest, used for storing email hashes (GDPR forget) and dedup helpers.
235
+ */
236
+ declare function sha256Hex(input: string): string;
237
+
238
+ /**
239
+ * Public exports for the `mailery` package.
240
+ */
241
+ declare const VERSION = "0.1.0";
242
+
243
+ export { AdapterFilter, type AdminRouterOptions, Contact, ContactAdapter, MailProvider, Mailer, MongoContactAdapter, type MongoContactAdapterOptions, NormalizedEvent, type PublicRouterOptions, SendArgs, SendGridProvider, type SendGridProviderOptions, SendResult, SuppressionScope, TemplateDoc, VERSION, applyTracking, compileTemplate, createAdminRouter, createPublicRouter, derivePlaintext, renderTemplate, sha256Hex, signUnsubscribeToken, verifyUnsubscribeToken };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,243 @@
1
- declare const VERSION = "0.0.0";
1
+ import { C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, N as NormalizedEvent, c as Mailer, T as TemplateDoc, d as SuppressionScope } from './null-7gnz1V98.js';
2
+ export { e as AuditLogDoc, B as BroadcastDoc, f as BroadcastStatus, g as CircuitBreakerThresholds, h as Collections, i as ContactTagDoc, E as EventDoc, F as FlowDoc, j as FlowGoal, k as FlowRunDoc, l as FlowRunStatus, m as FlowStep, n as FlowVersionDoc, H as HealthDoc, o as HealthStatus, L as LeadDoc, p as MailerConfig, q as NullProvider, O as OutboxDoc, P as Predicate, R as RedisOptions, r as SegmentDefinition, s as SegmentFilter, t as SendDoc, u as SendStatus, v as SubscriptionDoc, w as SubscriptionStatus, x as SuppressionDoc, y as SuppressionReason, z as TemplateKind, D as TemplateVersionDoc, W as WebhookEventDoc, G as ensureIndexes, I as getCollections } from './null-7gnz1V98.js';
3
+ import { Db, Filter } from 'mongodb';
4
+ import { Request, Router } from 'express';
5
+ import Handlebars from 'handlebars';
6
+ import 'ioredis';
7
+ import 'zod';
2
8
 
3
- export { VERSION };
9
+ /**
10
+ * MongoContactAdapter — reads contacts directly from the host's `users`
11
+ * collection (read-mostly; optional narrow tag writes). Mailer never
12
+ * duplicates identity data — the host is the source of truth.
13
+ */
14
+
15
+ interface MongoContactAdapterOptions {
16
+ db: Db;
17
+ collection: string;
18
+ emailField?: string;
19
+ idField?: string;
20
+ /** Path to the tags array on the user document. */
21
+ tagsField?: string;
22
+ /** When true, mailer writes tags via `$addToSet` / `$pull` on the user doc. */
23
+ tagsWritable?: boolean;
24
+ /** 'strings' = ['vip','beta'], 'objects' = [{ name: 'vip' }]. */
25
+ tagsArrayShape?: 'strings' | 'objects';
26
+ /** Customize the projection mailer sees. Defaults pick up email + tags + a few common fields. */
27
+ toContact?: (userDoc: any) => Contact;
28
+ /** Customize how AdapterFilter becomes a Mongo query. */
29
+ translateFilter?: (filter: AdapterFilter) => Filter<any>;
30
+ /** Per-call default for query() limit. */
31
+ batchSize?: number;
32
+ }
33
+ declare class MongoContactAdapter implements ContactAdapter {
34
+ private readonly col;
35
+ private readonly emailField;
36
+ private readonly idField;
37
+ private readonly tagsField;
38
+ private readonly tagsWritable;
39
+ private readonly tagsArrayShape;
40
+ private readonly toContactFn;
41
+ private readonly translateFilterFn;
42
+ private readonly batchSize;
43
+ constructor(opts: MongoContactAdapterOptions);
44
+ getById(externalId: string): Promise<Contact | null>;
45
+ getByEmail(email: string): Promise<Contact | null>;
46
+ getBatch(externalIds: string[]): Promise<Map<string, Contact>>;
47
+ query(filter: AdapterFilter, opts: {
48
+ limit: number;
49
+ cursor?: string;
50
+ }): Promise<{
51
+ contacts: Contact[];
52
+ nextCursor?: string;
53
+ }>;
54
+ count(filter: AdapterFilter): Promise<number>;
55
+ addTags?: (externalId: string, tags: string[]) => Promise<void>;
56
+ removeTags?: (externalId: string, tags: string[]) => Promise<void>;
57
+ private idFilter;
58
+ private defaultToContact;
59
+ private defaultTranslateFilter;
60
+ private addTagsImpl;
61
+ private removeTagsImpl;
62
+ }
63
+
64
+ /**
65
+ * SendGridProvider — sends mail through @sendgrid/mail, verifies the Event
66
+ * Webhook signature with the ECDSA public key configured in SendGrid, and
67
+ * normalizes inbound event payloads into our shared shape.
68
+ *
69
+ * Setup steps required on the SendGrid side (one-time):
70
+ * 1. Authenticate sender domain (SPF, DKIM, DMARC).
71
+ * 2. Configure event webhook → POST to https://your.host/m/webhooks/sendgrid
72
+ * 3. Enable: delivered, open, click, bounce, dropped, spamreport, unsubscribe
73
+ * 4. Generate Signed Event Webhook key → store as webhookVerificationKey
74
+ */
75
+
76
+ interface SendGridProviderOptions {
77
+ apiKey: string;
78
+ /** ECDSA public key (PEM) from SendGrid → Settings → Mail Settings → Signed Event Webhook. */
79
+ webhookVerificationKey?: string;
80
+ /** Send-rate cap per second (BullMQ group limiter consults this). */
81
+ sendRatePerSecond?: number;
82
+ /** Sandbox mode bypasses actual delivery — useful in dev/test. */
83
+ sandbox?: boolean;
84
+ }
85
+ declare class SendGridProvider implements MailProvider {
86
+ private readonly opts;
87
+ readonly name = "sendgrid";
88
+ readonly sendRatePerSecond: number;
89
+ constructor(opts: SendGridProviderOptions);
90
+ send(args: SendArgs): Promise<SendResult>;
91
+ verifyWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<boolean>;
92
+ parseWebhookEvents(payload: unknown): NormalizedEvent[];
93
+ }
94
+
95
+ /**
96
+ * Admin router — serves the prebuilt React SPA + REST endpoints the SPA
97
+ * consumes. Mount inside a host Express app, gated by host auth.
98
+ *
99
+ * app.use('/admin/mailer', requireAdmin, createAdminRouter(mailer))
100
+ *
101
+ * REST routes under /api/* are documented in plans/14-admin-api.md.
102
+ */
103
+
104
+ interface AdminRouterOptions {
105
+ /** Override path to the built SPA. Defaults to `dist/admin/spa` shipped with the package. */
106
+ spaDir?: string;
107
+ /** Resolve actor metadata from a Request. Defaults to `human:${req.user?.email || 'anonymous'}`. */
108
+ getActor?: (req: Request) => string;
109
+ }
110
+ declare function createAdminRouter(mailer: Mailer, opts?: AdminRouterOptions): Router;
111
+
112
+ /**
113
+ * Public router — endpoints that must be reachable by email clients and
114
+ * provider webhooks. Mount under your tracking base path (default `/m`).
115
+ *
116
+ * app.use('/m', createPublicRouter(mailer))
117
+ *
118
+ * Routes:
119
+ * GET /open/:sendId.png — open pixel (records open, returns 1×1 PNG)
120
+ * GET /click/:sendId/:linkId — click redirect (records click, 302 → target)
121
+ * GET /unsub/:token — confirmation page (one-click POST link)
122
+ * POST /unsub/:token — RFC 8058 one-click unsubscribe
123
+ * POST /webhooks/:provider — inbound provider event webhook
124
+ */
125
+
126
+ interface PublicRouterOptions {
127
+ /**
128
+ * Path on disk where unsubscribe events fall back to when Mongo is degraded.
129
+ * Defaults to /tmp/mailery-pending-unsubs.jsonl.
130
+ */
131
+ pendingUnsubsPath?: string;
132
+ }
133
+ declare function createPublicRouter(mailer: Mailer, opts?: PublicRouterOptions): Router;
134
+
135
+ /**
136
+ * Template render pipeline.
137
+ *
138
+ * authorMjml + handlebarsContext
139
+ * ↓ Handlebars render → MJML with substituted vars
140
+ * ↓ mjml-core compile → HTML
141
+ * ↓ html-to-text derive → plain text alternative
142
+ * ↓ applyTracking(sendId) → tracked HTML with rewritten links + open pixel
143
+ *
144
+ * Subject and preheader run through Handlebars too. Plain text is auto-derived
145
+ * unless the template explicitly overrides it.
146
+ */
147
+
148
+ interface CompileResult {
149
+ html: string;
150
+ plainText: string;
151
+ errors: Array<{
152
+ line?: number;
153
+ message: string;
154
+ tagName?: string;
155
+ formattedMessage?: string;
156
+ }>;
157
+ }
158
+ /** Compile MJML → HTML, then derive plain text. Called at template publish time. */
159
+ declare function compileTemplate(mjml: string): Promise<CompileResult>;
160
+ /** Auto-derive plain text from compiled HTML. */
161
+ declare function derivePlaintext(html: string): string;
162
+ interface RenderContext {
163
+ contact: Contact;
164
+ vars: Record<string, unknown>;
165
+ /** URL the recipient hits to one-click unsubscribe. */
166
+ unsubscribeUrl: string;
167
+ /** URL to view this email in a browser (when implemented). */
168
+ viewInBrowserUrl?: string;
169
+ /** URL for the preference center (when implemented). */
170
+ preferenceCenterUrl?: string;
171
+ /** Configured sender postal address (CAN-SPAM). */
172
+ senderAddress?: string;
173
+ }
174
+ interface RenderedTemplate {
175
+ subject: string;
176
+ preheader: string;
177
+ html: string;
178
+ plainText: string;
179
+ fromName: string;
180
+ fromEmail: string;
181
+ replyTo: string | null;
182
+ }
183
+ interface RenderOptions {
184
+ /** Extra Handlebars helpers contributed by the host. */
185
+ helpers?: Record<string, Handlebars.HelperDelegate>;
186
+ }
187
+ /**
188
+ * Render a published template against a contact + vars context. Returns the
189
+ * substituted subject/preheader/html/plainText. Tracking is NOT applied here —
190
+ * that step needs the send id and runs separately via `applyTracking`.
191
+ */
192
+ declare function renderTemplate(template: TemplateDoc, ctx: RenderContext, opts?: RenderOptions): Promise<RenderedTemplate>;
193
+ interface TrackingOptions {
194
+ sendId: string;
195
+ publicUrl: string;
196
+ trackOpens: boolean;
197
+ trackClicks: boolean;
198
+ /** URL that must NOT be rewritten (e.g. the resolved unsubscribe URL). */
199
+ preserveUrls?: string[];
200
+ }
201
+ interface TrackingResult {
202
+ html: string;
203
+ /** linkId → original URL map; persist on `mailer_sends.links` for click resolution. */
204
+ links: Array<{
205
+ linkId: string;
206
+ url: string;
207
+ }>;
208
+ }
209
+ /**
210
+ * Rewrite `<a href>` in `html` to /m/click/<sendId>/<linkId>?... and append an
211
+ * open pixel. Returns the modified HTML plus the link map to persist on the
212
+ * send document.
213
+ */
214
+ declare function applyTracking(html: string, opts: TrackingOptions): TrackingResult;
215
+
216
+ /**
217
+ * HMAC-signed tokens for unsubscribe + preference-center URLs.
218
+ *
219
+ * Format: base64url(payload) '.' base64url(hmac)
220
+ * payload = JSON.stringify({ e: email, s: scope, x: expiresAtMs })
221
+ * hmac = HMAC-SHA256(secret, payload)
222
+ *
223
+ * Tokens expire because long-lived signed URLs are a liability.
224
+ */
225
+
226
+ interface UnsubscribeTokenPayload {
227
+ email: string;
228
+ scope: SuppressionScope;
229
+ expiresAt: Date;
230
+ }
231
+ declare function signUnsubscribeToken(payload: UnsubscribeTokenPayload, secret: string): string;
232
+ declare function verifyUnsubscribeToken(token: string, secret: string, now?: Date): UnsubscribeTokenPayload | null;
233
+ /**
234
+ * sha256 hex digest, used for storing email hashes (GDPR forget) and dedup helpers.
235
+ */
236
+ declare function sha256Hex(input: string): string;
237
+
238
+ /**
239
+ * Public exports for the `mailery` package.
240
+ */
241
+ declare const VERSION = "0.1.0";
242
+
243
+ export { AdapterFilter, type AdminRouterOptions, Contact, ContactAdapter, MailProvider, Mailer, MongoContactAdapter, type MongoContactAdapterOptions, NormalizedEvent, type PublicRouterOptions, SendArgs, SendGridProvider, type SendGridProviderOptions, SendResult, SuppressionScope, TemplateDoc, VERSION, applyTracking, compileTemplate, createAdminRouter, createPublicRouter, derivePlaintext, renderTemplate, sha256Hex, signUnsubscribeToken, verifyUnsubscribeToken };