mailery 0.10.0 → 0.10.2
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.cjs +9 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +2 -0
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +2 -0
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/adapters/vars.ts","../src/server/adapters/mongo.ts","../src/server/providers/sendgrid.ts","../src/shared/schemas.ts","../src/server/config.ts","../src/server/models/index.ts","../src/server/events.ts","../src/server/tokens.ts","../src/server/queues/bull.ts","../src/server/queues/agenda.ts","../src/server/queues/noop.ts","../src/server/queues/index.ts","../src/server/runner/triggers.ts","../src/server/templates/sender-domain.ts","../src/server/runner/health.ts","../src/server/runner/webhook.ts","../src/server/runner/predicate.ts","../src/server/runner/delivery-window.ts","../src/server/templates/render.ts","../src/server/runner/send.ts","../src/server/runner/suppression.ts","../src/server/runner/step.ts","../src/server/runner/sweep.ts","../src/server/runner/broadcasts.ts","../src/server/runner/bounce-promotion.ts","../src/server/runner/dnsbl.ts","../src/server/runner/postmaster.ts","../src/server/runner/snds.ts","../src/server/runner/dmarc.ts","../src/server/runner/tick.ts","../src/server/mailer.ts","../src/server/index.ts","../src/server/providers/null.ts","../src/server/templates/linter.ts","../src/server/api/admin.ts","../src/server/api/setup-status.ts","../src/server/runner/hygiene.ts","../src/server/runner/mail-tester.ts","../src/server/api/public.ts","../src/shared/options.ts"],"names":["RESERVED_VAR_KEYS","z","MongoContactAdapter","ObjectId","SendGridProvider","sgMail","crypto","IORedis","QUEUE_NAMES","counter","mjml2html","htmlToText","Handlebars","branchKey","DAY_MS","dns","net","psl","path","FETCH_TIMEOUT_MS","safeText","dst","processScheduledBroadcasts","assertNoReservedVarKeys","ObjectIdCtor","cursor","__filename","fileURLToPath","__dirname","Router","express","r","report","multer","fs"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * VarsAdapter — host-provided template variables, resolved at render time.\n *\n * The host declares a zod schema (the contract templates can rely on) plus a\n * `resolve` function that loads those values from the host's own database for\n * a given contact. Resolved keys are merged into the render context root, so\n * a schema key `user` is referenced in templates as `{{user.name}}`.\n *\n * The schema does double duty: it is exposed to the admin SPA as JSON Schema\n * (GET /vars-schema) to drive editor autocomplete, and the content linter\n * uses it to flag `{{paths}}` that don't exist.\n */\n\nimport { z } from 'zod'\n\nimport type { Contact } from '../../shared/types.js'\n\nexport interface VarsResolveInfo {\n /** Why the vars are being resolved. Previews and tests should be side-effect free. */\n reason: 'send' | 'preview' | 'test'\n /** Slug of the template being rendered, when known. */\n templateSlug?: string\n /** Slug of the flow the send belongs to, when the render is part of a flow run. */\n flowSlug?: string\n /** Name of the event that triggered the flow run, when applicable. */\n eventName?: string\n /**\n * Properties of the triggering event (`mailer.fire(name, id, properties)`).\n * This is how a resolver scopes lookups for account/topic flows:\n * `info.eventProperties?.accountId` tells it WHICH account the run is about.\n * Also available raw in templates as `{{event.*}}`.\n */\n eventProperties?: Record<string, unknown>\n}\n\nexport interface VarsAdapter<S extends z.ZodType = z.ZodType> {\n /** Contract for what `resolve` returns. Root keys become root template variables. */\n schema: S\n /** Load the variables for one contact from the host's data. */\n resolve(contact: Contact, info: VarsResolveInfo): Promise<z.infer<S>> | z.infer<S>\n}\n\n/**\n * Identity helper that pins `resolve`'s return type to `z.infer<schema>` —\n * without it, TypeScript widens the schema generic and the return type is\n * unchecked.\n *\n * const varsAdapter = defineVars({\n * schema: z.object({ user: z.object({ name: z.string() }) }),\n * async resolve(contact) {\n * return { user: { name: await lookupName(contact.externalId) } }\n * },\n * })\n */\nexport function defineVars<S extends z.ZodType>(adapter: VarsAdapter<S>): VarsAdapter<S> {\n return adapter\n}\n\n/**\n * Render-context keys mailery owns. Resolved vars never override these — a\n * schema that declares one is rejected at Mailer.init.\n */\nexport const RESERVED_VAR_KEYS = [\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n] as const\n\n/**\n * Throw if the schema's root keys collide with reserved render-context keys.\n * Called once at Mailer.init — fail fast, not per send.\n */\nexport function assertNoReservedVarKeys(adapter: VarsAdapter): void {\n const json = varsJsonSchema(adapter)\n const props = json && typeof json === 'object' ? (json as any).properties : undefined\n if (!props) return\n const clashes = RESERVED_VAR_KEYS.filter((k) => k in props)\n if (clashes.length > 0) {\n throw new Error(\n `varsAdapter schema declares reserved key(s): ${clashes.join(', ')}. ` +\n `These names are provided by mailery itself — rename them in your schema.`,\n )\n }\n}\n\n/** JSON Schema for the adapter's zod schema (wire format for the admin SPA + linter). */\nexport function varsJsonSchema(adapter: VarsAdapter): Record<string, unknown> {\n return z.toJSONSchema(adapter.schema, { io: 'output' }) as Record<string, unknown>\n}\n\n/**\n * Resolve vars for a contact, or `{}` when no adapter is configured.\n * Errors propagate to the caller — send paths let the queue retry, preview\n * paths surface the message to the operator.\n */\nexport async function resolveVars(\n adapter: VarsAdapter | undefined,\n contact: Contact,\n info: VarsResolveInfo,\n): Promise<Record<string, unknown>> {\n if (!adapter) return {}\n const resolved = await adapter.resolve(contact, info)\n if (!resolved || typeof resolved !== 'object') return {}\n // Belt-and-braces: drop reserved keys even if the init-time assert was\n // bypassed (e.g. a hand-built adapter object with a lying schema).\n const out: Record<string, unknown> = { ...(resolved as Record<string, unknown>) }\n for (const k of RESERVED_VAR_KEYS) delete out[k]\n return out\n}\n","/**\n * MongoContactAdapter — reads contacts directly from the host's `users`\n * collection (read-mostly; optional narrow tag writes). Mailer never\n * duplicates identity data — the host is the source of truth.\n */\n\nimport type { Collection, Db, Filter } from 'mongodb'\nimport { ObjectId } from 'mongodb'\n\nimport type {\n AdapterFilter,\n Contact,\n ContactAdapter,\n} from '../../shared/types.js'\n\nexport interface MongoContactAdapterOptions {\n db: Db\n collection: string\n emailField?: string\n idField?: string\n /** Path to the tags array on the user document. */\n tagsField?: string\n /** When true, mailer writes tags via `$addToSet` / `$pull` on the user doc. */\n tagsWritable?: boolean\n /** 'strings' = ['vip','beta'], 'objects' = [{ name: 'vip' }]. */\n tagsArrayShape?: 'strings' | 'objects'\n /** Customize the projection mailer sees. Defaults pick up email + tags + a few common fields. */\n toContact?: (userDoc: any) => Contact\n /** Customize how AdapterFilter becomes a Mongo query. */\n translateFilter?: (filter: AdapterFilter) => Filter<any>\n /** Per-call default for query() limit. */\n batchSize?: number\n}\n\nexport class MongoContactAdapter implements ContactAdapter {\n private readonly col: Collection<any>\n private readonly emailField: string\n private readonly idField: string\n private readonly tagsField: string | null\n private readonly tagsWritable: boolean\n private readonly tagsArrayShape: 'strings' | 'objects'\n private readonly toContactFn: (doc: any) => Contact\n private readonly translateFilterFn: (filter: AdapterFilter) => Filter<any>\n private readonly batchSize: number\n\n constructor(opts: MongoContactAdapterOptions) {\n this.col = opts.db.collection(opts.collection)\n this.emailField = opts.emailField ?? 'email'\n this.idField = opts.idField ?? '_id'\n this.tagsField = opts.tagsField ?? null\n this.tagsWritable = !!opts.tagsWritable\n this.tagsArrayShape = opts.tagsArrayShape ?? 'strings'\n this.toContactFn = opts.toContact ?? this.defaultToContact.bind(this)\n this.translateFilterFn = opts.translateFilter ?? this.defaultTranslateFilter.bind(this)\n this.batchSize = opts.batchSize ?? 500\n\n // Only expose tag write methods if the host opted in.\n if (this.tagsWritable && this.tagsField) {\n this.addTags = this.addTagsImpl.bind(this)\n this.removeTags = this.removeTagsImpl.bind(this)\n }\n }\n\n async getById(externalId: string): Promise<Contact | null> {\n const filter = this.idFilter(externalId)\n const doc = await this.col.findOne(filter)\n return doc ? this.toContactFn(doc) : null\n }\n\n async getByEmail(email: string): Promise<Contact | null> {\n const doc = await this.col.findOne({ [this.emailField]: email.toLowerCase() })\n return doc ? this.toContactFn(doc) : null\n }\n\n async getBatch(externalIds: string[]): Promise<Map<string, Contact>> {\n if (externalIds.length === 0) return new Map()\n const tryObjectId = externalIds.every(canBeObjectId)\n const ids: any[] = tryObjectId ? externalIds.map((s) => new ObjectId(s)) : externalIds\n const docs = await this.col.find({ [this.idField]: { $in: ids } }).toArray()\n const out = new Map<string, Contact>()\n for (const doc of docs) {\n const c = this.toContactFn(doc)\n out.set(c.externalId, c)\n }\n return out\n }\n\n async query(\n filter: AdapterFilter,\n opts: { limit: number; cursor?: string },\n ): Promise<{ contacts: Contact[]; nextCursor?: string }> {\n const query = this.translateFilterFn(filter)\n const limit = Math.min(opts.limit, this.batchSize)\n\n // Cursor is an ObjectId-or-externalId encoded as a string; we use it as a >\n // bound on the idField for stable pagination ordered by id.\n if (opts.cursor) {\n const cursorVal = canBeObjectId(opts.cursor) ? new ObjectId(opts.cursor) : opts.cursor\n ;(query as any)[this.idField] = { ...((query as any)[this.idField] ?? {}), $gt: cursorVal }\n }\n\n const docs = await this.col\n .find(query)\n .sort({ [this.idField]: 1 })\n .limit(limit + 1)\n .toArray()\n\n const hasMore = docs.length > limit\n const slice = hasMore ? docs.slice(0, limit) : docs\n const contacts = slice.map((d) => this.toContactFn(d))\n const last = slice[slice.length - 1]\n const nextCursor = hasMore && last ? String((last as any)[this.idField]) : undefined\n return { contacts, nextCursor }\n }\n\n async count(filter: AdapterFilter): Promise<number> {\n const query = this.translateFilterFn(filter)\n return await this.col.countDocuments(query)\n }\n\n addTags?: (externalId: string, tags: string[]) => Promise<void>\n removeTags?: (externalId: string, tags: string[]) => Promise<void>\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private idFilter(externalId: string): Filter<any> {\n if (this.idField === '_id' && canBeObjectId(externalId)) {\n return { _id: new ObjectId(externalId) } as Filter<any>\n }\n return { [this.idField]: externalId }\n }\n\n private defaultToContact(doc: any): Contact {\n const tagsRaw = this.tagsField ? doc[this.tagsField] ?? [] : []\n const tags: string[] =\n this.tagsArrayShape === 'objects'\n ? (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t.name ?? t))\n : (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t))\n\n const externalId = String(doc[this.idField] ?? '')\n const email = String(doc[this.emailField] ?? '').toLowerCase()\n\n // Default projection: everything that's not _id / email / tags becomes a field.\n const fields: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(doc)) {\n if (k === this.idField || k === this.emailField || k === this.tagsField) continue\n fields[k] = v\n }\n\n return {\n externalId,\n email,\n tags,\n fields,\n timezone: typeof doc.timezone === 'string' ? doc.timezone : undefined,\n locale: typeof doc.locale === 'string' ? doc.locale : undefined,\n }\n }\n\n private defaultTranslateFilter(filter: AdapterFilter): Filter<any> {\n const q: Record<string, unknown> = {}\n\n if (filter.emailIn && filter.emailIn.length > 0) {\n q[this.emailField] = { $in: filter.emailIn.map((e) => e.toLowerCase()) }\n }\n if (filter.externalIdIn && filter.externalIdIn.length > 0) {\n const tryObjectId = filter.externalIdIn.every(canBeObjectId)\n q[this.idField] = {\n $in: tryObjectId ? filter.externalIdIn.map((s) => new ObjectId(s)) : filter.externalIdIn,\n }\n }\n if (filter.fieldEquals) {\n q[filter.fieldEquals.field] = filter.fieldEquals.value\n }\n if (filter.fieldIn) {\n q[filter.fieldIn.field] = { $in: filter.fieldIn.values }\n }\n if (filter.fieldExists) {\n q[filter.fieldExists] = { $exists: true }\n }\n if (filter.createdAfter || filter.createdBefore) {\n const r: any = {}\n if (filter.createdAfter) r.$gte = filter.createdAfter\n if (filter.createdBefore) r.$lte = filter.createdBefore\n q.createdAt = r\n }\n if (this.tagsField) {\n if (filter.hasTag) {\n q[this.tagsField] = filter.hasTag\n }\n if (filter.hasTagIn && filter.hasTagIn.length > 0) {\n q[this.tagsField] = { $in: filter.hasTagIn }\n }\n }\n return q\n }\n\n private async addTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? tags.map((name) => ({ name }))\n : tags\n await this.col.updateOne(this.idFilter(externalId), {\n $addToSet: { [this.tagsField]: { $each: value } } as any,\n })\n }\n\n private async removeTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? { $in: tags.map((name) => ({ name })) }\n : { $in: tags }\n await this.col.updateOne(this.idFilter(externalId), {\n $pull: { [this.tagsField]: value } as any,\n })\n }\n}\n\nfunction canBeObjectId(s: string): boolean {\n return typeof s === 'string' && /^[a-f0-9]{24}$/i.test(s)\n}\n","/**\n * SendGridProvider — sends mail through @sendgrid/mail, verifies the Event\n * Webhook signature with the ECDSA public key configured in SendGrid, and\n * normalizes inbound event payloads into our shared shape.\n *\n * Setup steps required on the SendGrid side (one-time):\n * 1. Authenticate sender domain (SPF, DKIM, DMARC).\n * 2. Configure event webhook → POST to https://your.host/m/webhooks/sendgrid\n * 3. Enable: delivered, open, click, bounce, dropped, spamreport, unsubscribe\n * 4. Generate Signed Event Webhook key → store as webhookVerificationKey\n */\n\nimport crypto from 'node:crypto'\nimport sgMail from '@sendgrid/mail'\n\nimport type {\n MailProvider,\n NormalizedEvent,\n SendArgs,\n SendResult,\n} from '../../shared/types.js'\n\nexport interface SendGridProviderOptions {\n apiKey: string\n /** ECDSA public key (PEM) from SendGrid → Settings → Mail Settings → Signed Event Webhook. */\n webhookVerificationKey?: string\n /** Send-rate cap per second (BullMQ group limiter consults this). */\n sendRatePerSecond?: number\n /** Sandbox mode bypasses actual delivery — useful in dev/test. */\n sandbox?: boolean\n}\n\nconst SG_SIG_HEADER = 'x-twilio-email-event-webhook-signature'\nconst SG_TS_HEADER = 'x-twilio-email-event-webhook-timestamp'\n\nexport class SendGridProvider implements MailProvider {\n readonly name = 'sendgrid'\n readonly sendRatePerSecond: number\n\n constructor(private readonly opts: SendGridProviderOptions) {\n sgMail.setApiKey(opts.apiKey)\n this.sendRatePerSecond = opts.sendRatePerSecond ?? 10\n }\n\n async send(args: SendArgs): Promise<SendResult> {\n const msg: sgMail.MailDataRequired = {\n to: args.to,\n from: { name: args.fromName, email: args.fromEmail },\n replyTo: args.replyTo,\n subject: args.subject,\n text: args.text,\n html: args.html,\n headers: args.headers,\n customArgs: args.messageMeta,\n trackingSettings: {\n // We do our own click/open tracking — let provider stay out of it.\n clickTracking: { enable: false, enableText: false },\n openTracking: { enable: false },\n },\n mailSettings: {\n sandboxMode: { enable: this.opts.sandbox ?? false },\n },\n }\n\n const [response] = await sgMail.send(msg)\n const providerId =\n (response.headers['x-message-id'] as string | undefined) ?? `sg-${Date.now()}`\n return {\n providerId,\n status: response.statusCode < 300 ? 'accepted' : 'rejected',\n raw: response,\n }\n }\n\n async verifyWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<boolean> {\n if (!this.opts.webhookVerificationKey) return false\n const sig = headers[SG_SIG_HEADER]\n const ts = headers[SG_TS_HEADER]\n if (!sig || !ts) return false\n\n const payload = Buffer.concat([Buffer.from(ts, 'utf8'), rawBody])\n try {\n const verifier = crypto.createVerify('sha256')\n verifier.update(payload)\n return verifier.verify(this.opts.webhookVerificationKey, sig, 'base64')\n } catch {\n return false\n }\n }\n\n parseWebhookEvents(payload: unknown): NormalizedEvent[] {\n if (!Array.isArray(payload)) return []\n return payload\n .map((raw) => normalizeSendGridEvent(raw))\n .filter((e): e is NormalizedEvent => e !== null)\n }\n}\n\nfunction normalizeSendGridEvent(e: any): NormalizedEvent | null {\n const type = mapEventType(e.event)\n if (!type) return null\n return {\n type,\n providerEventId: String(e.sg_event_id ?? e['smtp-id'] ?? `${e.event}-${e.timestamp}-${e.email}`),\n providerMessageId: String(e.sg_message_id ?? e['smtp-id'] ?? ''),\n email: String(e.email ?? '').toLowerCase(),\n occurredAt: new Date(Number(e.timestamp) * 1000),\n details: {\n bounceType:\n e.event === 'bounce' ? (e.type === 'bounce' ? 'hard' : 'soft') : undefined,\n bounceReason: e.reason,\n clickedUrl: e.url,\n userAgent: e.useragent,\n ipAddress: e.ip,\n },\n }\n}\n\nfunction mapEventType(sgEvent: string): NormalizedEvent['type'] | null {\n switch (sgEvent) {\n case 'delivered':\n return 'delivered'\n case 'open':\n return 'open'\n case 'click':\n return 'click'\n case 'bounce':\n case 'dropped':\n return 'bounce'\n case 'spamreport':\n return 'spam_report'\n case 'unsubscribe':\n case 'group_unsubscribe':\n return 'unsubscribe'\n default:\n return null\n }\n}\n","/**\n * Zod schemas for runtime validation at write boundaries — public API entry\n * points (fire, upsertSubscription, suppress, sendOneOff, scheduleBroadcast)\n * and REST handler bodies.\n *\n * Domain TypeScript types live in `./types.ts`; these schemas overlap with\n * those types deliberately so we get both compile-time and runtime checking\n * at the surfaces that need it.\n */\n\nimport { z } from 'zod'\n\n// ---------------------------------------------------------------------------\n// Primitive helpers\n// ---------------------------------------------------------------------------\n\nexport const externalIdSchema = z.string().min(1).max(256)\nexport const emailSchema = z.string().email().toLowerCase().trim()\nexport const slugSchema = z\n .string()\n .min(1)\n .max(128)\n .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/, 'must be kebab-case slug')\n\n// ---------------------------------------------------------------------------\n// Public API inputs\n// ---------------------------------------------------------------------------\n\nexport const fireInputSchema = z.object({\n eventName: z.string().min(1).max(128),\n externalId: externalIdSchema,\n properties: z.record(z.string(), z.unknown()).optional(),\n dedupeKey: z.string().min(1).max(512).optional(),\n})\nexport type FireInput = z.infer<typeof fireInputSchema>\n\nexport const registerEventSchema = z.object({\n name: z.string().min(1).max(128),\n dedupePolicy: z.enum(['once-per-contact', 'once-per-day', 'every-time']),\n})\nexport type RegisterEventInput = z.infer<typeof registerEventSchema>\n\nexport const upsertSubscriptionSchema = z.object({\n externalId: externalIdSchema,\n source: z.string().min(1).max(256),\n consentTimestamp: z.date().optional(),\n consentIp: z.string().optional(),\n consentUserAgent: z.string().optional(),\n})\nexport type UpsertSubscriptionInput = z.infer<typeof upsertSubscriptionSchema>\n\nexport const unsubscribeScopeSchema = z.enum(['all', 'marketing', 'transactional'])\nexport const unsubscribeReasonSchema = z.enum([\n 'user_request',\n 'hard_bounce',\n 'complaint',\n 'manual',\n 'gdpr_forget',\n 'list_cleaning',\n])\n\nexport const unsubscribeInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: unsubscribeReasonSchema.default('user_request'),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n})\nexport type UnsubscribeInput = z.infer<typeof unsubscribeInputSchema>\n\nexport const suppressInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: z.enum(['unsubscribed', 'hard_bounce', 'complaint', 'manual', 'list_cleaning', 'gdpr_forget']),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n expiresAt: z.date().optional(),\n})\nexport type SuppressInput = z.infer<typeof suppressInputSchema>\n\nexport const tagInputSchema = z.object({\n externalId: externalIdSchema,\n tag: z.string().min(1).max(128),\n})\nexport type TagInput = z.infer<typeof tagInputSchema>\n\nexport const abortFlowInputSchema = z.object({\n flowSlug: slugSchema,\n externalId: externalIdSchema,\n reason: z.string().min(1).max(200).optional(),\n /**\n * Restrict the abort to runs whose trigger event carried these properties —\n * e.g. `{ accountId }` to cancel one account's series while the same\n * contact's other accounts keep running. Omit to abort every active run for\n * the contact on this flow.\n *\n * Keys and values are both constrained because these go straight into a\n * Mongo query. Values are primitives only: an object value like\n * `{ $ne: null }` would reach the query as an OPERATOR and match every\n * scoped run, turning a one-account abort into abort-everything. Hosts\n * typically pass an id from a request body, so treat it as untrusted. The\n * key regex likewise blocks `$`-prefixed keys and dots (a dot would silently\n * extend the path and change match semantics).\n */\n matchTriggerProperties: z\n .record(\n z.string().regex(/^[A-Za-z0-9_]+$/),\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\n )\n .optional(),\n})\nexport type AbortFlowInput = z.infer<typeof abortFlowInputSchema>\n\nexport const abortAllFlowsInputSchema = abortFlowInputSchema.omit({ flowSlug: true })\nexport type AbortAllFlowsInput = z.infer<typeof abortAllFlowsInputSchema>\n\nexport const sendOneOffInputSchema = z.object({\n templateSlug: slugSchema,\n externalId: externalIdSchema,\n vars: z.record(z.string(), z.unknown()).optional(),\n providerOverride: z.string().optional(),\n dedupeKey: z.string().min(1).max(512),\n})\nexport type SendOneOffInput = z.infer<typeof sendOneOffInputSchema>\n\n// ---------------------------------------------------------------------------\n// Flow step + predicate schemas (mirror types.ts)\n// ---------------------------------------------------------------------------\n\nexport const flowStepSchema: z.ZodType<unknown> = z.lazy(() =>\n z.discriminatedUnion('type', [\n z.object({\n type: z.literal('wait'),\n value: z.number().int().positive(),\n unit: z.enum(['minutes', 'hours', 'days', 'weeks']),\n }),\n z.object({\n type: z.literal('condition'),\n test: predicateSchema,\n ifFalse: z.enum(['continue', 'exit']),\n }),\n z.object({\n type: z.literal('branch'),\n test: predicateSchema,\n ifTrueSteps: z.array(flowStepSchema),\n ifFalseSteps: z.array(flowStepSchema),\n }),\n z.object({\n type: z.literal('send'),\n templateSlug: slugSchema,\n providerOverride: z.string().optional(),\n vars: z.record(z.string(), z.unknown()).optional(),\n delivery: z\n .object({\n weekdaysOnly: z.boolean().optional(),\n timeOfDay: z.string().regex(/^([01]\\d|2[0-3]):[0-5]\\d$/, 'expected HH:mm').optional(),\n useContactTimezone: z.boolean().optional(),\n timezone: z.string().optional(),\n })\n .optional(),\n }),\n z.object({\n type: z.literal('tag'),\n addTags: z.array(z.string()).optional(),\n removeTags: z.array(z.string()).optional(),\n }),\n z.object({\n type: z.literal('fire_event'),\n eventName: z.string().min(1).max(128),\n properties: z.record(z.string(), z.unknown()).optional(),\n }),\n z.object({\n type: z.literal('webhook'),\n url: z.string().url(),\n method: z.enum(['POST', 'PUT']).optional(),\n payload: z.record(z.string(), z.unknown()).optional(),\n failureMode: z.enum(['soft', 'fail_run']).optional(),\n }),\n z.object({\n type: z.literal('exit'),\n reason: z.string().optional(),\n }),\n ]),\n)\n\nexport const predicateSchema: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.object({ hasTag: z.string() }),\n z.object({ notHasTag: z.string() }),\n z.object({ fieldEquals: z.object({ field: z.string(), value: z.unknown() }) }),\n z.object({ fieldExists: z.string() }),\n z.object({\n triggerPropertyEquals: z.object({\n key: z.string().min(1),\n value: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n }),\n }),\n z.object({ triggerPropertyTruthy: z.string().min(1) }),\n z.object({\n hasFiredEvent: z.string(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n notHasFiredEvent: z.string(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n subscriptionStatus: z.enum(['subscribed', 'unsubscribed', 'pending_doi', 'bounced', 'complained']),\n }),\n z.object({\n hasOpened: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClicked: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasOpenedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClickedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n openedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({\n clickedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({ all: z.array(predicateSchema) }),\n z.object({ any: z.array(predicateSchema) }),\n z.object({ not: predicateSchema }),\n ]),\n)\n","/**\n * Mailer configuration shape. Required + optional surfaces with sane defaults.\n */\n\nimport type { Db } from 'mongodb'\nimport type Handlebars from 'handlebars'\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport type { QueueDriverConfig } from './queues/types.js'\nimport type { SenderDomainRegistry } from './templates/sender-domain.js'\nimport type { VarsAdapter } from './adapters/vars.js'\n\nexport type { SenderDomainConfig, SenderDomainRegistry } from './templates/sender-domain.js'\n\nexport interface RedisOptions {\n host?: string\n port?: number\n password?: string\n url?: string\n db?: number\n username?: string\n tls?: boolean\n}\n\nexport interface DnsblListSpec {\n /** DNS suffix to query, e.g. `'dbl.spamhaus.org'`. */\n host: string\n /** Display label for the UI, e.g. `'Spamhaus DBL'`. */\n label: string\n}\n\nexport interface DnsblConfig {\n /** Domain block lists (DBLs) — queried as `<domain>.<host>`. */\n domainLists?: DnsblListSpec[]\n /** IP block lists — queried as `<reversed-octets>.<host>`. */\n ipLists?: DnsblListSpec[]\n /** Dedicated sending IPs to check. Most operators on shared ESPs leave empty. */\n dedicatedIps?: string[]\n /** Hours between automatic runs. Default 24. Set to 0 to disable scheduled runs. */\n intervalHours?: number\n}\n\nexport const DEFAULT_DOMAIN_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'dbl.spamhaus.org', label: 'Spamhaus DBL' },\n { host: 'multi.surbl.org', label: 'SURBL' },\n { host: 'multi.uribl.com', label: 'URIBL' },\n]\n\nexport const DEFAULT_IP_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'zen.spamhaus.org', label: 'Spamhaus ZEN' },\n { host: 'b.barracudacentral.org', label: 'Barracuda' },\n { host: 'dnsbl.sorbs.net', label: 'SORBS' },\n { host: 'bl.spamcop.net', label: 'SpamCop' },\n]\n\nexport interface MailTesterConfig {\n /** API key from your Mail-Tester paid plan. */\n apiKey: string\n /** Minimum score (0-10) below which publish is blocked. Default 8.0. */\n minScore?: number\n /**\n * When true, publishing content that has no cached score is blocked too —\n * the operator must run a deliverability check for that exact content first.\n * Default false, which only blocks content already known to score below\n * `minScore`; in that mode any edit (even whitespace) changes the content\n * key, misses the cache, and publishes freely.\n */\n requireScore?: boolean\n /**\n * How long a successful score remains cached for the same content. Default 24.\n * Re-publishing the same body within the window does not burn a credit.\n */\n cacheHours?: number\n /** API base URL. Defaults to `https://mail-tester.com/api`. Override for staging or alternate provider. */\n baseUrl?: string\n}\n\nexport interface DmarcSourceTag {\n /** Source IP, e.g. `'149.72.45.10'`. */\n ip: string\n /** Operator-provided label, e.g. `'SendGrid (transactional)'` or `'Hubspot'`. */\n label: string\n /** When true, ignore failures from this source in the alignment-trend headline. */\n ignored?: boolean\n}\n\nexport interface DmarcConfig {\n /**\n * Operator-tagged sources. After RUA reports start arriving, the operator\n * marks each source IP as known/legit (with a label) or rogue. Tagged\n * sources are excluded from the headline failure count, surfacing only\n * unknown senders.\n */\n knownSources?: DmarcSourceTag[]\n /**\n * How many days of failure rows to retain. Default 90. Older rows are\n * trimmed by the daily tick to keep the collection bounded.\n */\n retentionDays?: number\n}\n\nexport interface SndsConfig {\n /**\n * SNDS automated-access key. Obtained per-account from the SNDS portal at\n * https://sendersupport.olc.protection.outlook.com/snds/ once each\n * sending IP has been added and verified.\n */\n accessKey: string\n /**\n * Optional IP filter — when set, only rows for these IPs are persisted.\n * Useful when an SNDS account covers a wider IP pool than this mailery\n * deployment uses. Defaults to keeping all rows the API returns.\n */\n ips?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface PostmasterConfig {\n /** OAuth client ID from a Google Cloud project with Postmaster Tools API enabled. */\n clientId: string\n clientSecret: string\n /**\n * A refresh token obtained via the OAuth consent flow with scope\n * `https://www.googleapis.com/auth/postmaster.readonly` for the user that\n * verified the domain(s) in Postmaster Tools. See\n * docs/guide/deliverability.md → \"Google Postmaster Tools\" for the\n * one-time setup procedure.\n */\n refreshToken: string\n /**\n * Domains to pull data for. When omitted, mailery uses every domain from the\n * senderDomains registry plus the From defaults. Each must be verified in\n * Postmaster Tools under the same Google account.\n */\n domains?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface CircuitBreakerThresholds {\n /** Trip when last-hour hard-bounce rate >= this percent (e.g. 2 = 2%). */\n hardBounceRatePctTrip: number\n complaintRatePctTrip: number\n combinedBounceRatePctTrip: number\n failedToSendRatePctDegrade: number\n windowMinutes: number\n minSendsBeforeEval: number\n}\n\nexport interface MailerConfig {\n // ---- Storage --------------------------------------------------------------\n db: Db\n collectionPrefix?: string\n adapter: ContactAdapter\n /**\n * Optional host-provided template variables. `resolve(contact)` runs at\n * send/preview/test render time; its result is merged into the template\n * context root (schema key `user` → `{{user.name}}`). The zod schema\n * drives admin-editor autocomplete and the `unknown_variable` lint rule.\n * Build one with `defineVars({ schema, resolve })`.\n */\n varsAdapter?: VarsAdapter<any>\n\n // ---- Queue ----------------------------------------------------------------\n /**\n * Queue driver selection. One of:\n * - `{ driver: 'bull', redis: ... }` — BullMQ (default for prod; requires Redis)\n * - `{ driver: 'agenda' }` — @hokify/agenda using this Mongo (no Redis required, single-process)\n * - `{ driver: 'noop' }` — no background workers (tests, synchronous-only hosts)\n */\n queue: QueueDriverConfig\n\n // ---- Providers ------------------------------------------------------------\n providers: Record<string, MailProvider>\n defaultProvider: string\n defaultTransactionalProvider?: string\n\n // ---- Identity / URLs ------------------------------------------------------\n publicUrl: string\n unsubscribeSecret: string\n senderAddress?: string\n fromDefaults?: { name: string; email: string }\n transactionalFromDefaults?: { name: string; email: string }\n /**\n * Optional registry of sender domains by kind. When set, mailery enforces at\n * template publish time that a template's `fromEmail` domain is declared and\n * matches the template's `kind`. Used to keep marketing reputation isolated\n * from transactional reputation by sending from separate verified domains.\n *\n * Domains are case-insensitive. If unset, no enforcement happens.\n */\n senderDomains?: SenderDomainRegistry\n\n // ---- Compliance -----------------------------------------------------------\n requireDoubleOptIn?: boolean\n unsubscribeTokenLifetimeDays?: number\n transactionalRespectUnsubscribe?: boolean\n /** Slug of the transactional template sent for DOI confirmation. Defaults to 'doi-confirmation'. */\n doiTemplateSlug?: string\n /** How long the DOI token stays valid. Default 7 days. */\n doiTokenLifetimeDays?: number\n\n // ---- Circuit breaker ------------------------------------------------------\n circuitBreaker?: Partial<CircuitBreakerThresholds>\n\n // ---- DNSBL monitoring -----------------------------------------------------\n /**\n * Daily DNS-based block-list checks on sender domains and (optionally) any\n * dedicated sending IPs. Results surface in setup-status and on the Health\n * screen. No external API needed — plain DNS lookups.\n */\n dnsbl?: DnsblConfig\n\n // ---- Google Postmaster Tools ---------------------------------------------\n /**\n * Pulls daily reputation tiers + spam ratio + auth pass rates from Google\n * Postmaster Tools. Trips the (domain × marketing) circuit breaker when a\n * domain falls to reputation `BAD`. Only meaningful at >100/day to Gmail.\n */\n postmaster?: PostmasterConfig\n\n // ---- Microsoft SNDS ------------------------------------------------------\n /**\n * Pulls daily Outlook/Hotmail/Live IP reputation from Microsoft's Smart\n * Network Data Services. IP-level rather than domain-level — only useful\n * if you send from a dedicated IP. Visibility-only: RED filter results\n * surface as a setup-status error, no auto-trip.\n */\n snds?: SndsConfig\n\n // ---- Mail-Tester deliverability check ------------------------------------\n /**\n * Optional Mail-Tester integration. When set, the template editor exposes\n * a \"Run deliverability check\" button that sends a copy of the rendered\n * draft to a Mail-Tester address and polls for a score (0-10) covering\n * SpamAssassin verdict, auth alignment, content red flags, and link\n * reputation. Score < minScore blocks publish until re-run or overridden.\n */\n mailTester?: MailTesterConfig\n\n // ---- DMARC aggregate report ingestion ------------------------------------\n /**\n * DMARC RUA aggregate reports tell you who is sending mail that claims to\n * be from your domain — both legitimate sources and spoofers. Operator\n * uploads the report attachments (or POSTs them via SendGrid Inbound Parse\n * to /admin/mailer/api/dmarc/upload). Mailery decompresses, parses, and\n * surfaces alignment failures + unknown senders.\n */\n dmarc?: DmarcConfig\n\n // ---- Broadcast safety + throughput ---------------------------------------\n broadcastConfirmationThreshold?: number\n broadcastEnqueueBatchSize?: number\n broadcastEnqueueMaxWaiting?: number\n\n // ---- Worker behavior ------------------------------------------------------\n workerless?: boolean\n tickIntervalSeconds?: number\n sendConcurrency?: number\n sendRatePerSecond?: number\n softBouncePromotionThreshold?: number\n softBouncePromotionWindowDays?: number\n webhookRetryAttempts?: number\n sendRetryAttempts?: number\n\n // ---- Tracking -------------------------------------------------------------\n trackOpens?: boolean\n trackClicks?: boolean\n storeTrackingIp?: boolean\n storeRenderedBody?: boolean\n\n // ---- Hooks ----------------------------------------------------------------\n getAdminActor?: (req: any) => string\n onCircuitBreakerTrip?: (info: { reason: string; rates: Record<string, number> }) => Promise<void> | void\n onSendFailure?: (info: { send: any; error: Error }) => Promise<void> | void\n handlebarsHelpers?: Record<string, Handlebars.HelperDelegate>\n}\n\nexport type ResolvedConfig = Required<\n Pick<\n MailerConfig,\n | 'collectionPrefix'\n | 'requireDoubleOptIn'\n | 'unsubscribeTokenLifetimeDays'\n | 'transactionalRespectUnsubscribe'\n | 'doiTemplateSlug'\n | 'doiTokenLifetimeDays'\n | 'broadcastConfirmationThreshold'\n | 'broadcastEnqueueBatchSize'\n | 'broadcastEnqueueMaxWaiting'\n | 'workerless'\n | 'tickIntervalSeconds'\n | 'sendConcurrency'\n | 'sendRatePerSecond'\n | 'softBouncePromotionThreshold'\n | 'softBouncePromotionWindowDays'\n | 'webhookRetryAttempts'\n | 'sendRetryAttempts'\n | 'trackOpens'\n | 'trackClicks'\n | 'storeTrackingIp'\n | 'storeRenderedBody'\n >\n> & {\n circuitBreaker: CircuitBreakerThresholds\n} & MailerConfig\n\nexport const DEFAULTS = {\n collectionPrefix: 'mailer_',\n requireDoubleOptIn: false,\n unsubscribeTokenLifetimeDays: 90,\n transactionalRespectUnsubscribe: false,\n doiTemplateSlug: 'doi-confirmation',\n doiTokenLifetimeDays: 7,\n broadcastConfirmationThreshold: 1000,\n broadcastEnqueueBatchSize: 1000,\n broadcastEnqueueMaxWaiting: 5000,\n workerless: false,\n tickIntervalSeconds: 60,\n sendConcurrency: 5,\n sendRatePerSecond: 10,\n softBouncePromotionThreshold: 3,\n softBouncePromotionWindowDays: 30,\n webhookRetryAttempts: 3,\n sendRetryAttempts: 4,\n trackOpens: true,\n trackClicks: true,\n storeTrackingIp: false,\n storeRenderedBody: false,\n} as const\n\nexport const CIRCUIT_BREAKER_DEFAULTS: CircuitBreakerThresholds = {\n hardBounceRatePctTrip: 2,\n complaintRatePctTrip: 0.3,\n combinedBounceRatePctTrip: 5,\n failedToSendRatePctDegrade: 10,\n windowMinutes: 60,\n minSendsBeforeEval: 100,\n}\n\nexport function resolveConfig(c: MailerConfig): ResolvedConfig {\n return {\n ...c,\n collectionPrefix: c.collectionPrefix ?? DEFAULTS.collectionPrefix,\n requireDoubleOptIn: c.requireDoubleOptIn ?? DEFAULTS.requireDoubleOptIn,\n unsubscribeTokenLifetimeDays: c.unsubscribeTokenLifetimeDays ?? DEFAULTS.unsubscribeTokenLifetimeDays,\n transactionalRespectUnsubscribe: c.transactionalRespectUnsubscribe ?? DEFAULTS.transactionalRespectUnsubscribe,\n doiTemplateSlug: c.doiTemplateSlug ?? DEFAULTS.doiTemplateSlug,\n doiTokenLifetimeDays: c.doiTokenLifetimeDays ?? DEFAULTS.doiTokenLifetimeDays,\n broadcastConfirmationThreshold: c.broadcastConfirmationThreshold ?? DEFAULTS.broadcastConfirmationThreshold,\n broadcastEnqueueBatchSize: c.broadcastEnqueueBatchSize ?? DEFAULTS.broadcastEnqueueBatchSize,\n broadcastEnqueueMaxWaiting: c.broadcastEnqueueMaxWaiting ?? DEFAULTS.broadcastEnqueueMaxWaiting,\n workerless: c.workerless ?? DEFAULTS.workerless,\n tickIntervalSeconds: c.tickIntervalSeconds ?? DEFAULTS.tickIntervalSeconds,\n sendConcurrency: c.sendConcurrency ?? DEFAULTS.sendConcurrency,\n sendRatePerSecond: c.sendRatePerSecond ?? DEFAULTS.sendRatePerSecond,\n softBouncePromotionThreshold: c.softBouncePromotionThreshold ?? DEFAULTS.softBouncePromotionThreshold,\n softBouncePromotionWindowDays: c.softBouncePromotionWindowDays ?? DEFAULTS.softBouncePromotionWindowDays,\n webhookRetryAttempts: c.webhookRetryAttempts ?? DEFAULTS.webhookRetryAttempts,\n sendRetryAttempts: c.sendRetryAttempts ?? DEFAULTS.sendRetryAttempts,\n trackOpens: c.trackOpens ?? DEFAULTS.trackOpens,\n trackClicks: c.trackClicks ?? DEFAULTS.trackClicks,\n storeTrackingIp: c.storeTrackingIp ?? DEFAULTS.storeTrackingIp,\n storeRenderedBody: c.storeRenderedBody ?? DEFAULTS.storeRenderedBody,\n circuitBreaker: { ...CIRCUIT_BREAKER_DEFAULTS, ...(c.circuitBreaker ?? {}) },\n }\n}\n","/**\n * Mongo collection helpers + indexes for every mailer-owned collection.\n *\n * The single source of truth for `mailer_*` schemas lives in\n * `plans/02-data-model.md`. The TS interfaces here track that doc.\n *\n * const collections = getCollections(db)\n * await ensureIndexes(db)\n * await collections.events.insertOne({ ... })\n */\n\nimport type { Db, Collection, ObjectId } from 'mongodb'\n\nimport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../../shared/enums.js'\nimport type { FlowStep, SegmentDefinition } from '../../shared/types.js'\n\n// ---------------------------------------------------------------------------\n// Document interfaces (per collection)\n// ---------------------------------------------------------------------------\n\nexport interface SubscriptionDoc {\n _id?: ObjectId\n externalId: string\n status: SubscriptionStatus\n subscribedAt: Date | null\n unsubscribedAt: Date | null\n unsubscribeReason: string | null\n doiTokenHash: string | null\n doiRequestedAt: Date | null\n doiConfirmedAt: Date | null\n doiIp: string | null\n doiUserAgent: string | null\n source: string\n emailAtSubscribe: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface LeadDoc {\n _id?: ObjectId\n email: string\n source: string\n capturedFields: Record<string, unknown>\n status: 'lead' | 'promoted' | 'rejected'\n promotedToExternalId: string | null\n promotedAt: Date | null\n consentedAt: Date | null\n consentIp: string | null\n unsubscribedAt: Date | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface EventDoc {\n _id?: ObjectId\n externalId: string\n name: string\n properties: Record<string, unknown>\n dedupeKey: string\n occurredAt: Date\n createdAt: Date\n}\n\nexport interface FlowTrigger {\n type: 'event' | 'segment_enter' | 'cron'\n eventName?: string\n segmentDefinition?: SegmentDefinition\n cronExpression?: string\n once: boolean\n}\n\nexport interface FlowDraft {\n steps: FlowStep[]\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface FlowDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n trigger: FlowTrigger\n enabled: boolean\n steps: FlowStep[]\n version: number\n draft: FlowDraft | null\n goal: FlowGoal\n audience: string\n expectedVolumePerWeek: number | null\n stats: {\n activeRuns: number\n completedRuns: number\n sendsTotal: number\n sendsLast7Days: number\n }\n lastTriggerScanAt: Date | null\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface FlowVersionDoc {\n _id?: ObjectId\n flowId: ObjectId\n version: number\n steps: FlowStep[]\n trigger: FlowTrigger\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface FlowRunHistoryEntry {\n stepIndex: number\n action:\n | 'entered'\n | 'wait_started'\n | 'wait_completed'\n | 'condition_evaluated'\n | 'branch_taken'\n | 'sent'\n | 'send_skipped'\n | 'send_deferred'\n | 'tagged'\n | 'event_fired'\n | 'webhook_called'\n | 'exited'\n | 'failed'\n at: Date\n details?: Record<string, unknown>\n}\n\nexport interface FlowRunDoc {\n _id?: ObjectId\n externalId: string\n flowId: ObjectId\n flowSlug: string\n flowVersion: number\n emailAtEntry: string\n /**\n * Snapshot of the event that triggered this run. Properties surface in\n * templates as `{{event.*}}` and in `varsAdapter.resolve` via\n * `info.eventProperties` — this is how account/topic-scoped flows know\n * which account or topic the run is about. Null for non-event entries.\n */\n triggerEvent?: { name: string; properties: Record<string, unknown>; occurredAt: Date } | null\n /**\n * Dedupe key of the triggering event. Unique per flow (partial index) so the\n * trigger scan's overlap window can re-read an event without creating a\n * second run. Null for non-event entries (manual/API).\n */\n triggerDedupeKey?: string | null\n enteredAt: Date\n status: FlowRunStatus\n currentStepIndex: number\n currentBranchPath: Array<number | 'true' | 'false'>\n nextActionAt: Date\n attemptsForCurrentStep: number\n history: FlowRunHistoryEntry[]\n exitedAt: Date | null\n exitReason: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateDraft {\n subject: string\n preheader: string\n /** MJML source (when template is authored as MJML). Empty string if Maily-authored. */\n mjml: string\n /** Maily editor JSON (when template is authored via the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface TemplateDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n kind: TemplateKind\n fromName: string\n fromEmail: string\n replyTo: string | null\n providerOverride: string | null\n subject: string\n preheader: string\n body: {\n /** MJML source (set when published from MJML). */\n mjml: string\n /** Maily editor JSON (set when published from the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n html: string\n plainText: string\n compiledAt: Date | null\n }\n variablesSchema: Record<\n string,\n {\n type: 'string' | 'number' | 'boolean' | 'date' | 'url'\n required: boolean\n description?: string\n defaultValue?: unknown\n }\n >\n draft: TemplateDraft | null\n tags: string[]\n trackOpens: boolean\n trackClicks: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n lastSentAt: Date | null\n }\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateVersionDoc {\n _id?: ObjectId\n templateId: ObjectId\n version: number\n mjml: string\n html: string\n plainText: string\n subject: string\n preheader: string\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface SendDoc {\n _id?: ObjectId\n dedupeKey: string\n externalId: string\n emailAtSend: string\n templateId: ObjectId\n templateSlug: string\n flowRunId: ObjectId | null\n broadcastId: ObjectId | null\n manualSendBy: string | null\n kind: TemplateKind\n provider: string\n providerMessageId: string | null\n fromName: string\n fromEmail: string\n subject: string\n bodyHash: string\n status: SendStatus\n errorMessage: string | null\n bounceType: 'hard' | 'soft' | null\n bounceReason: string | null\n /** Pre-send map: every rewritten link's linkId → original URL. Lookup target on click. */\n links: Array<{ linkId: string; url: string }>\n /** Render-time vars from the flow step or one-off send. Re-applied at dispatch. */\n vars: Record<string, unknown>\n openedAt: Date | null\n openCount: number\n firstClickAt: Date | null\n clickCount: number\n /** History of actual clicks (a linkId may appear multiple times). */\n clickedLinks: Array<{ url: string; linkId: string; clickedAt: Date }>\n unsubscribedAt: Date | null\n complainedAt: Date | null\n queuedAt: Date\n /** Last time the row was mutated; used by the stranded-send sweep. */\n updatedAt: Date\n sentAt: Date | null\n deliveredAt: Date | null\n}\n\nexport interface SuppressionDoc {\n _id?: ObjectId\n email: string | null\n emailHash: string\n scope: SuppressionScope\n reason: SuppressionReason\n source: string\n notes: string | null\n addedAt: Date\n expiresAt: Date | null\n}\n\nexport interface BroadcastDoc {\n _id?: ObjectId\n slug: string\n name: string\n templateSlug: string\n segmentDefinition: SegmentDefinition\n status: BroadcastStatus\n scheduledAt: Date | null\n startedAt: Date | null\n completedAt: Date | null\n confirmationRequired: boolean\n confirmedCount: number | null\n confirmedAt: Date | null\n confirmedBy: string | null\n recipientCount: number | null\n /** When true, dispatch fires each recipient at their local-timezone equivalent of `scheduledAt`. */\n respectRecipientTimezone?: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n }\n createdAt: Date\n createdBy: string\n updatedAt: Date\n}\n\nexport interface OutboxDoc {\n _id?: ObjectId\n payload: {\n type: 'event' | 'upsert_subscription' | 'unsubscribe'\n data: Record<string, unknown>\n dedupeKey: string\n }\n status: 'pending' | 'processed' | 'failed' | 'duplicate'\n attempts: number\n lastAttemptAt: Date | null\n lastError: string | null\n enqueuedAt: Date\n processedAt: Date | null\n}\n\nexport interface AuditLogDoc {\n _id?: ObjectId\n actor: string\n action: string\n resource: { collection: string; id?: ObjectId | string; slug?: string }\n before: Record<string, unknown> | null\n after: Record<string, unknown> | null\n diffSummary: string | null\n ip: string | null\n userAgent: string | null\n requestId: string | null\n occurredAt: Date\n}\n\nexport interface WebhookEventDoc {\n _id?: ObjectId\n provider: string\n providerEventId: string\n eventType: string\n normalizedType: 'delivered' | 'open' | 'click' | 'bounce' | 'complaint' | 'unsubscribe' | 'spam_report'\n providerMessageId: string\n email: string\n occurredAt: Date\n receivedAt: Date\n processed: boolean\n raw: unknown\n}\n\n/**\n * Health bucket. One doc per (senderDomain, kind) pair plus a single aggregate\n * doc with _id='agg' that rolls up everything.\n *\n * _id: 'agg' // cross-domain, cross-kind roll-up\n * _id: 'd:<senderDomain>|k:<kind>' // per-bucket\n *\n * The aggregate is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n */\nexport interface HealthDoc {\n _id: string\n /** null on the aggregate doc, set on bucket docs. */\n senderDomain: string | null\n /** null on the aggregate doc, set on bucket docs. */\n kind: TemplateKind | null\n windowStartedAt: Date\n windowDurationMs: number\n counters: {\n sent: number\n delivered: number\n bounced: number\n hardBounced: number\n softBounced: number\n complained: number\n failedToSend: number\n }\n rates: {\n bounceRate: number\n hardBounceRate: number\n complaintRate: number\n failureRate: number\n }\n status: HealthStatus\n trippedAt: Date | null\n trippedReason: string | null\n manuallyResumedAt: Date | null\n updatedAt: Date\n}\n\nexport const HEALTH_AGG_ID = 'agg'\n\nexport function healthBucketId(senderDomain: string | null, kind: TemplateKind): string {\n return `d:${senderDomain ?? '_unknown'}|k:${kind}`\n}\n\nexport type PostmasterReputation = 'HIGH' | 'MEDIUM' | 'LOW' | 'BAD' | 'REPUTATION_CATEGORY_UNSPECIFIED'\n\n/**\n * One day's traffic stats for a domain from Google Postmaster Tools.\n * Stored per (domain, date) so we can chart trends.\n */\nexport interface PostmasterSnapshotDoc {\n _id?: ObjectId\n domain: string\n /** Reporting date in YYYY-MM-DD per Postmaster's stat day. */\n date: string\n domainReputation: PostmasterReputation | null\n ipReputations: Array<{ reputation: PostmasterReputation; ipCount: number }> | null\n userReportedSpamRatio: number | null\n spfSuccessRatio: number | null\n dkimSuccessRatio: number | null\n dmarcSuccessRatio: number | null\n outboundEncryptionRatio: number | null\n inboundEncryptionRatio: number | null\n deliveryErrors: Array<{ errorType: string; errorClass: string; errorRatio: number }> | null\n spammyFeedbackLoops: Array<{ id: string; spamRatio: number }> | null\n fetchedAt: Date\n}\n\nexport interface MailTesterFeedback {\n category: string\n severity: 'info' | 'warning' | 'error'\n message: string\n}\n\n/**\n * Cached Mail-Tester deliverability score for a given (template content)\n * fingerprint. Operators don't burn a credit re-running on identical\n * content within cacheHours.\n */\nexport interface MailTesterScoreDoc {\n _id?: ObjectId\n templateSlug: string\n /** Hash of bodyHash + subject + fromEmail — the cache key. */\n contentKey: string\n checkId: string\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n fetchedAt: Date\n expiresAt: Date\n}\n\nexport type DmarcPolicy = 'none' | 'quarantine' | 'reject'\nexport type DmarcAuthResult = 'pass' | 'fail' | 'softfail' | 'neutral' | 'temperror' | 'permerror' | 'none' | 'unknown'\n\n/**\n * One DMARC RUA aggregate report. Receivers (Google, Yahoo, Microsoft, etc.)\n * email one per day per sending domain. We store one DmarcReportDoc per\n * incoming report, plus one DmarcFailureDoc per non-aligned record row.\n */\nexport interface DmarcReportDoc {\n _id?: ObjectId\n reportId: string\n /** Reporting org, e.g. 'google.com', 'enterprise.protection.outlook.com'. */\n orgName: string\n /** Reporter contact email from <report_metadata>. */\n email: string\n /** The domain we publish DMARC for, from <policy_published><domain>. */\n domain: string\n policyP: DmarcPolicy\n /** % of mail subject to the policy (1-100). */\n policyPct: number\n /** Activity window the report covers. */\n rangeStart: Date\n rangeEnd: Date\n /** Sum of <count> across all records. */\n totalMessages: number\n /** Messages that passed DMARC (DKIM aligned OR SPF aligned). */\n passCount: number\n failCount: number\n receivedAt: Date\n}\n\n/**\n * One alignment-failing source × day. Composite key `(sourceIp, domain, day)`\n * lets us roll up \"this IP sent N misaligned messages over the past week.\"\n * Failures from multiple reports for the same key get counted once per\n * report (we de-dupe on reportId × sourceIp).\n */\nexport interface DmarcFailureDoc {\n _id?: ObjectId\n reportId: string\n domain: string\n sourceIp: string\n count: number\n headerFrom: string\n dkimResult: DmarcAuthResult\n spfResult: DmarcAuthResult\n dispositionApplied: 'none' | 'quarantine' | 'reject' | string\n /** YYYY-MM-DD bucket derived from the reporting window's mid-point. */\n day: string\n receivedAt: Date\n}\n\n/**\n * Operator-set DMARC source tag. Created/updated/deleted from the admin UI\n * so operators can mark \"this IP is our SendGrid\", \"this is Hubspot\", etc.\n * Merged with `MailerConfig.dmarc.knownSources` at read time — the config\n * version is read-only baseline, the collection is mutable runtime state.\n */\nexport interface DmarcSourceTagDoc {\n _id?: ObjectId\n ip: string\n label: string\n ignored: boolean\n setBy: string\n setAt: Date\n}\n\nexport type SndsFilterResult = 'GREEN' | 'YELLOW' | 'RED' | 'UNKNOWN'\n\n/**\n * One row from a Microsoft SNDS data export covering a single activity\n * window for one sending IP. Stored unique per (ip, activityStart) so\n * historical windows accumulate without re-writing.\n */\nexport interface SndsSnapshotDoc {\n _id?: ObjectId\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n /** 0-1 fraction. SNDS reports as \"<0.1%\", \"0.1-0.3%\", etc; we store the upper bound. null when unknown. */\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n fetchedAt: Date\n}\n\nexport type DnsblResult = 'clean' | 'listed' | 'error'\nexport type DnsblTargetKind = 'domain' | 'ip'\n\n/**\n * Latest DNSBL check result per (target, list). Replaced in-place on each run\n * so the collection stays small. History (if needed later) lives in audit_log.\n */\nexport interface DnsblCheckDoc {\n _id?: ObjectId\n /** Domain (e.g. `mkt.example.com`) or dotted-quad IP (e.g. `203.0.113.5`). */\n target: string\n targetKind: DnsblTargetKind\n /** DNS suffix queried (e.g. `dbl.spamhaus.org`). */\n list: string\n /** Display label for the UI (e.g. `Spamhaus DBL`). */\n listLabel: string\n result: DnsblResult\n /** A records returned by the lookup, when listed. */\n returnCodes: string[]\n /** When result is 'error', the message; otherwise null. */\n errorMessage: string | null\n runAt: Date\n}\n\nexport interface ContactTagDoc {\n _id?: ObjectId\n externalId: string\n tag: string\n appliedBy: 'flow' | 'admin' | 'script' | 'import'\n appliedAt: Date\n}\n\n// ---------------------------------------------------------------------------\n// Collection factory\n// ---------------------------------------------------------------------------\n\nexport interface Collections {\n subscriptions: Collection<SubscriptionDoc>\n leads: Collection<LeadDoc>\n events: Collection<EventDoc>\n flows: Collection<FlowDoc>\n flowVersions: Collection<FlowVersionDoc>\n flowRuns: Collection<FlowRunDoc>\n templates: Collection<TemplateDoc>\n templateVersions: Collection<TemplateVersionDoc>\n sends: Collection<SendDoc>\n suppressions: Collection<SuppressionDoc>\n broadcasts: Collection<BroadcastDoc>\n outbox: Collection<OutboxDoc>\n auditLog: Collection<AuditLogDoc>\n webhookEvents: Collection<WebhookEventDoc>\n health: Collection<HealthDoc>\n contactTags: Collection<ContactTagDoc>\n dnsblChecks: Collection<DnsblCheckDoc>\n postmasterSnapshots: Collection<PostmasterSnapshotDoc>\n sndsSnapshots: Collection<SndsSnapshotDoc>\n dmarcReports: Collection<DmarcReportDoc>\n dmarcFailures: Collection<DmarcFailureDoc>\n dmarcSourceTags: Collection<DmarcSourceTagDoc>\n mailTesterScores: Collection<MailTesterScoreDoc>\n}\n\nexport function getCollections(db: Db, prefix = 'mailer_'): Collections {\n return {\n subscriptions: db.collection<SubscriptionDoc>(`${prefix}subscriptions`),\n leads: db.collection<LeadDoc>(`${prefix}leads`),\n events: db.collection<EventDoc>(`${prefix}events`),\n flows: db.collection<FlowDoc>(`${prefix}flows`),\n flowVersions: db.collection<FlowVersionDoc>(`${prefix}flow_versions`),\n flowRuns: db.collection<FlowRunDoc>(`${prefix}flow_runs`),\n templates: db.collection<TemplateDoc>(`${prefix}templates`),\n templateVersions: db.collection<TemplateVersionDoc>(`${prefix}template_versions`),\n sends: db.collection<SendDoc>(`${prefix}sends`),\n suppressions: db.collection<SuppressionDoc>(`${prefix}suppressions`),\n broadcasts: db.collection<BroadcastDoc>(`${prefix}broadcasts`),\n outbox: db.collection<OutboxDoc>(`${prefix}outbox`),\n auditLog: db.collection<AuditLogDoc>(`${prefix}audit_log`),\n webhookEvents: db.collection<WebhookEventDoc>(`${prefix}webhook_events`),\n health: db.collection<HealthDoc>(`${prefix}health`),\n contactTags: db.collection<ContactTagDoc>(`${prefix}contact_tags`),\n dnsblChecks: db.collection<DnsblCheckDoc>(`${prefix}dnsbl_checks`),\n postmasterSnapshots: db.collection<PostmasterSnapshotDoc>(`${prefix}postmaster_snapshots`),\n sndsSnapshots: db.collection<SndsSnapshotDoc>(`${prefix}snds_snapshots`),\n dmarcReports: db.collection<DmarcReportDoc>(`${prefix}dmarc_reports`),\n dmarcFailures: db.collection<DmarcFailureDoc>(`${prefix}dmarc_failures`),\n dmarcSourceTags: db.collection<DmarcSourceTagDoc>(`${prefix}dmarc_source_tags`),\n mailTesterScores: db.collection<MailTesterScoreDoc>(`${prefix}mail_tester_scores`),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Index ensurer\n// ---------------------------------------------------------------------------\n\nexport async function ensureIndexes(db: Db, prefix = 'mailer_'): Promise<void> {\n const c = getCollections(db, prefix)\n\n await Promise.all([\n c.subscriptions.createIndexes([\n { key: { externalId: 1 }, unique: true },\n { key: { status: 1, unsubscribedAt: -1 } },\n ]),\n c.leads.createIndexes([\n { key: { email: 1 }, unique: true },\n { key: { status: 1, createdAt: -1 } },\n ]),\n c.events.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, occurredAt: -1 } },\n { key: { name: 1, occurredAt: -1 } },\n { key: { name: 1, createdAt: 1 } },\n { key: { externalId: 1, name: 1 } },\n ]),\n c.flows.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { enabled: 1, 'trigger.type': 1, 'trigger.eventName': 1 } },\n ]),\n c.flowVersions.createIndexes([{ key: { flowId: 1, version: 1 }, unique: true }]),\n c.flowRuns.createIndexes([\n { key: { status: 1, nextActionAt: 1 } },\n { key: { externalId: 1, flowId: 1 } },\n { key: { flowId: 1, status: 1 } },\n {\n key: { flowId: 1, triggerDedupeKey: 1 },\n unique: true,\n partialFilterExpression: { triggerDedupeKey: { $type: 'string' } },\n },\n ]),\n c.templates.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { tags: 1 } },\n { key: { kind: 1 } },\n ]),\n c.templateVersions.createIndexes([{ key: { templateId: 1, version: 1 }, unique: true }]),\n c.sends.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, sentAt: -1 } },\n { key: { templateId: 1, sentAt: -1 } },\n { key: { flowRunId: 1 }, sparse: true },\n { key: { broadcastId: 1 }, sparse: true },\n { key: { providerMessageId: 1 }, sparse: true },\n { key: { status: 1, queuedAt: 1 } },\n { key: { status: 1, updatedAt: 1 } },\n ]),\n c.suppressions.createIndexes([\n { key: { email: 1, scope: 1 }, unique: true, partialFilterExpression: { email: { $type: 'string' } } },\n { key: { emailHash: 1 } },\n { key: { addedAt: -1 } },\n ]),\n c.broadcasts.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { status: 1, scheduledAt: 1 } },\n ]),\n c.outbox.createIndexes([\n { key: { status: 1, enqueuedAt: 1 } },\n { key: { 'payload.dedupeKey': 1 }, unique: true },\n ]),\n c.auditLog.createIndexes([\n { key: { occurredAt: -1 } },\n { key: { 'resource.collection': 1, 'resource.id': 1, occurredAt: -1 } },\n { key: { actor: 1, occurredAt: -1 } },\n ]),\n c.webhookEvents.createIndexes([\n { key: { provider: 1, providerEventId: 1 }, unique: true },\n { key: { providerMessageId: 1 } },\n { key: { processed: 1, receivedAt: 1 } },\n ]),\n c.contactTags.createIndexes([\n { key: { externalId: 1, tag: 1 }, unique: true },\n { key: { tag: 1 } },\n ]),\n c.health.createIndexes([\n { key: { senderDomain: 1, kind: 1 } },\n { key: { status: 1 } },\n // setup-status reads the most-recently-touched health doc as a heartbeat.\n { key: { updatedAt: -1 } },\n ]),\n c.dnsblChecks.createIndexes([\n { key: { target: 1, list: 1 }, unique: true },\n // Supports the admin /dnsbl GET sort: result asc, then target asc, list asc.\n { key: { result: 1, target: 1, list: 1 } },\n // TTL — stale rows for targets the operator removed disappear after\n // 60 days without manual cleanup. The puller refreshes runAt on\n // every active target so existing targets stay indefinitely.\n { key: { runAt: 1 }, expireAfterSeconds: 60 * 24 * 60 * 60 },\n ]),\n c.postmasterSnapshots.createIndexes([\n { key: { domain: 1, date: 1 }, unique: true },\n { key: { domain: 1, fetchedAt: -1 } },\n { key: { domainReputation: 1 } },\n ]),\n c.sndsSnapshots.createIndexes([\n { key: { ip: 1, activityStart: 1 }, unique: true },\n { key: { ip: 1, fetchedAt: -1 } },\n { key: { filterResult: 1 } },\n ]),\n c.dmarcReports.createIndexes([\n { key: { reportId: 1, orgName: 1 }, unique: true },\n { key: { domain: 1, rangeEnd: -1 } },\n // Cross-domain \"most recent reports\" queries scan a lot without this.\n { key: { rangeEnd: -1 } },\n { key: { receivedAt: -1 } },\n ]),\n c.dmarcFailures.createIndexes([\n { key: { reportId: 1, sourceIp: 1 }, unique: true },\n { key: { domain: 1, day: -1 } },\n { key: { sourceIp: 1, day: -1 } },\n { key: { receivedAt: 1 } }, // for retention pruning\n ]),\n c.dmarcSourceTags.createIndexes([\n { key: { ip: 1 }, unique: true },\n ]),\n c.mailTesterScores.createIndexes([\n { key: { contentKey: 1 }, unique: true },\n { key: { templateSlug: 1, fetchedAt: -1 } },\n // TTL — Mongo auto-deletes expired scores so we never serve stale data.\n { key: { expiresAt: 1 }, expireAfterSeconds: 0 },\n ]),\n ])\n\n // One-shot migrations — run after indexes are in place so any DELETE\n // plan can use them. Idempotent at MongoDB level (returns 0 when\n // nothing is there).\n await c.health.deleteOne({ _id: 'singleton' as any }).catch(() => {})\n}\n","/**\n * Event registry + dedupe-key policy. INVARIANT 1: every `mailer_events` row\n * has a unique dedupeKey. Callers either pass one or `mailer.registerEvent`\n * declares a policy and we derive it.\n */\n\nimport crypto from 'node:crypto'\n\nexport type DedupePolicy = 'once-per-contact' | 'once-per-day' | 'every-time'\n\nexport interface EventRegistration {\n name: string\n dedupePolicy: DedupePolicy\n}\n\nexport class EventRegistry {\n private readonly policies = new Map<string, DedupePolicy>()\n\n register(reg: EventRegistration): void {\n this.policies.set(reg.name, reg.dedupePolicy)\n }\n\n has(name: string): boolean {\n return this.policies.has(name)\n }\n\n policy(name: string): DedupePolicy | undefined {\n return this.policies.get(name)\n }\n\n list(): EventRegistration[] {\n return Array.from(this.policies, ([name, dedupePolicy]) => ({ name, dedupePolicy }))\n }\n\n /**\n * Derive a dedupeKey for an event call. Returns null when no policy is\n * registered AND no key was passed — caller should throw.\n */\n deriveKey(\n name: string,\n externalId: string,\n passedKey: string | undefined,\n now: Date,\n ): string | null {\n if (passedKey) return passedKey\n const policy = this.policies.get(name)\n if (!policy) return null\n\n switch (policy) {\n case 'once-per-contact':\n return `${externalId}:${name}`\n case 'once-per-day':\n return `${externalId}:${name}:${isoDay(now)}`\n case 'every-time':\n return `${externalId}:${name}:${randomId()}`\n }\n }\n}\n\nfunction isoDay(d: Date): string {\n return d.toISOString().slice(0, 10)\n}\n\nfunction randomId(): string {\n return crypto.randomBytes(8).toString('hex')\n}\n","/**\n * HMAC-signed tokens for unsubscribe + preference-center URLs.\n *\n * Format: base64url(payload) '.' base64url(hmac)\n * payload = JSON.stringify({ e: email, s: scope, x: expiresAtMs })\n * hmac = HMAC-SHA256(secret, payload)\n *\n * Tokens expire because long-lived signed URLs are a liability.\n */\n\nimport crypto from 'node:crypto'\nimport type { SuppressionScope } from '../shared/enums.js'\n\nexport interface UnsubscribeTokenPayload {\n email: string\n scope: SuppressionScope\n expiresAt: Date\n}\n\nexport function signUnsubscribeToken(\n payload: UnsubscribeTokenPayload,\n secret: string,\n): string {\n const body = JSON.stringify({\n e: payload.email.toLowerCase(),\n s: payload.scope,\n x: payload.expiresAt.getTime(),\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyUnsubscribeToken(\n token: string,\n secret: string,\n now: Date = new Date(),\n): UnsubscribeTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { e?: string; s?: string; x?: number }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.e || !body.s || typeof body.x !== 'number') return null\n if (body.x < now.getTime()) return null\n if (body.s !== 'all' && body.s !== 'marketing' && body.s !== 'transactional') return null\n\n return {\n email: body.e,\n scope: body.s,\n expiresAt: new Date(body.x),\n }\n}\n\nfunction b64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction b64urlDecode(s: string): Buffer {\n const padded = s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4)\n return Buffer.from(padded, 'base64')\n}\n\n/**\n * sha256 hex digest, used for storing email hashes (GDPR forget) and dedup helpers.\n */\nexport function sha256Hex(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex')\n}\n\n// ---------------------------------------------------------------------------\n// Double opt-in tokens\n// ---------------------------------------------------------------------------\n\nexport interface DoiTokenPayload {\n externalId: string\n expiresAt: Date\n}\n\n/**\n * Sign a DOI confirmation token. Same shape as the unsubscribe token, but\n * scoped to \"this externalId confirmed their subscription.\"\n */\nexport function signDoiToken(payload: DoiTokenPayload, secret: string): string {\n const body = JSON.stringify({\n i: payload.externalId,\n x: payload.expiresAt.getTime(),\n k: 'doi',\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyDoiToken(token: string, secret: string, now: Date = new Date()): DoiTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { i?: string; x?: number; k?: string }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.i || typeof body.x !== 'number' || body.k !== 'doi') return null\n if (body.x < now.getTime()) return null\n\n return { externalId: body.i, expiresAt: new Date(body.x) }\n}\n","/**\n * BullMQ driver. Four named queues backed by Redis. Job-level `attempts`,\n * `backoff`, `delay`, and `jobId` pass through to BullMQ's native semantics.\n * Send rate limit is enforced via BullMQ's `limiter` option (Redis Lua script).\n */\n\nimport type { Queue, Worker } from 'bullmq'\nimport IORedis, { type RedisOptions as IORedisOptions } from 'ioredis'\n\nimport type { RedisOptions } from '../config.js'\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface BullQueues {\n tick: Queue\n advance: Queue\n send: Queue\n webhook: Queue\n}\n\ninterface BullModule {\n Queue: typeof Queue\n Worker: typeof Worker\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\nexport class BullDriver implements QueueDriver {\n readonly queues: Queues\n private redis: IORedis\n private bullQueues: BullQueues\n private workers: { tick: Worker; advance: Worker; send: Worker; webhook: Worker } | null = null\n private bull: BullModule\n\n static async create(redisConfig: RedisOptions | IORedis, prefix?: string): Promise<BullDriver> {\n let bull: BullModule\n try {\n bull = (await import('bullmq')) as unknown as BullModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'bull' requires the 'bullmq' peer dependency. Run `npm install bullmq ioredis`.\",\n )\n }\n if (prefix?.includes(':')) {\n throw new Error(\n `mailery: queue prefix \"${prefix}\" must not contain ':' — BullMQ uses it as the Redis key separator.`,\n )\n }\n const redis = isRedisLike(redisConfig) ? (redisConfig as IORedis) : connect(redisConfig as RedisOptions)\n return new BullDriver(bull, redis, prefix)\n }\n\n private prefix?: string\n\n private constructor(bull: BullModule, redis: IORedis, prefix?: string) {\n this.bull = bull\n this.redis = redis\n this.prefix = prefix\n // Bounded retention: completed/failed jobs must not accumulate in Redis\n // forever. Completed jobs also need to leave promptly so jobId-based\n // idempotent re-adds aren't dropped against a stale completed job.\n const opts = {\n connection: redis,\n prefix,\n defaultJobOptions: {\n removeOnComplete: { age: 24 * 3600, count: 1000 },\n removeOnFail: { age: 7 * 24 * 3600 },\n },\n }\n this.bullQueues = {\n tick: new bull.Queue(QUEUE_NAMES.tick, opts),\n advance: new bull.Queue(QUEUE_NAMES.advance, opts),\n send: new bull.Queue(QUEUE_NAMES.send, opts),\n webhook: new bull.Queue(QUEUE_NAMES.webhook, opts),\n }\n this.queues = {\n tick: adaptBullQueue(this.bullQueues.tick),\n advance: adaptBullQueue(this.bullQueues.advance),\n send: adaptBullQueue(this.bullQueues.send),\n webhook: adaptBullQueue(this.bullQueues.webhook),\n }\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n await (this.bullQueues.tick as any).upsertJobScheduler(\n 'mailer-tick-repeat',\n { every: intervalSeconds * 1000 },\n {\n name: 'tick',\n data: {},\n opts: { removeOnComplete: { count: 20 }, removeOnFail: { count: 50 } },\n },\n )\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n if (this.workers) return\n // Workers must share the queues' prefix or they'd poll different keys.\n const base = { connection: this.redis, prefix: this.prefix }\n const { Worker } = this.bull\n\n const tick = new Worker(\n QUEUE_NAMES.tick,\n async (job: any) => opts.handlers.tick(job.data),\n { ...base, concurrency: 1 },\n )\n const advance = new Worker(\n QUEUE_NAMES.advance,\n async (job: any) => opts.handlers.advance(job.data),\n { ...base, concurrency: 10 },\n )\n const send = new Worker(\n QUEUE_NAMES.send,\n async (job: any) => opts.handlers.send(job.data),\n {\n ...base,\n concurrency: opts.concurrency.send,\n limiter: opts.sendRateLimit\n ? { max: opts.sendRateLimit.max, duration: opts.sendRateLimit.durationMs }\n : undefined,\n },\n )\n const webhook = new Worker(\n QUEUE_NAMES.webhook,\n async (job: any) => opts.handlers.webhook(job.data),\n { ...base, concurrency: 4 },\n )\n\n this.workers = { tick, advance, send, webhook }\n }\n\n async stopWorkers(): Promise<void> {\n if (!this.workers) return\n await Promise.all([\n this.workers.tick.close(),\n this.workers.advance.close(),\n this.workers.send.close(),\n this.workers.webhook.close(),\n ])\n this.workers = null\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n await Promise.all([\n this.bullQueues.tick.close(),\n this.bullQueues.advance.close(),\n this.bullQueues.send.close(),\n this.bullQueues.webhook.close(),\n ])\n }\n}\n\nfunction adaptBullQueue(q: Queue): QueueAPI {\n return {\n add: (name, data, opts) => q.add(name, data as any, opts as any),\n getWaitingCount: () => q.getWaitingCount(),\n getInFlightCount: async () => {\n const [active, waiting] = await Promise.all([q.getActiveCount(), q.getWaitingCount()])\n return active + waiting\n },\n getDelayedCount: () => q.getDelayedCount(),\n close: () => q.close(),\n }\n}\n\nfunction isRedisLike(x: unknown): boolean {\n return !!x && typeof x === 'object' && typeof (x as any).get === 'function' && typeof (x as any).set === 'function'\n}\n\nfunction connect(opts: RedisOptions): IORedis {\n const config: IORedisOptions = {\n maxRetriesPerRequest: null, // BullMQ requirement\n enableReadyCheck: false,\n }\n if (opts.url) return new IORedis(opts.url, config)\n return new IORedis({\n ...config,\n host: opts.host ?? '127.0.0.1',\n port: opts.port ?? 6379,\n password: opts.password,\n db: opts.db,\n username: opts.username,\n tls: opts.tls ? {} : undefined,\n })\n}\n\n// Re-exports needed by the broader queue surface\nexport type { AddOptions }\n","/**\n * Agenda driver. Backed by the same MongoDB instance the rest of mailery uses,\n * so no Redis is required. Uses `agenda` + `@agendajs/mongo-backend`.\n *\n * Single-process only: send rate limit is enforced via an in-memory Bottleneck\n * wrapped around the send handler. Multi-process Agenda deployments would\n * fan-out beyond the rate cap — out of scope.\n *\n * Retry/backoff: applied per-definition via Agenda's built-in\n * `backoffStrategies.exponential`. Per-call `attempts` from add() is ignored;\n * the driver uses the shared config-level `sendRetryAttempts`.\n *\n * Idempotency: per-call `jobId` is stored as `data.__jobId`. Before scheduling\n * we look for a pending (not-yet-run, not-finished) job with the same key.\n */\n\nimport type { Db } from 'mongodb'\nimport type { Agenda, Job } from 'agenda'\nimport type Bottleneck from 'bottleneck'\n\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface AgendaModule {\n Agenda: typeof Agenda\n backoffStrategies: { exponential: (opts: { delay: number; maxRetries: number; factor?: number }) => any }\n}\n\ninterface MongoBackendModule {\n MongoBackend: new (cfg: { mongo: Db; collection?: string; ensureIndex?: boolean }) => any\n}\n\ninterface BottleneckCtor {\n new (opts: { minTime?: number; maxConcurrent?: number }): Bottleneck\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\nexport interface AgendaDriverOptions {\n db: Db\n processEverySeconds?: number\n lockLifetimeSeconds?: number\n collectionName?: string\n}\n\nexport class AgendaDriver implements QueueDriver {\n readonly queues: Queues\n private agenda: Agenda\n private agendaMod: AgendaModule\n private sendLimiter: Bottleneck | null = null\n private started = false\n\n static async create(opts: AgendaDriverOptions): Promise<AgendaDriver> {\n let agendaMod: AgendaModule\n let backendMod: MongoBackendModule\n try {\n agendaMod = (await import('agenda')) as unknown as AgendaModule\n backendMod = (await import('@agendajs/mongo-backend')) as unknown as MongoBackendModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' requires the 'agenda' and '@agendajs/mongo-backend' peer dependencies. Run `npm install agenda @agendajs/mongo-backend bottleneck`.\",\n )\n }\n\n const collectionName = opts.collectionName ?? '_mailerJobs'\n const backend = new backendMod.MongoBackend({\n mongo: opts.db,\n collection: collectionName,\n })\n\n const agenda = new agendaMod.Agenda({\n backend,\n processEvery: `${opts.processEverySeconds ?? 5} seconds`,\n defaultLockLifetime: (opts.lockLifetimeSeconds ?? 10 * 60) * 1000,\n maxConcurrency: 50,\n defaultConcurrency: 5,\n } as any)\n\n return new AgendaDriver(agenda, agendaMod, opts.db, collectionName)\n }\n\n private db: Db\n private collName: string\n\n private constructor(agenda: Agenda, agendaMod: AgendaModule, db: Db, collectionName: string) {\n this.agenda = agenda\n this.agendaMod = agendaMod\n this.db = db\n this.collName = collectionName\n this.queues = {\n tick: this.makeQueueAPI(QUEUE_NAMES.tick),\n advance: this.makeQueueAPI(QUEUE_NAMES.advance),\n send: this.makeQueueAPI(QUEUE_NAMES.send),\n webhook: this.makeQueueAPI(QUEUE_NAMES.webhook),\n }\n }\n\n private makeQueueAPI(name: string): QueueAPI {\n return {\n add: async (_jobName: string, data: unknown, opts?: AddOptions) => {\n const payload: Record<string, unknown> = { ...(data as object) }\n if (opts?.jobId) {\n payload.__jobId = opts.jobId\n if (await this.findPending(name, opts.jobId)) return\n }\n const job = this.agenda.create(name, payload as any)\n if (opts?.delay) job.schedule(new Date(Date.now() + opts.delay))\n await job.save()\n },\n getWaitingCount: async () => {\n return this.jobsCollection().countDocuments({\n name,\n $or: [{ lockedAt: null }, { lockedAt: { $exists: false } }],\n nextRunAt: { $lte: new Date() },\n })\n },\n close: async () => {},\n }\n }\n\n /** Direct access to the Mongo collection Agenda persists jobs into. */\n private jobsCollection() {\n return this.db.collection(this.collName)\n }\n\n private async findPending(name: string, jobId: string): Promise<unknown> {\n return this.jobsCollection().findOne({\n name,\n 'data.__jobId': jobId,\n $or: [{ lastFinishedAt: null }, { lastFinishedAt: { $exists: false } }],\n })\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n // Persist the repeating job only — do NOT start Agenda here. Starting with\n // a placeholder tick handler would let a process that never calls\n // startWorkers (API-only process in a web/worker split) lock and complete\n // tick jobs as no-ops, silently swallowing real ticks. Agenda starts in\n // startWorkers, after the real handlers are defined.\n await this.agenda.every(`${intervalSeconds} seconds`, QUEUE_NAMES.tick)\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n const exp = this.agendaMod.backoffStrategies.exponential\n\n if (opts.sendRateLimit) {\n try {\n const Bottleneck = (await import('bottleneck')).default as unknown as BottleneckCtor\n this.sendLimiter = new Bottleneck({\n minTime: Math.ceil(opts.sendRateLimit.durationMs / opts.sendRateLimit.max),\n maxConcurrent: opts.concurrency.send,\n })\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' with sendRateLimit requires the 'bottleneck' peer dependency. Run `npm install bottleneck`.\",\n )\n }\n }\n\n const retryBackoff = exp({ delay: 60_000, maxRetries: Math.max(0, opts.retryAttempts - 1), factor: 2 })\n\n this.agenda.define(QUEUE_NAMES.tick, async (job: Job) => {\n await opts.handlers.tick(job.attrs.data)\n }, { concurrency: 1 })\n\n this.agenda.define(QUEUE_NAMES.advance, async (job: Job) => {\n await opts.handlers.advance(job.attrs.data as any)\n }, { concurrency: 10, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.send, async (job: Job) => {\n const data = job.attrs.data as any\n if (this.sendLimiter) {\n await this.sendLimiter.schedule(() => opts.handlers.send(data))\n } else {\n await opts.handlers.send(data)\n }\n }, { concurrency: opts.concurrency.send, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.webhook, async (job: Job) => {\n await opts.handlers.webhook(job.attrs.data as any)\n }, { concurrency: 4, backoff: retryBackoff })\n\n if (!this.started) {\n await this.agenda.start()\n this.started = true\n }\n }\n\n async stopWorkers(): Promise<void> {\n if (!this.started) return\n await this.agenda.stop()\n this.started = false\n if (this.sendLimiter) {\n await this.sendLimiter.stop({ dropWaitingJobs: true }).catch(() => {})\n this.sendLimiter = null\n }\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n }\n}\n","/**\n * No-op queue driver. Used by tests and by hosts that drive the runner\n * synchronously (no background workers, no Redis, no Agenda). `add()` is a\n * no-op; the caller is expected to invoke runner functions directly.\n */\n\nimport type {\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nfunction noopQueueAPI(): QueueAPI {\n return {\n add: async () => undefined,\n getWaitingCount: async () => 0,\n close: async () => undefined,\n }\n}\n\nexport class NoopDriver implements QueueDriver {\n readonly queues: Queues = {\n tick: noopQueueAPI(),\n advance: noopQueueAPI(),\n send: noopQueueAPI(),\n webhook: noopQueueAPI(),\n }\n\n async scheduleRepeatingTick(_intervalSeconds: number): Promise<void> {\n /* noop */\n }\n\n async startWorkers(_opts: WorkerStartOptions): Promise<void> {\n /* noop */\n }\n\n async stopWorkers(): Promise<void> {\n /* noop */\n }\n\n async close(): Promise<void> {\n /* noop */\n }\n}\n","/**\n * Queue subsystem entry point. Exports the driver interface, the three\n * built-in drivers (Bull, Agenda, Noop), and a factory that resolves a\n * `QueueDriverConfig` to a concrete driver.\n */\n\nimport type { Db } from 'mongodb'\n\nimport { BullDriver } from './bull.js'\nimport { AgendaDriver } from './agenda.js'\nimport { NoopDriver } from './noop.js'\nimport type { QueueDriver, QueueDriverConfig } from './types.js'\n\nexport { BullDriver } from './bull.js'\nexport { AgendaDriver } from './agenda.js'\nexport { NoopDriver } from './noop.js'\nexport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n QueueDriverConfig,\n QueueHandlers,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nexport async function createQueueDriver(\n config: QueueDriverConfig,\n fallbackDb: Db,\n): Promise<QueueDriver> {\n switch (config.driver) {\n case 'bull':\n return BullDriver.create(config.redis, config.prefix)\n case 'agenda':\n return AgendaDriver.create({\n db: config.db ?? fallbackDb,\n processEverySeconds: config.processEverySeconds,\n lockLifetimeSeconds: config.lockLifetimeSeconds,\n collectionName: config.collectionName,\n })\n case 'noop':\n return new NoopDriver()\n default: {\n const _exhaustive: never = config\n void _exhaustive\n throw new Error(`mailery: unknown queue driver`)\n }\n }\n}\n","/**\n * Event-trigger scan. Finds new event firings since each flow's\n * lastTriggerScanAt watermark, creates flow_runs for matching contacts,\n * enqueues immediate-advance jobs.\n */\n\nimport type { RunnerContext } from './index.js'\nimport type { FlowDoc, EventDoc } from '../models/index.js'\n\nconst BATCH_SIZE = 1000\n\n/**\n * Re-scan window. The watermark advances on `createdAt` (insert time), but a\n * concurrent `fire()` can commit a row with a createdAt slightly before the\n * scan's read. Re-reading this much history every pass closes that race; the\n * unique (flowId, triggerDedupeKey) index makes re-reads harmless.\n */\nconst SCAN_OVERLAP_MS = 30_000\n\nexport async function processNewlyFiredEventTriggers(ctx: RunnerContext): Promise<void> {\n const flows = await ctx.collections.flows.find({ enabled: true, 'trigger.type': 'event' }).toArray()\n for (const flow of flows) {\n await processFlowTriggers(flow, ctx)\n }\n}\n\nasync function processFlowTriggers(flow: FlowDoc, ctx: RunnerContext): Promise<void> {\n const eventName = flow.trigger.eventName\n if (!eventName) return\n // Watermark on createdAt, not occurredAt: occurredAt can lag insert time\n // (outbox-drained events carry the host-transaction timestamp), so an\n // occurredAt watermark permanently skips any event that lands \"in the past.\"\n // createdAt only ever moves forward with inserts.\n const since = flow.lastTriggerScanAt ?? flow.createdAt\n const scanFrom = new Date(since.getTime() - SCAN_OVERLAP_MS)\n\n const events = await ctx.collections.events\n .find({ name: eventName, createdAt: { $gt: scanFrom } })\n .sort({ createdAt: 1 })\n .limit(BATCH_SIZE)\n .toArray()\n\n if (events.length === 0) return\n\n for (const event of events) {\n await tryEnterFlow(flow, event, ctx)\n }\n\n const newestCreatedAt = events[events.length - 1]!.createdAt\n if (newestCreatedAt.getTime() > since.getTime()) {\n await ctx.collections.flows.updateOne(\n { _id: flow._id },\n { $set: { lastTriggerScanAt: newestCreatedAt, updatedAt: new Date() } },\n )\n }\n}\n\nasync function tryEnterFlow(flow: FlowDoc, event: EventDoc, ctx: RunnerContext): Promise<void> {\n if (flow.trigger.once) {\n const existing = await ctx.collections.flowRuns.findOne(\n { externalId: event.externalId, flowId: flow._id },\n { projection: { _id: 1 } },\n )\n if (existing) return\n }\n\n // Flow entry requires an active subscription — flows are marketing-scope.\n // Transactional mail for not-subscribed contacts goes through sendOneOff.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: event.externalId })\n if (!sub || sub.status !== 'subscribed') return\n\n let result\n try {\n result = await ctx.collections.flowRuns.insertOne({\n externalId: event.externalId,\n flowId: flow._id!,\n flowSlug: flow.slug,\n flowVersion: flow.version,\n emailAtEntry: sub.emailAtSubscribe,\n triggerEvent: { name: event.name, properties: event.properties ?? {}, occurredAt: event.occurredAt },\n triggerDedupeKey: event.dedupeKey,\n enteredAt: new Date(),\n status: 'active',\n currentStepIndex: 0,\n currentBranchPath: [],\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n history: [{ stepIndex: -1, action: 'entered', at: new Date(), details: { eventDedupeKey: event.dedupeKey } }],\n exitedAt: null,\n exitReason: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n } catch (err: any) {\n // Event already entered this flow (overlap-window re-read) — no-op.\n if (err?.code !== 11000) throw err\n return\n }\n\n await ctx.queues.advance.add('advance', { flowRunId: String(result.insertedId) })\n}\n","/**\n * Sender-domain validator.\n *\n * Hosts may declare a `senderDomains` registry mapping a domain to which kind\n * of email is allowed to send from it. Used to isolate marketing reputation\n * from transactional reputation:\n *\n * senderDomains: {\n * 'news.example.com': { kind: 'marketing' },\n * 'mail.example.com': { kind: 'transactional' },\n * 'tools.example.com': { kind: 'both' }, // OK for either kind\n * }\n *\n * The check runs at template publish time. If a template's `fromEmail` domain\n * isn't declared, or is declared for the wrong kind, publish fails with a\n * descriptive 400. Hosts who don't set `senderDomains` get no enforcement —\n * back-compat default.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\n\nexport interface SenderDomainConfig {\n /** Which template `kind` may use this domain as a From address. */\n kind: 'marketing' | 'transactional' | 'both'\n}\n\nexport type SenderDomainRegistry = Record<string, SenderDomainConfig>\n\nexport type SenderDomainValidation =\n | { ok: true }\n | { ok: false; code: 'invalid_email' | 'unregistered_domain' | 'wrong_kind'; reason: string }\n\nexport function validateSenderDomain(\n fromEmail: string,\n templateKind: TemplateKind,\n registry: SenderDomainRegistry | undefined,\n): SenderDomainValidation {\n if (!registry || Object.keys(registry).length === 0) return { ok: true }\n\n const domain = extractDomain(fromEmail)\n if (!domain) {\n return {\n ok: false,\n code: 'invalid_email',\n reason: `invalid fromEmail \"${fromEmail}\" — expected \"name@domain\"`,\n }\n }\n\n const entry = registry[domain]\n if (!entry) {\n const known = Object.keys(registry).join(', ')\n return {\n ok: false,\n code: 'unregistered_domain',\n reason: `sender domain \"${domain}\" is not declared in senderDomains (allowed: ${known})`,\n }\n }\n\n if (entry.kind === 'both') return { ok: true }\n if (entry.kind !== templateKind) {\n return {\n ok: false,\n code: 'wrong_kind',\n reason: `sender domain \"${domain}\" is configured for ${entry.kind} email, but this template's kind is ${templateKind}`,\n }\n }\n\n return { ok: true }\n}\n\nexport function extractDomain(email: string): string | null {\n if (typeof email !== 'string') return null\n const at = email.lastIndexOf('@')\n if (at <= 0 || at === email.length - 1) return null\n return email.slice(at + 1).toLowerCase().trim()\n}\n","/**\n * Circuit breaker. Tracks rolling counters in mailer_health per\n * (senderDomain, kind) bucket plus a single aggregate roll-up. Computes rates\n * on each tick and trips individual buckets when thresholds are exceeded.\n *\n * status: 'healthy' — normal\n * 'degraded' — non-blocking warnings (e.g. high failed-to-send rate)\n * 'tripped' — marketing sends held; transactional bypasses (INVARIANT 6)\n *\n * The aggregate doc is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n *\n * Recovery is manual (admin UI: POST /api/health/resume[?domain&kind]).\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { HealthDoc } from '../models/index.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\ntype CounterKey =\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'hardBounced'\n | 'softBounced'\n | 'complained'\n | 'failedToSend'\n\nexport interface HealthDims {\n /** Caller passes the raw `fromEmail`; we extract the domain here. */\n fromEmail: string | null\n kind: TemplateKind\n}\n\nconst ZERO_COUNTERS = {\n sent: 0,\n delivered: 0,\n bounced: 0,\n hardBounced: 0,\n softBounced: 0,\n complained: 0,\n failedToSend: 0,\n}\n\nconst ZERO_RATES = {\n bounceRate: 0,\n hardBounceRate: 0,\n complaintRate: 0,\n failureRate: 0,\n}\n\n/**\n * Bump a counter on the relevant bucket doc plus the aggregate doc. Called\n * from the send / webhook paths. Idempotent at the document level (upsert).\n *\n * `dims` is null when we can't attribute the event (e.g. webhook event with\n * no matching send) — in that case only the aggregate is updated.\n */\nexport async function recordHealthCounter(\n ctx: RunnerContext,\n counter: CounterKey,\n dims: HealthDims | null,\n by = 1,\n): Promise<void> {\n const windowMs = ctx.config.circuitBreaker.windowMinutes * 60 * 1000\n const writes: Array<Promise<unknown>> = []\n\n writes.push(upsertCounter(ctx, HEALTH_AGG_ID, null, null, counter, by, windowMs))\n\n if (dims) {\n // Skip the bucket write when we can't extract a real domain from\n // fromEmail rather than funneling unrelated invalid-sender sends into a\n // shared `_unknown` bucket — that bucket can collect bounces from many\n // unrelated sources and falsely trip them all at once.\n const domain = dims.fromEmail ? extractDomain(dims.fromEmail) : null\n if (domain) {\n const id = healthBucketId(domain, dims.kind)\n writes.push(upsertCounter(ctx, id, domain, dims.kind, counter, by, windowMs))\n }\n }\n\n await Promise.all(writes)\n}\n\nasync function upsertCounter(\n ctx: RunnerContext,\n _id: string,\n senderDomain: string | null,\n kind: TemplateKind | null,\n counter: CounterKey,\n by: number,\n windowMs: number,\n): Promise<void> {\n await ctx.collections.health.updateOne(\n { _id },\n {\n $inc: { [`counters.${counter}`]: by },\n $setOnInsert: {\n _id,\n senderDomain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n rates: { ...ZERO_RATES },\n } as Partial<HealthDoc>,\n $set: { updatedAt: new Date() },\n },\n { upsert: true },\n )\n}\n\n/**\n * Recompute rates from the rolling window for every bucket and trip individual\n * buckets when thresholds are exceeded. The aggregate doc is updated but never\n * tripped. Called from the tick.\n */\nexport async function evaluateHealth(ctx: RunnerContext): Promise<void> {\n const cb = ctx.config.circuitBreaker\n const windowMs = cb.windowMinutes * 60 * 1000\n\n const docs = await ctx.collections.health.find({}).toArray()\n if (docs.length === 0) return\n\n // Ensure the aggregate doc exists so the worker-heartbeat check has\n // something to look at as soon as any bucket exists.\n const hasAgg = docs.some((d) => d._id === HEALTH_AGG_ID)\n if (!hasAgg) {\n await upsertCounter(ctx, HEALTH_AGG_ID, null, null, 'sent', 0, windowMs)\n }\n\n for (const doc of docs) {\n const isAgg = doc._id === HEALTH_AGG_ID\n const windowAge = Date.now() - new Date(doc.windowStartedAt).getTime()\n\n if (windowAge > windowMs && doc.status !== 'tripped') {\n // Window roll: zero out counters AND reset status to healthy. A bucket\n // that was 'degraded' on the prior window but receives no samples in\n // the new window should not stay degraded — degraded is a function of\n // the current window's failureRate, not a sticky state.\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n {\n $set: {\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n counters: { ...ZERO_COUNTERS },\n rates: { ...ZERO_RATES },\n status: 'healthy',\n updatedAt: new Date(),\n },\n },\n )\n continue\n }\n\n const c = doc.counters\n const total = c.sent || 1\n const rates = {\n bounceRate: c.bounced / total,\n hardBounceRate: c.hardBounced / total,\n complaintRate: c.complained / total,\n failureRate: c.failedToSend / total,\n }\n\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { rates, updatedAt: new Date() } },\n )\n\n // Aggregate never trips, only reports.\n if (isAgg) continue\n\n if (c.sent < cb.minSendsBeforeEval) continue\n if (doc.status === 'tripped') continue\n\n let trippedReason: string | null = null\n if (rates.hardBounceRate * 100 >= cb.hardBounceRatePctTrip) {\n trippedReason = `hard bounce rate ${(rates.hardBounceRate * 100).toFixed(2)}% >= ${cb.hardBounceRatePctTrip}%`\n } else if (rates.complaintRate * 100 >= cb.complaintRatePctTrip) {\n trippedReason = `complaint rate ${(rates.complaintRate * 100).toFixed(2)}% >= ${cb.complaintRatePctTrip}%`\n } else if (rates.bounceRate * 100 >= cb.combinedBounceRatePctTrip) {\n trippedReason = `combined bounce rate ${(rates.bounceRate * 100).toFixed(2)}% >= ${cb.combinedBounceRatePctTrip}%`\n }\n\n if (trippedReason) {\n // Gate the trip write on the current non-tripped status so two\n // concurrent ticks can't both transition the same bucket. The\n // matchedCount check below tells us whether *this* tick was the one\n // that flipped it — only then do we fire the alert + audit log.\n const result = await ctx.collections.health.updateOne(\n { _id: doc._id, status: { $in: ['healthy', 'degraded'] } },\n { $set: { status: 'tripped', trippedAt: new Date(), trippedReason, updatedAt: new Date() } },\n )\n if (result.modifiedCount > 0) {\n // Audit log so the admin UI's \"Recent trips\" panel has rows to render.\n if (ctx.audit) {\n try {\n await ctx.audit({\n actor: 'system:circuit-breaker',\n action: 'health.trip',\n resource: {\n collection: 'mailer_health',\n id: String(doc._id),\n slug: `${doc.senderDomain ?? '_unknown'}|${doc.kind}`,\n },\n diffSummary: trippedReason,\n })\n } catch {\n /* swallow — audit failure must not block runner */\n }\n }\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({\n reason: `[${doc.senderDomain ?? '_unknown'} / ${doc.kind}] ${trippedReason}`,\n rates,\n })\n } catch {\n /* swallow — alert hook failures don't propagate */\n }\n }\n }\n continue\n }\n\n if (rates.failureRate * 100 >= cb.failedToSendRatePctDegrade) {\n if (doc.status !== 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'degraded', updatedAt: new Date() } },\n )\n }\n } else if (doc.status === 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'healthy', updatedAt: new Date() } },\n )\n }\n }\n}\n\n/**\n * Look up the bucket status that gates a marketing send. Returns the\n * bucket doc when found, otherwise null (which the caller treats as healthy\n * — sends from a never-seen-before bucket flow through).\n */\nexport async function getBucketStatus(\n ctx: RunnerContext,\n fromEmail: string | null,\n kind: TemplateKind,\n): Promise<HealthDoc | null> {\n const domain = fromEmail ? extractDomain(fromEmail) : null\n const id = healthBucketId(domain, kind)\n return ctx.collections.health.findOne({ _id: id })\n}\n\n/**\n * Derive an effective overall status across all buckets. The aggregate doc\n * itself never trips, so callers that want a single \"is anything wrong\"\n * answer use this. Returns null when no buckets exist yet (no tick has run).\n */\nexport function effectiveOverallStatus(docs: HealthDoc[]): HealthDoc['status'] | null {\n // Only canonical bucket docs (id prefix 'd:') participate. The aggregate\n // never trips and a legacy 'singleton' doc, if it survives the migration,\n // is ignored.\n const buckets = docs.filter((d) => typeof d._id === 'string' && d._id.startsWith('d:'))\n if (buckets.length === 0) {\n return docs.length === 0 ? null : 'healthy'\n }\n if (buckets.some((d) => d.status === 'tripped')) return 'tripped'\n if (buckets.some((d) => d.status === 'degraded')) return 'degraded'\n return 'healthy'\n}\n","/**\n * Apply a normalized provider event to the corresponding Send + cascading\n * suppression / subscription updates. Called from the webhook worker.\n */\n\nimport type { NormalizedEvent } from '../../shared/types.js'\nimport type { SendDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter, type HealthDims } from './health.js'\n\nfunction dimsFromSend(send: SendDoc | null | undefined): HealthDims | null {\n if (!send) return null\n return { fromEmail: send.fromEmail, kind: send.kind }\n}\n\n/**\n * Apply unprocessed rows from mailer_webhook_events. Called by the webhook\n * worker (no age filter) and by the tick as a fallback (`olderThanMs` set) for\n * events whose enqueue failed at ingest — those would otherwise sit unprocessed\n * until the next webhook happened to arrive. The tick's age filter keeps it out\n * of the webhook worker's way in the normal path.\n */\nexport async function processWebhookBacklog(\n ctx: RunnerContext,\n opts: { olderThanMs?: number } = {},\n): Promise<void> {\n const filter: Record<string, unknown> = { processed: false }\n if (opts.olderThanMs) {\n filter.receivedAt = { $lt: new Date(Date.now() - opts.olderThanMs) }\n }\n const batch = await ctx.collections.webhookEvents.find(filter).limit(500).toArray()\n\n for (const evt of batch) {\n // At-most-once: claim the event BEFORE applying. Concurrent workers scan\n // the same unprocessed batch; without the claim each would apply the same\n // event, double-counting bounces/complaints into the circuit-breaker\n // health counters. Losing an event to a crash mid-apply is the cheaper\n // failure mode.\n const claimed = await ctx.collections.webhookEvents.findOneAndUpdate(\n { _id: evt._id, processed: false },\n { $set: { processed: true } },\n )\n if (!claimed) continue\n\n try {\n // The stored `raw` wraps the normalized event we captured at ingest;\n // pull details back out so applyWebhookEvent has the bounce reason etc.\n const normalized = (evt.raw as any)?.normalized\n const details = normalized?.details ?? {}\n await applyWebhookEvent(\n {\n type: evt.normalizedType,\n providerEventId: evt.providerEventId,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n details,\n },\n ctx,\n )\n } catch (err) {\n console.error('mailery: webhook apply failed', { id: String(evt._id), err })\n }\n }\n}\n\nexport async function applyWebhookEvent(event: NormalizedEvent, ctx: RunnerContext): Promise<void> {\n const send = await ctx.collections.sends.findOne(\n event.providerMessageId\n ? { $or: [{ providerMessageId: event.providerMessageId }, { emailAtSend: event.email }] }\n : { emailAtSend: event.email },\n { sort: { queuedAt: -1 } },\n )\n\n switch (event.type) {\n case 'delivered':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'delivered', deliveredAt: event.occurredAt } },\n )\n }\n await recordHealthCounter(ctx, 'delivered', dimsFromSend(send))\n break\n\n case 'open':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n openedAt: send.openedAt ?? event.occurredAt,\n status: send.status === 'sent' ? 'delivered' : send.status,\n },\n $inc: { openCount: 1 },\n },\n )\n }\n break\n\n case 'click':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: { firstClickAt: send.firstClickAt ?? event.occurredAt },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: event.details.clickedUrl ?? '',\n linkId: '',\n clickedAt: event.occurredAt,\n },\n },\n },\n )\n }\n break\n\n case 'bounce': {\n const bounceType = event.details.bounceType ?? 'hard'\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'bounced',\n bounceType,\n bounceReason: event.details.bounceReason ?? null,\n },\n },\n )\n }\n if (bounceType === 'hard') {\n await suppressOnce(ctx, event.email, 'hard_bounce', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n }\n {\n const dims = dimsFromSend(send)\n await recordHealthCounter(ctx, 'bounced', dims)\n await recordHealthCounter(ctx, bounceType === 'hard' ? 'hardBounced' : 'softBounced', dims)\n }\n break\n }\n\n case 'complaint':\n case 'spam_report':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { complainedAt: event.occurredAt, status: 'complained' } },\n )\n }\n await suppressOnce(ctx, event.email, 'complaint', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'complained', updatedAt: new Date() } },\n )\n await recordHealthCounter(ctx, 'complained', dimsFromSend(send))\n break\n\n case 'unsubscribe':\n if (send) {\n await ctx.collections.sends.updateOne({ _id: send._id }, { $set: { unsubscribedAt: event.occurredAt } })\n }\n await suppressOnce(ctx, event.email, 'unsubscribed', 'marketing')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n {\n $set: {\n status: 'unsubscribed',\n unsubscribedAt: event.occurredAt,\n unsubscribeReason: 'user_request',\n updatedAt: new Date(),\n },\n },\n )\n break\n }\n}\n\nasync function suppressOnce(\n ctx: RunnerContext,\n email: string,\n reason: 'hard_bounce' | 'complaint' | 'unsubscribed',\n scope: 'all' | 'marketing' | 'transactional',\n): Promise<void> {\n const normalized = email.toLowerCase()\n await ctx.collections.suppressions.updateOne(\n { email: normalized, scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope,\n reason,\n source: 'provider_webhook',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n}\n","/**\n * Predicate evaluator. Resolves all Predicate variants from `shared/types.ts`\n * against a Contact (host-side fields/tags) + mailer state (events, sends,\n * subscription).\n *\n * Network calls hit Mongo. Cache the Contact at the call site if you evaluate\n * many predicates in a row.\n */\n\nimport type { Contact, Predicate } from '../../shared/types.js'\nimport type { Collections, FlowRunDoc, SendDoc } from '../models/index.js'\n\nexport interface PredicateContext {\n contact: Contact\n run: FlowRunDoc\n collections: Collections\n now?: Date\n}\n\nconst BOT_UA_RE = /Mimecast|SafeLinks|proofpoint|HeadlessChrome|Googlebot|bingbot/i\n\nexport async function evaluatePredicate(\n predicate: Predicate,\n ctx: PredicateContext,\n): Promise<boolean> {\n const p = predicate as any\n\n if ('hasTag' in p) return ctx.contact.tags.includes(p.hasTag)\n if ('notHasTag' in p) return !ctx.contact.tags.includes(p.notHasTag)\n\n if ('fieldEquals' in p) {\n return ctx.contact.fields[p.fieldEquals.field] === p.fieldEquals.value\n }\n if ('fieldExists' in p) {\n return ctx.contact.fields[p.fieldExists] !== undefined\n }\n\n // Read from the run's own trigger event, NOT the contact — two concurrent\n // runs for the same person can legitimately disagree here.\n if ('triggerPropertyEquals' in p) {\n return (\n (ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyEquals.key] ===\n p.triggerPropertyEquals.value\n )\n }\n if ('triggerPropertyTruthy' in p) {\n return Boolean((ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyTruthy])\n }\n\n if ('subscriptionStatus' in p) {\n const sub = await ctx.collections.subscriptions.findOne({ externalId: ctx.contact.externalId })\n return sub?.status === p.subscriptionStatus\n }\n\n if ('hasFiredEvent' in p) {\n return hasEvent(ctx, p.hasFiredEvent, { sinceFlowStart: p.sinceFlowStart, withinDays: p.withinDays })\n }\n if ('notHasFiredEvent' in p) {\n return !(await hasEvent(ctx, p.notHasFiredEvent, { withinDays: p.withinDays }))\n }\n\n if ('hasOpened' in p) return await openOrClickCount(ctx, 'opened', p.hasOpened, false) > 0\n if ('hasClicked' in p) return await openOrClickCount(ctx, 'clicked', p.hasClicked, false) > 0\n if ('hasOpenedExcludingBots' in p) return await openOrClickCount(ctx, 'opened', p.hasOpenedExcludingBots, true) > 0\n if ('hasClickedExcludingBots' in p) return await openOrClickCount(ctx, 'clicked', p.hasClickedExcludingBots, true) > 0\n if ('openedAtLeastN' in p) return await openOrClickCount(ctx, 'opened', p.openedAtLeastN, true) >= p.openedAtLeastN.count\n if ('clickedAtLeastN' in p) return await openOrClickCount(ctx, 'clicked', p.clickedAtLeastN, true) >= p.clickedAtLeastN.count\n\n if ('all' in p) {\n for (const sub of p.all) {\n if (!(await evaluatePredicate(sub, ctx))) return false\n }\n return true\n }\n if ('any' in p) {\n for (const sub of p.any) {\n if (await evaluatePredicate(sub, ctx)) return true\n }\n return false\n }\n if ('not' in p) {\n return !(await evaluatePredicate(p.not, ctx))\n }\n\n return false\n}\n\nasync function hasEvent(\n ctx: PredicateContext,\n name: string,\n opts: { sinceFlowStart?: boolean; withinDays?: number },\n): Promise<boolean> {\n const filter: any = { externalId: ctx.contact.externalId, name }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter.occurredAt = { $gt: lower }\n const found = await ctx.collections.events.findOne(filter, { projection: { _id: 1 } })\n return !!found\n}\n\nasync function openOrClickCount(\n ctx: PredicateContext,\n kind: 'opened' | 'clicked',\n opts: { templateSlug?: string; sinceFlowStart?: boolean; withinDays?: number },\n excludeBots: boolean,\n): Promise<number> {\n const filter: any = { externalId: ctx.contact.externalId }\n if (opts.templateSlug) filter.templateSlug = opts.templateSlug\n if (kind === 'opened') filter.openedAt = { $ne: null }\n if (kind === 'clicked') filter.firstClickAt = { $ne: null }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter[kind === 'opened' ? 'openedAt' : 'firstClickAt'] = { $gt: lower }\n\n if (!excludeBots) {\n return await ctx.collections.sends.countDocuments(filter)\n }\n\n // Bot filter is best-effort: we only know UA for clicks (open pixel hits don't reliably carry one)\n const docs = await ctx.collections.sends.find(filter).limit(1000).toArray()\n let n = 0\n for (const s of docs) {\n if (kind === 'opened') {\n n++\n continue\n }\n const hasHumanClick = (s as SendDoc).clickedLinks?.some((c: any) => !c.userAgent || !BOT_UA_RE.test(c.userAgent))\n if (hasHumanClick) n++\n }\n return n\n}\n\nfunction effectiveLowerBound(ctx: PredicateContext, opts: { sinceFlowStart?: boolean; withinDays?: number }): Date | null {\n const now = ctx.now ?? new Date()\n if (opts.sinceFlowStart) return ctx.run.enteredAt\n if (opts.withinDays && opts.withinDays > 0) {\n return new Date(now.getTime() - opts.withinDays * 24 * 60 * 60 * 1000)\n }\n return null\n}\n","/**\n * Delivery-window math. Pure — no I/O, no Date.now(); callers pass `now`.\n *\n * Given the moment a send step becomes runnable, `computeDeliveryTime`\n * returns the earliest instant the email is allowed to go out. It only ever\n * moves forward: a send already inside its window returns `now` unchanged.\n *\n * Timezone handling uses the Intl API (no dependency). DST transitions are\n * resolved with a two-pass offset fix; the worst case during a transition is\n * being off by the shifted hour, which is fine for email delivery.\n */\n\nimport type { DeliveryWindow } from '../../shared/types.js'\n\n/**\n * Ticks fire with jitter, so a send arriving shortly AFTER its timeOfDay slot\n * still goes out rather than waiting a full day.\n */\nconst TIME_OF_DAY_GRACE_MS = 60 * 60_000\n\nexport function computeDeliveryTime(\n now: Date,\n window: DeliveryWindow,\n contactTimezone?: string,\n): Date {\n const tz = pickTimezone(window, contactTimezone)\n let candidate = now\n\n if (window.timeOfDay) {\n const [hh, mm] = window.timeOfDay.split(':').map(Number) as [number, number]\n const local = localParts(candidate, tz)\n const todaySlot = utcFromLocal(local.y, local.mo, local.d, hh, mm, tz)\n if (candidate.getTime() < todaySlot.getTime()) {\n candidate = todaySlot\n } else if (candidate.getTime() - todaySlot.getTime() > TIME_OF_DAY_GRACE_MS) {\n const next = addLocalDays(local, 1)\n candidate = utcFromLocal(next.y, next.mo, next.d, hh, mm, tz)\n }\n // else: within grace of today's slot — send now.\n }\n\n if (window.weekdaysOnly) {\n for (let guard = 0; guard < 3; guard++) {\n const local = localParts(candidate, tz)\n if (local.weekday !== 'Sat' && local.weekday !== 'Sun') break\n const shift = local.weekday === 'Sat' ? 2 : 1\n const moved = addLocalDays(local, shift)\n // Preserve the local clock time (timeOfDay slot, or the wall-clock\n // moment the step became runnable).\n candidate = utcFromLocal(moved.y, moved.mo, moved.d, local.hh, local.mi, tz)\n }\n }\n\n return candidate\n}\n\nfunction pickTimezone(window: DeliveryWindow, contactTimezone?: string): string {\n const candidates = [\n window.useContactTimezone ? contactTimezone : undefined,\n window.timezone,\n 'UTC',\n ]\n for (const tz of candidates) {\n if (tz && isValidTimezone(tz)) return tz\n }\n return 'UTC'\n}\n\nconst validatedZones = new Map<string, boolean>()\n\nfunction isValidTimezone(tz: string): boolean {\n const cached = validatedZones.get(tz)\n if (cached !== undefined) return cached\n let ok = true\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: tz })\n } catch {\n ok = false\n }\n validatedZones.set(tz, ok)\n return ok\n}\n\ninterface LocalParts {\n y: number\n mo: number\n d: number\n hh: number\n mi: number\n ss: number\n weekday: string // 'Mon'…'Sun'\n}\n\nconst partFormatters = new Map<string, Intl.DateTimeFormat>()\n\nfunction formatterFor(tz: string): Intl.DateTimeFormat {\n let f = partFormatters.get(tz)\n if (!f) {\n f = new Intl.DateTimeFormat('en-US', {\n timeZone: tz,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n weekday: 'short',\n hour12: false,\n })\n partFormatters.set(tz, f)\n }\n return f\n}\n\nfunction localParts(date: Date, tz: string): LocalParts {\n const parts: Record<string, string> = {}\n for (const p of formatterFor(tz).formatToParts(date)) parts[p.type] = p.value\n return {\n y: Number(parts.year),\n mo: Number(parts.month),\n d: Number(parts.day),\n hh: Number(parts.hour) % 24, // Intl emits '24' for midnight in some locales\n mi: Number(parts.minute),\n ss: Number(parts.second),\n weekday: parts.weekday!,\n }\n}\n\n/** UTC instant for a wall-clock time in `tz`. Two passes to converge across DST. */\nfunction utcFromLocal(y: number, mo: number, d: number, hh: number, mi: number, tz: string): Date {\n let ts = Date.UTC(y, mo - 1, d, hh, mi, 0)\n for (let i = 0; i < 2; i++) {\n const p = localParts(new Date(ts), tz)\n const asUtc = Date.UTC(p.y, p.mo - 1, p.d, p.hh, p.mi, p.ss)\n const offset = asUtc - ts\n ts = Date.UTC(y, mo - 1, d, hh, mi, 0) - offset\n }\n return new Date(ts)\n}\n\n/** Add days to a local calendar date (normalizes month/year rollover). */\nfunction addLocalDays(p: LocalParts, days: number): { y: number; mo: number; d: number } {\n const dt = new Date(Date.UTC(p.y, p.mo - 1, p.d + days))\n return { y: dt.getUTCFullYear(), mo: dt.getUTCMonth() + 1, d: dt.getUTCDate() }\n}\n","/**\n * Template render pipeline.\n *\n * authorMjml + handlebarsContext\n * ↓ Handlebars render → MJML with substituted vars\n * ↓ mjml-core compile → HTML\n * ↓ html-to-text derive → plain text alternative\n * ↓ applyTracking(sendId) → tracked HTML with rewritten links + open pixel\n *\n * Subject and preheader run through Handlebars too. Plain text is auto-derived\n * unless the template explicitly overrides it.\n */\n\nimport crypto from 'node:crypto'\nimport Handlebars from 'handlebars'\nimport { convert as htmlToText } from 'html-to-text'\nimport mjml2html from 'mjml'\n\nimport type { Contact } from '../../shared/types.js'\nimport type { TemplateDoc } from '../models/index.js'\n\n// ---------------------------------------------------------------------------\n// Compile (publish-time)\n// ---------------------------------------------------------------------------\n\nexport interface CompileResult {\n html: string\n plainText: string\n errors: Array<{ line?: number; message: string; tagName?: string; formattedMessage?: string }>\n}\n\n/** Compile MJML → HTML, then derive plain text. Called at template publish time. */\nexport async function compileTemplate(mjml: string): Promise<CompileResult> {\n const out = await mjml2html(mjml, { validationLevel: 'soft', minify: false })\n const plainText = derivePlaintext(out.html)\n return { html: out.html, plainText, errors: out.errors ?? [] }\n}\n\n/**\n * Compile Maily editor JSON (Tiptap-shape) → HTML via `@maily-to/render`, then\n * derive plain text. Called at template publish time when the template was\n * authored via the WYSIWYG editor.\n */\nexport async function compileMailyTemplate(content: unknown): Promise<CompileResult> {\n const { render } = await import('@maily-to/render')\n const html = await render(content as any)\n const plainText = derivePlaintext(html)\n return { html, plainText, errors: [] }\n}\n\n/** Auto-derive plain text from compiled HTML. */\nexport function derivePlaintext(html: string): string {\n return htmlToText(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'img', format: 'skip' },\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n ],\n }).trim()\n}\n\n// ---------------------------------------------------------------------------\n// Render (send-time)\n// ---------------------------------------------------------------------------\n\nexport interface RenderContext {\n /**\n * Host-resolved variables (varsAdapter) live at the context root, so a\n * schema key `user` renders as `{{user.name}}`. Reserved keys below always\n * win over resolved keys.\n */\n [resolvedVar: string]: unknown\n contact: Contact\n vars: Record<string, unknown>\n /** Properties of the event that triggered the flow run ({{event.*}}). Empty outside flow sends. */\n event?: Record<string, unknown>\n /** URL the recipient hits to one-click unsubscribe. */\n unsubscribeUrl: string\n /** URL to view this email in a browser (when implemented). */\n viewInBrowserUrl?: string\n /** URL for the preference center (when implemented). */\n preferenceCenterUrl?: string\n /** Configured sender postal address (CAN-SPAM). */\n senderAddress?: string\n}\n\nexport interface RenderedTemplate {\n subject: string\n preheader: string\n html: string\n plainText: string\n fromName: string\n fromEmail: string\n replyTo: string | null\n}\n\nexport interface RenderOptions {\n /** Extra Handlebars helpers contributed by the host. */\n helpers?: Record<string, Handlebars.HelperDelegate>\n}\n\n/**\n * Render a published template against a contact + vars context. Returns the\n * substituted subject/preheader/html/plainText. Tracking is NOT applied here —\n * that step needs the send id and runs separately via `applyTracking`.\n */\nexport async function renderTemplate(\n template: TemplateDoc,\n ctx: RenderContext,\n opts: RenderOptions = {},\n): Promise<RenderedTemplate> {\n const hb = makeHandlebars(opts.helpers)\n\n const subject = hb.compile(template.subject)(ctx)\n const preheader = hb.compile(template.preheader)(ctx)\n\n // Prefer the compiled HTML if present; fall back to compiling MJML on the fly.\n let html: string\n if (template.body.html) {\n html = hb.compile(template.body.html)(ctx)\n } else {\n const compiled = await compileTemplate(template.body.mjml)\n html = hb.compile(compiled.html)(ctx)\n }\n\n const plainText = template.body.plainText\n ? hb.compile(template.body.plainText)(ctx)\n : derivePlaintext(html)\n\n return {\n subject,\n preheader,\n html,\n plainText,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n replyTo: template.replyTo,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tracking application\n// ---------------------------------------------------------------------------\n\nexport interface TrackingOptions {\n sendId: string\n publicUrl: string\n trackOpens: boolean\n trackClicks: boolean\n /** URL that must NOT be rewritten (e.g. the resolved unsubscribe URL). */\n preserveUrls?: string[]\n}\n\nexport interface TrackingResult {\n html: string\n /** linkId → original URL map; persist on `mailer_sends.links` for click resolution. */\n links: Array<{ linkId: string; url: string }>\n}\n\n/**\n * Rewrite `<a href>` in `html` to /m/click/<sendId>/<linkId>?... and append an\n * open pixel. Returns the modified HTML plus the link map to persist on the\n * send document.\n */\nexport function applyTracking(html: string, opts: TrackingOptions): TrackingResult {\n const preserve = new Set((opts.preserveUrls ?? []).map((u) => u.trim()))\n const links: Array<{ linkId: string; url: string }> = []\n const seen = new Map<string, string>() // url → linkId\n\n let out = html\n\n if (opts.trackClicks) {\n out = out.replace(/<a\\b([^>]*?)\\bhref=([\"'])([^\"']+)\\2([^>]*)>/gi, (full, pre, _q, rawUrl, post) => {\n // Handlebars `{{ }}` escapes substituted URLs (& → &, = → =). That is\n // correct in HTML source, but the stored/redirect URL must be the decoded one.\n const url = decodeHtmlEntities(rawUrl)\n if (shouldSkipClickRewrite(url, preserve, full)) return full\n let linkId = seen.get(url)\n if (!linkId) {\n linkId = shortHash(`${opts.sendId}:${url}:${links.length}`)\n seen.set(url, linkId)\n links.push({ linkId, url })\n }\n const newHref = `${opts.publicUrl}/m/click/${opts.sendId}/${linkId}`\n return `<a${pre}href=\"${newHref}\"${post}>`\n })\n }\n\n if (opts.trackOpens) {\n const pixel = `<img src=\"${opts.publicUrl}/m/open/${opts.sendId}.png\" width=\"1\" height=\"1\" alt=\"\" style=\"display:block;border:0\" />`\n if (/<\\/body>/i.test(out)) {\n out = out.replace(/<\\/body>/i, `${pixel}</body>`)\n } else {\n out = out + pixel\n }\n }\n\n return { html: out, links }\n}\n\nfunction shouldSkipClickRewrite(url: string, preserve: Set<string>, fullTag: string): boolean {\n if (!url) return true\n if (url.startsWith('mailto:')) return true\n if (url.startsWith('tel:')) return true\n if (url.startsWith('#')) return true\n if (url.startsWith('{{') || url.startsWith('{')) return true // unrendered handlebars\n if (preserve.has(url.trim())) return true\n if (/data-mailer-notrack=[\"']true[\"']/.test(fullTag)) return true\n return false\n}\n\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n}\n\n/**\n * Decode the HTML entities Handlebars' escapeExpression emits (plus numeric\n * forms), so a captured href round-trips to the URL the browser would request.\n * `&` is decoded last-wins via a single pass so `&lt;` stays `<`.\n */\nfunction decodeHtmlEntities(input: string): string {\n return input.replace(/&(#x[0-9a-f]+|#\\d+|[a-z][a-z0-9]*);/gi, (match, body: string) => {\n if (body[0] === '#') {\n const code =\n body[1] === 'x' || body[1] === 'X'\n ? parseInt(body.slice(2), 16)\n : parseInt(body.slice(1), 10)\n if (!Number.isFinite(code) || code < 0 || code > 0x10ffff) return match\n try {\n return String.fromCodePoint(code)\n } catch {\n return match\n }\n }\n const named = NAMED_ENTITIES[body.toLowerCase()]\n return named ?? match\n })\n}\n\nfunction shortHash(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex').slice(0, 12)\n}\n\n// ---------------------------------------------------------------------------\n// Handlebars instance + helpers\n// ---------------------------------------------------------------------------\n\nfunction makeHandlebars(extra?: Record<string, Handlebars.HelperDelegate>): typeof Handlebars {\n const hb = Handlebars.create()\n\n hb.registerHelper('eq', (a: unknown, b: unknown) => a === b)\n hb.registerHelper('ne', (a: unknown, b: unknown) => a !== b)\n hb.registerHelper('gt', (a: any, b: any) => a > b)\n hb.registerHelper('lt', (a: any, b: any) => a < b)\n hb.registerHelper('gte', (a: any, b: any) => a >= b)\n hb.registerHelper('lte', (a: any, b: any) => a <= b)\n hb.registerHelper('and', (...args: any[]) => args.slice(0, -1).every(Boolean))\n hb.registerHelper('or', (...args: any[]) => args.slice(0, -1).some(Boolean))\n hb.registerHelper('not', (a: unknown) => !a)\n\n hb.registerHelper('formatDate', (value: unknown, fmt?: string) => {\n if (!value) return ''\n const d = value instanceof Date ? value : new Date(String(value))\n if (Number.isNaN(d.getTime())) return ''\n if (fmt === 'long') return d.toLocaleDateString('en-US', { dateStyle: 'long' })\n if (fmt === 'short') return d.toLocaleDateString('en-US', { dateStyle: 'short' })\n return d.toISOString().slice(0, 10)\n })\n\n hb.registerHelper('formatNumber', (n: unknown) => {\n const v = Number(n)\n return Number.isFinite(v) ? v.toLocaleString('en-US') : ''\n })\n\n hb.registerHelper('formatCurrency', (cents: unknown, currency: string = 'usd') => {\n const v = Number(cents)\n if (!Number.isFinite(v)) return ''\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(v / 100)\n })\n\n hb.registerHelper('pluralize', (n: unknown, one: string, many: string) =>\n Number(n) === 1 ? one : many,\n )\n\n if (extra) {\n for (const [name, fn] of Object.entries(extra)) {\n hb.registerHelper(name, fn)\n }\n }\n\n return hb\n}\n\nexport { makeHandlebars }\n","/**\n * Send pipeline. `handleSend` is called by the runner state machine; it creates\n * the Send document and enqueues a mailer:send job. `dispatchSend` is the\n * worker — re-checks suppression + circuit breaker, applies tracking, calls\n * the provider, updates the Send row.\n */\n\nimport crypto from 'node:crypto'\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport {\n applyTracking,\n renderTemplate,\n type RenderContext,\n} from '../templates/render.js'\nimport { signUnsubscribeToken } from '../tokens.js'\nimport { resolveVars } from '../adapters/vars.js'\nimport { isSuppressed } from './suppression.js'\nimport { advanceStep, failFlowRun } from './step.js'\nimport { getBucketStatus, recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function handleSend(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'send' }>,\n contact: Contact,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: step.templateSlug })\n if (!template) {\n await failFlowRun(run, `template not found: ${step.templateSlug}`, ctx)\n return\n }\n\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}`\n\n // Idempotency: has this exact step already produced a send?\n const existing = await ctx.collections.sends.findOne({ dedupeKey })\n if (existing) {\n await advanceStep(run, ctx, {\n action: 'sent',\n details: { dedupeKey, alreadySent: true, sendId: String(existing._id) },\n })\n return\n }\n\n const providerName = pickProviderName(step.providerOverride, template, ctx)\n\n // Render now (with fresh contact + vars). Tracking application happens in\n // dispatchSend once we have the persisted sendId.\n const renderCtx = buildRenderContext(contact, run, step.vars ?? {}, ctx)\n let rendered\n try {\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await ctx.collections.sends.insertOne(\n newSendDoc({\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: template.subject,\n bodyHash: '',\n status: 'failed',\n errorMessage: `render error: ${err?.message ?? err}`,\n }),\n )\n await advanceStep(run, ctx, {\n action: 'send_skipped',\n details: { reason: 'render_error', message: String(err?.message ?? err) },\n })\n return\n }\n\n const sendId = new ObjectId()\n await ctx.collections.sends.insertOne(\n newSendDoc({\n _id: sendId,\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: rendered.subject,\n bodyHash: sha256(rendered.html),\n status: 'queued',\n renderedFrom: rendered.fromName ? { name: rendered.fromName, email: rendered.fromEmail } : undefined,\n vars: step.vars ?? {},\n }),\n )\n\n await ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: ctx.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n await advanceStep(run, ctx, { action: 'sent', details: { dedupeKey, sendId: String(sendId) } })\n}\n\n// ---------------------------------------------------------------------------\n// Send worker entry point\n// ---------------------------------------------------------------------------\n\nexport async function dispatchSend(sendId: ObjectId, ctx: RunnerContext): Promise<void> {\n // Atomic claim: flip queued/failed → sending so exactly one worker proceeds.\n // The stranded-send sweep and the queue's stalled-job retry can both fire a\n // job for the same send; a read-then-act status check lets both through and\n // the recipient gets the email twice. Every downstream path writes a\n // terminal status (or resets to 'queued' for the breaker retry); a crash\n // leaves 'sending', which the stranded-send sweep resets after 5 minutes.\n const send = await ctx.collections.sends.findOneAndUpdate(\n { _id: sendId, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'sending', updatedAt: new Date() } },\n )\n if (!send) return // already claimed / dispatched / cancelled\n\n const template = await ctx.collections.templates.findOne({ _id: send.templateId })\n if (!template) {\n await markFailed(send._id!, 'template_missing', ctx)\n return\n }\n\n // 1. Suppression check (INVARIANT 3: always re-checked at send time).\n const supp = await isSuppressed(ctx.collections, send.emailAtSend, send.kind)\n if (supp.suppressed) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'suppressed', errorMessage: `suppressed: ${supp.reason}` } },\n )\n return\n }\n\n // 2. Circuit-breaker check (only blocks marketing). The breaker is scoped\n // per (senderDomain, kind) bucket — one bad subdomain doesn't hold mail for\n // the others.\n if (send.kind === 'marketing') {\n const bucket = await getBucketStatus(ctx, send.fromEmail, send.kind)\n if (bucket?.status === 'tripped') {\n // Release the claim so the delayed retry can re-claim it.\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n await ctx.queues.send.add('send', { sendId: String(send._id) }, { delay: 60_000 })\n return\n }\n }\n\n // 3. Pull the contact + re-render (use the contact that exists now, not at flow entry).\n const contact = await ctx.adapter.getById(send.externalId)\n if (!contact) {\n await markFailed(send._id!, 'contact_missing', ctx)\n return\n }\n\n const run = send.flowRunId ? await ctx.collections.flowRuns.findOne({ _id: send.flowRunId }) : null\n\n // Aborted-run guard: closes the race where a send is enqueued between the\n // abort's send-cancellation sweep and dispatch. Only host aborts block here —\n // completed/naturally-exited runs may still have legitimately queued mail.\n if (run && run.status === 'exited' && run.exitReason?.startsWith('aborted_by_host')) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${run.exitReason}`, updatedAt: new Date() } },\n )\n return\n }\n\n // Resolve host vars + render. A throw here (host DB hiccup, bad template)\n // marks the send failed and rethrows so the queue retries with backoff —\n // never dispatch a half-rendered email.\n let renderCtx: RenderContext\n let rendered: Awaited<ReturnType<typeof renderTemplate>>\n try {\n const resolved = await resolveVars(ctx.varsAdapter, contact, {\n reason: 'send',\n templateSlug: template.slug,\n flowSlug: run?.flowSlug,\n eventName: run?.triggerEvent?.name,\n eventProperties: run?.triggerEvent?.properties,\n })\n renderCtx = buildRenderContext(contact, run, send.vars ?? {}, ctx, resolved)\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await markFailed(send._id!, `render error: ${String(err?.message ?? err)}`, ctx)\n throw err // let the queue retry per the attempts policy\n }\n\n // 4. Apply tracking using the now-known send id.\n const tracking = applyTracking(rendered.html, {\n sendId: String(send._id),\n publicUrl: ctx.config.publicUrl,\n trackOpens: template.trackOpens ?? ctx.config.trackOpens,\n trackClicks: template.trackClicks ?? ctx.config.trackClicks,\n preserveUrls: [renderCtx.unsubscribeUrl],\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n links: tracking.links,\n bodyHash: sha256(tracking.html),\n status: 'sending',\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: rendered.subject,\n updatedAt: new Date(),\n },\n },\n )\n\n // 5. Provider dispatch.\n const provider = ctx.providers[send.provider] ?? ctx.providers[ctx.config.defaultProvider]\n if (!provider) {\n await markFailed(send._id!, `provider_unknown: ${send.provider}`, ctx)\n return\n }\n\n // List-Unsubscribe belongs on bulk mail only. The unsubscribe token is\n // scoped 'marketing', so advertising one-click unsub on a password reset\n // both misrepresents the header and offers an opt-out that wouldn't stop\n // the transactional mail the recipient is looking at.\n const headers: Record<string, string> =\n send.kind === 'marketing'\n ? {\n 'List-Unsubscribe': `<${renderCtx.unsubscribeUrl}>`,\n 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',\n }\n : {}\n\n try {\n const result = await provider.send({\n to: send.emailAtSend,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n replyTo: rendered.replyTo ?? undefined,\n subject: rendered.subject,\n html: tracking.html,\n text: rendered.plainText,\n headers,\n messageMeta: { sendId: String(send._id) },\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'sent',\n sentAt: new Date(),\n providerMessageId: result.providerId,\n },\n },\n )\n // Use send.fromEmail (same field getBucketStatus reads) so the breaker\n // gate and the counter record into the same bucket even if a\n // hypothetical render-time fromDefaults swap ever lands.\n await recordHealthCounter(ctx, 'sent', { fromEmail: send.fromEmail, kind: send.kind })\n } catch (err: any) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'failed', errorMessage: String(err?.message ?? err) } },\n )\n await recordHealthCounter(ctx, 'failedToSend', { fromEmail: send.fromEmail, kind: send.kind })\n if (ctx.config.onSendFailure) {\n try {\n await ctx.config.onSendFailure({ send, error: err })\n } catch {\n /* swallow */\n }\n }\n throw err // let BullMQ retry per the attempts policy\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction pickProviderName(stepOverride: string | undefined, tpl: TemplateDoc, ctx: RunnerContext): string {\n if (stepOverride) return stepOverride\n if (tpl.providerOverride) return tpl.providerOverride\n if (tpl.kind === 'transactional' && ctx.config.defaultTransactionalProvider) {\n return ctx.config.defaultTransactionalProvider\n }\n return ctx.config.defaultProvider\n}\n\nfunction buildRenderContext(\n contact: Contact,\n run: FlowRunDoc | null,\n vars: Record<string, unknown>,\n ctx: RunnerContext,\n resolved: Record<string, unknown> = {},\n): RenderContext {\n const scope = 'marketing'\n const expiresAt = new Date(Date.now() + ctx.config.unsubscribeTokenLifetimeDays * 24 * 60 * 60 * 1000)\n const token = signUnsubscribeToken(\n { email: contact.email, scope, expiresAt },\n ctx.config.unsubscribeSecret,\n )\n const unsubscribeUrl = `${ctx.config.publicUrl}/m/unsub/${token}`\n\n return {\n ...resolved,\n contact,\n vars,\n event: run?.triggerEvent?.properties ?? {},\n unsubscribeUrl,\n senderAddress: ctx.config.senderAddress,\n }\n}\n\ninterface NewSendInput {\n _id?: ObjectId\n dedupeKey: string\n run: FlowRunDoc\n contact: Contact\n template: TemplateDoc\n flow: FlowDoc\n providerName: string\n renderedSubject: string\n bodyHash: string\n status: SendDoc['status']\n errorMessage?: string\n renderedFrom?: { name: string; email: string }\n vars?: Record<string, unknown>\n}\n\nfunction newSendDoc(input: NewSendInput): SendDoc {\n const now = new Date()\n return {\n _id: input._id,\n dedupeKey: input.dedupeKey,\n externalId: input.run.externalId,\n emailAtSend: input.contact.email,\n templateId: input.template._id!,\n templateSlug: input.template.slug,\n flowRunId: input.run._id!,\n broadcastId: null,\n manualSendBy: null,\n kind: input.template.kind,\n provider: input.providerName,\n providerMessageId: null,\n fromName: input.renderedFrom?.name ?? input.template.fromName,\n fromEmail: input.renderedFrom?.email ?? input.template.fromEmail,\n subject: input.renderedSubject,\n bodyHash: input.bodyHash,\n status: input.status,\n errorMessage: input.errorMessage ?? null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: input.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: now,\n updatedAt: now,\n sentAt: null,\n deliveredAt: null,\n }\n}\n\nasync function markFailed(sendId: ObjectId, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.sends.updateOne(\n { _id: sendId },\n { $set: { status: 'failed', errorMessage: reason } },\n )\n}\n\nfunction sha256(s: string): string {\n return crypto.createHash('sha256').update(s).digest('hex')\n}\n","/**\n * Suppression checks. INVARIANT 3: re-checked at send time, never trusted\n * from enqueue time. INVARIANT 9: hashed-suppression records (GDPR forget)\n * block sends without retaining the plaintext email.\n */\n\nimport type { Collections } from '../models/index.js'\nimport type { SuppressionScope, TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\n\nexport interface SuppressionResult {\n suppressed: boolean\n scope?: string\n reason?: string\n}\n\nconst SCOPES_BY_KIND: Record<TemplateKind, SuppressionScope[]> = {\n marketing: ['all', 'marketing'],\n transactional: ['all', 'transactional'],\n}\n\nexport async function isSuppressed(\n collections: Collections,\n email: string,\n kind: TemplateKind,\n): Promise<SuppressionResult> {\n const normalized = email.toLowerCase()\n const allowed = SCOPES_BY_KIND[kind]\n\n const byEmail = await collections.suppressions.findOne({\n email: normalized,\n scope: { $in: allowed },\n $or: [{ expiresAt: null }, { expiresAt: { $gt: new Date() } }],\n })\n if (byEmail) return { suppressed: true, scope: byEmail.scope, reason: byEmail.reason }\n\n const hashed = await collections.suppressions.findOne({\n emailHash: sha256Hex(normalized),\n scope: { $in: allowed },\n })\n if (hashed) return { suppressed: true, scope: hashed.scope, reason: hashed.reason }\n\n return { suppressed: false }\n}\n","/**\n * Flow_run state machine. One step transition per `processOneRunStep` call.\n * Idempotent — optimistic concurrency on `currentStepIndex` means two workers\n * racing on the same run advance exactly once.\n */\n\nimport type { ObjectId } from 'mongodb'\n\nimport type { FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc } from '../models/index.js'\nimport { evaluatePredicate } from './predicate.js'\nimport type { RunnerContext } from './index.js'\nimport { computeDeliveryTime } from './delivery-window.js'\nimport { handleSend } from './send.js'\n\nexport async function processOneRunStep(runId: ObjectId, ctx: RunnerContext): Promise<void> {\n const run = await ctx.collections.flowRuns.findOne({ _id: runId })\n if (!run || run.status !== 'active') return\n\n const flow = await ctx.collections.flows.findOne({ _id: run.flowId })\n if (!flow) {\n await failFlowRun(run, 'flow_missing', ctx)\n return\n }\n\n const steps = await loadStepsForRun(run, flow, ctx)\n const step = locateStep(steps, run.currentStepIndex, run.currentBranchPath)\n if (!step) {\n await completeFlowRun(run, 'completed', ctx)\n return\n }\n\n const contact = await ctx.adapter.getById(run.externalId)\n if (!contact) {\n await exitFlowRun(run, 'contact_missing', ctx)\n return\n }\n\n // Subscription gate: flows are marketing-scope. Any non-subscribed status\n // exits the run before the next step, regardless of template kind — there is\n // deliberately no transactional bypass here. Transactional mail that must\n // reach not-subscribed contacts (receipts, password resets) goes through\n // sendOneOff, not a flow. Entry is gated the same way in triggers.ts.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: run.externalId })\n if (sub && sub.status !== 'subscribed') {\n await exitFlowRun(run, sub.status, ctx)\n return\n }\n\n switch (step.type) {\n case 'wait':\n return handleWait(run, step, ctx)\n case 'condition':\n return handleCondition(run, step, contact, ctx)\n case 'branch':\n return handleBranch(run, step, contact, ctx)\n case 'send': {\n // Delivery window: push the send to the next allowed slot (weekday /\n // time-of-day, optionally in the contact's timezone) before rendering.\n if (step.delivery) {\n const deliverAt = computeDeliveryTime(new Date(), step.delivery, contact.timezone)\n if (deliverAt.getTime() > Date.now() + 30_000) {\n return deferSendForWindow(run, deliverAt, ctx)\n }\n }\n return handleSend(run, step, contact, flow, ctx)\n }\n case 'tag':\n return handleTag(run, step, ctx)\n case 'fire_event':\n return handleFireEvent(run, step, ctx)\n case 'webhook':\n return handleWebhookStep(run, step, ctx)\n case 'exit':\n return exitFlowRun(run, step.reason ?? 'exit_step', ctx)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Step handlers\n// ---------------------------------------------------------------------------\n\nasync function handleWait(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'wait' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const ms = unitToMs(step.value, step.unit)\n const nextAt = new Date(Date.now() + ms)\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: nextAt, attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: 1 },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'wait_started',\n at: new Date(),\n details: { until: nextAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return // another worker advanced; their job will fire.\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: ms, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex + 1}` },\n )\n}\n\nasync function handleCondition(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'condition' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections })\n\n if (result) {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: true } })\n return\n }\n if (step.ifFalse === 'continue') {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: false, skipped: 1 } }, { stepInc: 2 })\n return\n }\n await exitFlowRun(run, 'condition_false', ctx)\n}\n\nasync function handleBranch(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'branch' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections })\n const newPath = [...run.currentBranchPath, run.currentStepIndex, result ? 'true' : 'false', 0] as Array<number | 'true' | 'false'>\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: {\n currentBranchPath: newPath,\n currentStepIndex: 0,\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n updatedAt: new Date(),\n },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'branch_taken',\n at: new Date(),\n details: { result },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nasync function handleTag(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'tag' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const adds = step.addTags ?? []\n const removes = step.removeTags ?? []\n\n if (ctx.adapter.addTags && adds.length > 0) {\n await ctx.adapter.addTags(run.externalId, adds)\n } else if (adds.length > 0) {\n await ctx.collections.contactTags.bulkWrite(\n adds.map((tag) => ({\n updateOne: {\n filter: { externalId: run.externalId, tag },\n update: { $setOnInsert: { externalId: run.externalId, tag, appliedBy: 'flow', appliedAt: new Date() } },\n upsert: true,\n },\n })),\n )\n }\n\n if (ctx.adapter.removeTags && removes.length > 0) {\n await ctx.adapter.removeTags(run.externalId, removes)\n } else if (removes.length > 0) {\n await ctx.collections.contactTags.deleteMany({ externalId: run.externalId, tag: { $in: removes } })\n }\n\n await advanceStep(run, ctx, { action: 'tagged', details: { addTags: adds, removeTags: removes } })\n}\n\nasync function handleFireEvent(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'fire_event' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}:${step.eventName}`\n try {\n await ctx.collections.events.insertOne({\n externalId: run.externalId,\n name: step.eventName,\n // Inherit the triggering event's properties so a handoff carries the\n // context that identifies what the run is ABOUT (which account, order,\n // subscription, ...). A step's `properties` are static — authored once in\n // the flow definition — so without this a fired event can only ever say\n // \"this contact\", losing the scope the originating event supplied, and\n // the receiving flow has nothing to resolve variables against. Explicit\n // step.properties win on conflict.\n properties: { ...(run.triggerEvent?.properties ?? {}), ...(step.properties ?? {}) },\n dedupeKey,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n await advanceStep(run, ctx, { action: 'event_fired', details: { name: step.eventName } })\n}\n\nasync function handleWebhookStep(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'webhook' }>,\n ctx: RunnerContext,\n): Promise<void> {\n try {\n const res = await fetch(step.url, {\n method: step.method ?? 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(step.payload ?? { externalId: run.externalId, flowRunId: String(run._id) }),\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) throw new Error(`webhook step returned ${res.status}`)\n await advanceStep(run, ctx, { action: 'webhook_called', details: { url: step.url, status: res.status } })\n } catch (err: any) {\n const attempts = (run.attemptsForCurrentStep ?? 0) + 1\n if (attempts >= ctx.config.webhookRetryAttempts) {\n if (step.failureMode === 'fail_run') {\n await failFlowRun(run, `webhook failed: ${err?.message}`, ctx)\n } else {\n // Soft fail — log and advance.\n await advanceStep(run, ctx, {\n action: 'webhook_called',\n details: { url: step.url, error: err?.message, exhausted: true },\n })\n }\n } else {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n { $inc: { attemptsForCurrentStep: 1 }, $set: { nextActionAt: new Date(Date.now() + 60_000) } },\n )\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: 60_000, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:retry-${attempts}` },\n )\n }\n }\n}\n\n/**\n * Park the run on the SAME step until the delivery window opens, then let the\n * normal advance job re-enter processOneRunStep — at which point the window\n * check passes and handleSend runs. Idempotent via the jobId (one defer job\n * per step per slot) and the nextActionAt guard.\n */\nasync function deferSendForWindow(run: FlowRunDoc, deliverAt: Date, ctx: RunnerContext): Promise<void> {\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n // Only write once per deferral — if nextActionAt already points at (or\n // past) the slot, another worker/tick got here first.\n { _id: run._id, currentStepIndex: run.currentStepIndex, nextActionAt: { $lt: deliverAt } },\n {\n $set: { nextActionAt: deliverAt, updatedAt: new Date() },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'send_deferred' as const,\n at: new Date(),\n details: { until: deliverAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n {\n delay: Math.max(0, deliverAt.getTime() - Date.now()),\n jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:window:${deliverAt.getTime()}`,\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Common helpers\n// ---------------------------------------------------------------------------\n\nexport interface AdvanceOptions {\n stepInc?: number\n}\n\nexport interface AdvanceLog {\n action: FlowRunDoc['history'][number]['action']\n details?: Record<string, unknown>\n}\n\nexport async function advanceStep(\n run: FlowRunDoc,\n ctx: RunnerContext,\n log: AdvanceLog,\n opts: AdvanceOptions = {},\n): Promise<void> {\n const stepInc = opts.stepInc ?? 1\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: new Date(), attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: stepInc },\n $push: {\n history: { stepIndex: run.currentStepIndex, action: log.action, at: new Date(), details: log.details },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nexport async function exitFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'exited', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'exited', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function completeFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'completed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n },\n )\n}\n\nexport async function failFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'failed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'failed', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function loadStepsForRun(\n run: FlowRunDoc,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<FlowStep[]> {\n if (run.flowVersion === flow.version) return flow.steps\n const snapshot = await ctx.collections.flowVersions.findOne({ flowId: run.flowId, version: run.flowVersion })\n return snapshot?.steps ?? flow.steps\n}\n\n/**\n * Walk a branch path through nested branch steps to find the active step.\n * Branch path layout: [parentStepIndex, 'true'|'false', childStepIndex, ...repeat]\n */\nexport function locateStep(\n steps: FlowStep[],\n currentStepIndex: number,\n branchPath: ReadonlyArray<number | 'true' | 'false'>,\n): FlowStep | null {\n let arr: FlowStep[] = steps\n\n for (let i = 0; i < branchPath.length; i += 3) {\n const parentIndex = branchPath[i] as number\n const branchKey = branchPath[i + 1] as 'true' | 'false'\n const parent = arr[parentIndex]\n if (!parent || parent.type !== 'branch') return null\n arr = branchKey === 'true' ? parent.ifTrueSteps : parent.ifFalseSteps\n }\n\n return arr[currentStepIndex] ?? null\n}\n\n/**\n * Branch-path discriminator for advance jobIds. `currentStepIndex` resets to 0\n * on branch entry, so (runId, stepIndex) alone is not unique across a run's\n * lifetime — the same numeric index recurs inside each branch arm.\n */\nfunction branchKey(run: FlowRunDoc): string {\n return run.currentBranchPath.join('_')\n}\n\nfunction unitToMs(value: number, unit: 'minutes' | 'hours' | 'days' | 'weeks'): number {\n const m = 60_000\n switch (unit) {\n case 'minutes':\n return value * m\n case 'hours':\n return value * 60 * m\n case 'days':\n return value * 24 * 60 * m\n case 'weeks':\n return value * 7 * 24 * 60 * m\n }\n}\n","/**\n * Recovery sweep: finds active flow_runs whose `nextActionAt` has passed but\n * weren't woken by their delayed `mailer:advance` job (worker restart, BullMQ\n * data loss). Processes each one inline.\n */\n\nimport { processOneRunStep } from './step.js'\nimport type { RunnerContext } from './index.js'\n\nconst SWEEP_LIMIT = 500\n\nexport async function sweepStrandedFlowRuns(ctx: RunnerContext): Promise<void> {\n const runs = await ctx.collections.flowRuns\n .find({ status: 'active', nextActionAt: { $lte: new Date() } })\n .sort({ nextActionAt: 1 })\n .limit(SWEEP_LIMIT)\n .toArray()\n\n for (const run of runs) {\n try {\n await processOneRunStep(run._id!, ctx)\n } catch (err) {\n console.error('mailery: sweep advance failed', { runId: String(run._id), err })\n }\n }\n}\n","/**\n * Broadcast dispatch. Picks up scheduled broadcasts whose `scheduledAt` has\n * passed, streams the segment via the adapter cursor + mailer-side post-filter,\n * and bulk-enqueues Send docs + jobs. Per-provider rate limiting + bounded\n * enqueue (pause when waitingCount > broadcastEnqueueMaxWaiting).\n */\n\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, SegmentDefinition, SegmentFilter, AdapterFilter } from '../../shared/types.js'\nimport type { BroadcastDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport { isSuppressed } from './suppression.js'\nimport { sha256Hex } from '../tokens.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Broadcasts stuck in 'sending' with updatedAt older than this are assumed\n * dead (worker crashed mid-dispatch). dispatchBroadcast heartbeats updatedAt\n * on every page, so a stale timestamp means no live dispatcher.\n */\nconst STALLED_BROADCAST_THRESHOLD_MS = 10 * 60 * 1000\n\n/**\n * Process scheduled broadcasts whose `scheduledAt` has passed. Called from the\n * tick. Marks each broadcast `sending` before dispatch so concurrent ticks\n * don't double-dispatch.\n */\nexport async function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n const now = new Date()\n const due = await ctx.collections.broadcasts\n .find({ status: 'scheduled', scheduledAt: { $lte: now } })\n .toArray()\n\n for (const b of due) {\n // Optimistic claim — only one worker takes this broadcast.\n const claimed = await ctx.collections.broadcasts.findOneAndUpdate(\n { _id: b._id, status: 'scheduled' },\n { $set: { status: 'sending', startedAt: now, updatedAt: now } },\n { returnDocument: 'after' },\n )\n if (!claimed) continue\n await startBroadcastDispatch(claimed, ctx)\n }\n}\n\n/**\n * Hand the (potentially hours-long) recipient enqueue off the tick. With a\n * real queue driver, dispatch runs as an advance job so a large broadcast\n * can't starve trigger scans and sweeps — the tick worker has concurrency 1.\n * The noop driver has no workers (hosts drive the runner synchronously), so\n * dispatch stays inline there.\n */\nasync function startBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n if (ctx.config.queue.driver === 'noop') {\n await runBroadcastDispatch(broadcast, ctx)\n return\n }\n await ctx.queues.advance.add(\n 'advance',\n { broadcastId: String(broadcast._id) },\n {\n attempts: 3,\n backoff: { type: 'exponential', delay: 60_000 },\n jobId: `broadcast-dispatch:${broadcast._id}`,\n },\n )\n}\n\n/** Advance-worker entry point for `{ broadcastId }` jobs. */\nexport async function dispatchBroadcastById(broadcastId: ObjectId, ctx: RunnerContext): Promise<void> {\n const broadcast = await ctx.collections.broadcasts.findOne({ _id: broadcastId, status: 'sending' })\n if (!broadcast) return\n await runBroadcastDispatch(broadcast, ctx)\n}\n\n/**\n * Rescue broadcasts whose dispatcher died. Re-dispatch is idempotent: the\n * per-recipient dedupeKey unique index skips send rows already inserted, so\n * a resumed broadcast picks up where the dead worker left off.\n */\nexport async function resumeStalledBroadcasts(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STALLED_BROADCAST_THRESHOLD_MS)\n const stalled = await ctx.collections.broadcasts\n .find({ status: 'sending', updatedAt: { $lt: cutoff } })\n .toArray()\n\n for (const b of stalled) {\n // Touch before re-dispatch so subsequent ticks don't stack rescues.\n await ctx.collections.broadcasts.updateOne(\n { _id: b._id },\n { $set: { updatedAt: new Date() } },\n )\n await startBroadcastDispatch(b, ctx)\n }\n}\n\nasync function runBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n try {\n await dispatchBroadcast(broadcast, ctx)\n } catch (err) {\n console.error('mailery: broadcast dispatch failed', { id: String(broadcast._id), err })\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n }\n}\n\nasync function dispatchBroadcast(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: broadcast.templateSlug })\n if (!template) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n return\n }\n\n const hostFilter = toAdapterFilter(broadcast.segmentDefinition)\n const postFilters = broadcast.segmentDefinition.filters.filter((f) => isMailerSide(f))\n\n let cursor: string | undefined = undefined\n let total = 0\n const batchSize = ctx.config.broadcastEnqueueBatchSize\n const maxWaiting = ctx.config.broadcastEnqueueMaxWaiting\n const respectTimezone = broadcast.respectRecipientTimezone === true\n const scheduledMs = broadcast.scheduledAt?.getTime() ?? Date.now()\n\n for (;;) {\n // Progress heartbeat — resumeStalledBroadcasts treats a stale updatedAt\n // as a dead dispatcher, so touch it every page (and during backpressure).\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n\n const page = await ctx.adapter.query(hostFilter, { limit: batchSize, cursor })\n if (page.contacts.length === 0) break\n\n // Stage B: mailer-side post-filter.\n const eligible = await applyPostFilters(page.contacts, postFilters, ctx)\n\n if (eligible.length > 0) {\n // Backpressure: wait until the send queue's waiting set drains below cap.\n while ((await ctx.queues.send.getWaitingCount()) > maxWaiting) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n await sleep(2000)\n }\n\n const sendDocs = await Promise.all(\n eligible.map(async (contact) => buildSendDoc(broadcast, template, contact, ctx, scheduledMs, respectTimezone)),\n )\n\n // Filter out suppressed (mailer-side suppression check is the same one\n // dispatchSend would do; we short-circuit here to avoid enqueuing).\n const inserted: Array<{ sendId: ObjectId; delayMs: number }> = []\n for (const { doc, delayMs } of sendDocs) {\n if (!doc) continue\n try {\n await ctx.collections.sends.insertOne(doc)\n inserted.push({ sendId: doc._id!, delayMs })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // dup dedupeKey — already dispatched somewhere\n }\n }\n\n // Bulk enqueue.\n if (inserted.length > 0) {\n await Promise.all(\n inserted.map(({ sendId, delayMs }) =>\n ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n ...(delayMs > 0 ? { delay: delayMs } : {}),\n },\n ),\n ),\n )\n }\n\n total += inserted.length\n }\n\n if (!page.nextCursor) break\n cursor = page.nextCursor\n }\n\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n {\n $set: {\n status: 'sent',\n completedAt: new Date(),\n recipientCount: total,\n updatedAt: new Date(),\n },\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Segment translation\n// ---------------------------------------------------------------------------\n\nfunction toAdapterFilter(seg: SegmentDefinition): AdapterFilter {\n const out: AdapterFilter = {}\n for (const f of seg.filters) {\n switch (f.kind) {\n case 'hasTag':\n out.hasTag = f.tag\n break\n case 'fieldEquals':\n out.fieldEquals = { field: f.field, value: f.value }\n break\n case 'fieldIn':\n out.fieldIn = { field: f.field, values: f.values }\n break\n case 'fieldExists':\n out.fieldExists = f.field\n break\n // notHasTag isn't a single-condition adapter filter, defer to post-filter\n // subscriptionStatus / firedEvent / opened are all mailer-side\n }\n }\n return out\n}\n\nfunction isMailerSide(f: SegmentFilter): boolean {\n return (\n f.kind === 'subscriptionStatus' ||\n f.kind === 'firedEvent' ||\n f.kind === 'notFiredEvent' ||\n f.kind === 'subscribedAfter' ||\n f.kind === 'subscribedBefore' ||\n f.kind === 'opened' ||\n f.kind === 'notOpened' ||\n f.kind === 'notHasTag' ||\n f.kind === 'any' ||\n f.kind === 'not'\n )\n}\n\nasync function applyPostFilters(contacts: Contact[], filters: SegmentFilter[], ctx: RunnerContext): Promise<Contact[]> {\n if (filters.length === 0) return contacts\n const externalIds = contacts.map((c) => c.externalId)\n\n // Cache common lookups in one Mongo round-trip per filter.\n const cache: Record<string, Set<string>> = {}\n for (const f of filters) {\n if (f.kind === 'subscriptionStatus') {\n const docs = await ctx.collections.subscriptions\n .find({ externalId: { $in: externalIds }, status: f.equals })\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`sub:${f.equals}`] = new Set(docs.map((d) => d.externalId))\n }\n if (f.kind === 'firedEvent' || f.kind === 'notFiredEvent') {\n const query: any = { externalId: { $in: externalIds }, name: f.eventName }\n if (f.withinDays) {\n query.occurredAt = { $gt: new Date(Date.now() - f.withinDays * 86_400_000) }\n }\n const docs = await ctx.collections.events\n .find(query)\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`evt:${f.eventName}`] = new Set(docs.map((d) => d.externalId))\n }\n }\n\n return contacts.filter((c) => filters.every((f) => filterMatches(c, f, cache)))\n}\n\nfunction filterMatches(c: Contact, f: SegmentFilter, cache: Record<string, Set<string>>): boolean {\n switch (f.kind) {\n case 'subscriptionStatus':\n return cache[`sub:${f.equals}`]?.has(c.externalId) ?? false\n case 'firedEvent':\n return cache[`evt:${f.eventName}`]?.has(c.externalId) ?? false\n case 'notFiredEvent':\n return !cache[`evt:${f.eventName}`]?.has(c.externalId)\n case 'notHasTag':\n return !c.tags.includes(f.tag)\n case 'opened':\n case 'notOpened':\n // V1: not implemented in batch — would need a per-contact send lookup.\n // Treat as pass for now; suppress at dispatch time.\n return true\n case 'subscribedAfter':\n case 'subscribedBefore':\n return true // V2\n case 'any':\n return f.filters.some((sub) => filterMatches(c, sub, cache))\n case 'not':\n return !filterMatches(c, f.filter, cache)\n default:\n return true\n }\n}\n\n// ---------------------------------------------------------------------------\n// Send doc construction\n// ---------------------------------------------------------------------------\n\ninterface BuildResult {\n doc: SendDoc | null\n delayMs: number\n}\n\nasync function buildSendDoc(\n broadcast: BroadcastDoc,\n template: TemplateDoc,\n contact: Contact,\n ctx: RunnerContext,\n scheduledMs: number,\n respectTimezone: boolean,\n): Promise<BuildResult> {\n // Final suppression check before we insert.\n const supp = await isSuppressed(ctx.collections, contact.email, template.kind)\n if (supp.suppressed) return { doc: null, delayMs: 0 }\n\n const sendId = new ObjectId()\n const dedupeKey = `broadcast:${broadcast._id}:${contact.externalId}`\n\n // Per-recipient TZ delay calculation. Anchored to scheduledAt (not enqueue\n // time) so tick lag and backpressure pauses don't drift later batches.\n let delayMs = Math.max(0, scheduledMs - Date.now())\n if (respectTimezone && contact.timezone) {\n const offsetMs = perRecipientOffsetMs(scheduledMs, contact.timezone)\n delayMs = Math.max(0, scheduledMs + offsetMs - Date.now())\n }\n\n const doc: SendDoc = {\n _id: sendId,\n dedupeKey,\n externalId: contact.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: broadcast._id!,\n manualSendBy: null,\n kind: template.kind,\n provider: template.providerOverride ?? ctx.config.defaultProvider,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n }\n void sha256Hex\n return { doc, delayMs }\n}\n\n/**\n * Offset to add to `scheduledMs` so the email arrives at the same WALL-CLOCK\n * time in the recipient's timezone.\n *\n * Example: broadcast `scheduledAt` is 10am UTC, contact is in PST (UTC-8).\n * Their 10am is 6pm UTC → offset +8h.\n *\n * Recipients EAST of the schedule's timezone would need a negative offset —\n * their 10am already passed when dispatch starts. Sending \"now\" would land at\n * the wrong local time, so instead the offset is normalized into [0, 24h):\n * they get the NEXT occurrence of the wall-clock slot, i.e. same time\n * tomorrow. (Berlin, UTC+2: raw offset −2h → +22h.)\n */\nfunction perRecipientOffsetMs(scheduledMs: number, timezone: string): number {\n const DAY_MS = 24 * 60 * 60 * 1000\n try {\n // Get the offset between the scheduled UTC instant interpreted as a wall\n // clock and the same wall clock in the recipient's tz.\n const scheduled = new Date(scheduledMs)\n const utc = scheduled.toLocaleString('en-US', { timeZone: 'UTC', hour12: false })\n const local = scheduled.toLocaleString('en-US', { timeZone: timezone, hour12: false })\n\n // Parse both as Date objects in the runner's local tz and take the diff.\n const parse = (s: string) => {\n const m = s.match(/(\\d+)\\/(\\d+)\\/(\\d+),\\s*(\\d+):(\\d+):(\\d+)/)\n if (!m) return 0\n return Date.UTC(+m[3]!, +m[1]! - 1, +m[2]!, +m[4]!, +m[5]!, +m[6]!)\n }\n const utcMs = parse(utc)\n const localMs = parse(local)\n const offsetMs = utcMs - localMs\n\n return ((offsetMs % DAY_MS) + DAY_MS) % DAY_MS\n } catch {\n return 0\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * Soft → hard bounce promotion. Configurable threshold + window:\n *\n * softBouncePromotionThreshold soft bounces for the same email within\n * softBouncePromotionWindowDays → insert a hard suppression + mark\n * the subscription bounced.\n *\n * Runs on each tick. Idempotent: if a hard suppression already exists for\n * that email, we skip.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function promoteSoftBounces(ctx: RunnerContext): Promise<void> {\n const threshold = ctx.config.softBouncePromotionThreshold\n const windowDays = ctx.config.softBouncePromotionWindowDays\n if (threshold <= 0 || windowDays <= 0) return\n\n const cutoff = new Date(Date.now() - windowDays * 86_400_000)\n\n // Aggregate: count soft bounces per emailAtSend since cutoff, hitting the\n // threshold. Bounded limit to keep the tick fast.\n const offenders = await ctx.collections.sends\n .aggregate<{ _id: string; count: number; lastFromEmail: string | null; lastKind: TemplateKind | null }>([\n { $match: { status: 'bounced', bounceType: 'soft', queuedAt: { $gt: cutoff } } },\n { $sort: { queuedAt: 1 } },\n {\n $group: {\n _id: '$emailAtSend',\n count: { $sum: 1 },\n lastFromEmail: { $last: '$fromEmail' },\n lastKind: { $last: '$kind' },\n },\n },\n { $match: { count: { $gte: threshold } } },\n { $limit: 200 },\n ])\n .toArray()\n\n for (const o of offenders) {\n const email = String(o._id ?? '').toLowerCase()\n if (!email) continue\n\n // Skip if already hard-suppressed.\n const existing = await ctx.collections.suppressions.findOne({\n email,\n scope: 'all',\n })\n if (existing) continue\n\n await ctx.collections.suppressions.updateOne(\n { email, scope: 'all' },\n {\n $setOnInsert: {\n email,\n emailHash: sha256Hex(email),\n scope: 'all',\n reason: 'hard_bounce',\n source: 'soft_promotion',\n notes: `${o.count} soft bounces in last ${windowDays} days`,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n\n await recordHealthCounter(\n ctx,\n 'hardBounced',\n o.lastKind ? { fromEmail: o.lastFromEmail, kind: o.lastKind } : null,\n )\n }\n}\n","/**\n * DNSBL monitor. Once a day (or on demand) we DNS-query each configured\n * sender domain against domain block lists (DBLs) and each configured\n * dedicated IP against IP block lists. Results are stored as one doc per\n * (target, list) — the latest result replaces the prior one.\n *\n * No external API. Pure DNS, so it works in any environment that can\n * resolve public hostnames.\n */\n\nimport dns from 'node:dns/promises'\nimport net from 'node:net'\nimport psl from 'psl'\n\nimport type {\n DnsblConfig,\n DnsblListSpec,\n} from '../config.js'\nimport {\n DEFAULT_DOMAIN_DNSBL_LISTS,\n DEFAULT_IP_DNSBL_LISTS,\n} from '../config.js'\nimport type { DnsblCheckDoc, DnsblResult, DnsblTargetKind } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Lists that expect a registrable domain (eTLD+1) rather than the full\n * FQDN. Querying `mail.foo.example.com.multi.surbl.org` returns NXDOMAIN\n * even when `example.com` is listed.\n */\nconst REGISTRABLE_ONLY_LISTS = new Set(['multi.surbl.org', 'multi.uribl.com'])\n\n/** DNS-query concurrency for parallel lookups. Keep modest to avoid resolver throttling. */\nconst DNS_CONCURRENCY = 8\n\nexport interface Resolver {\n resolve4(hostname: string): Promise<string[]>\n}\n\nconst defaultResolver: Resolver = {\n resolve4: (hostname) => dns.resolve4(hostname),\n}\n\nexport interface RunDnsblOptions {\n /** Override the DNS resolver (used in tests). */\n resolver?: Resolver\n /** When true, ignore the throttle and run all checks immediately. */\n force?: boolean\n}\n\nexport interface RunDnsblResult {\n ran: boolean\n reason?: string\n totalChecks?: number\n listedCount?: number\n}\n\n/**\n * Run DNSBL checks for every (target × list) pair. Idempotent — the latest\n * result for each pair is upserted.\n */\nexport async function runDnsblChecks(\n ctx: RunnerContext,\n opts: RunDnsblOptions = {},\n): Promise<RunDnsblResult> {\n const cfg = ctx.config.dnsbl ?? {}\n const intervalHours = cfg.intervalHours ?? 24\n\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const targets = collectTargets(ctx, cfg)\n if (targets.domains.length === 0 && targets.ips.length === 0) {\n return { ran: false, reason: 'no_targets' }\n }\n\n const resolver = opts.resolver ?? defaultResolver\n const domainLists = cfg.domainLists ?? DEFAULT_DOMAIN_DNSBL_LISTS\n const ipLists = cfg.ipLists ?? DEFAULT_IP_DNSBL_LISTS\n\n const pairs: Array<{\n target: string\n targetKind: DnsblTargetKind\n list: DnsblListSpec\n }> = []\n for (const d of targets.domains) {\n for (const l of domainLists) pairs.push({ target: d, targetKind: 'domain', list: l })\n }\n for (const ip of targets.ips) {\n for (const l of ipLists) pairs.push({ target: ip, targetKind: 'ip', list: l })\n }\n\n // Per-pair throttle: skip pairs whose existing row is fresher than the\n // interval. Force ignores the throttle. This replaces the previous\n // single-most-recent-check gate that blocked the whole suite based on\n // one stale row.\n const throttleCutoff = opts.force ? null : Date.now() - intervalHours * 60 * 60 * 1000\n let duePairs = pairs\n if (throttleCutoff != null) {\n const existing = await ctx.collections.dnsblChecks\n .find(\n {\n $or: pairs.map((p) => ({ target: p.target, list: p.list.host })),\n },\n { projection: { target: 1, list: 1, runAt: 1 } },\n )\n .toArray()\n const fresh = new Set<string>()\n for (const e of existing) {\n if (new Date(e.runAt).getTime() > throttleCutoff) {\n fresh.add(`${e.target}|${e.list}`)\n }\n }\n duePairs = pairs.filter((p) => !fresh.has(`${p.target}|${p.list.host}`))\n if (duePairs.length === 0) {\n return { ran: false, reason: 'not_due', totalChecks: 0, listedCount: 0 }\n }\n }\n\n let listedCount = 0\n\n // Bounded parallelism — DNS lookups are I/O-bound, but blasting all 25+\n // queries at once invites resolver throttling.\n async function processPair(p: typeof pairs[number]) {\n const queryName = buildQueryName(p.target, p.targetKind, p.list.host)\n const lookup = queryName\n ? await queryDnsbl(resolver, queryName)\n : { result: 'error' as DnsblResult, returnCodes: [], errorMessage: 'unsupported target format' }\n // Transient DNS failure: preserve the prior verdict so a momentary\n // resolver hiccup doesn't flip a clean target to 'error' in setup-status.\n if (lookup.transient) return\n if (lookup.result === 'listed') listedCount++\n await ctx.collections.dnsblChecks.updateOne(\n { target: p.target, list: p.list.host },\n {\n $set: {\n target: p.target,\n targetKind: p.targetKind,\n list: p.list.host,\n listLabel: p.list.label,\n result: lookup.result,\n returnCodes: lookup.returnCodes,\n errorMessage: lookup.errorMessage,\n runAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n\n let idx = 0\n await Promise.all(\n Array.from({ length: Math.min(DNS_CONCURRENCY, duePairs.length) }, async () => {\n while (idx < duePairs.length) {\n const my = idx++\n await processPair(duePairs[my]!)\n }\n }),\n )\n\n return { ran: true, totalChecks: duePairs.length, listedCount }\n}\n\n/**\n * Targets we'll check: every sender domain we know about + any explicitly\n * configured dedicated IPs. Domains come from `senderDomains` registry plus\n * the From defaults so an operator who only set fromDefaults still gets\n * coverage.\n */\nfunction collectTargets(ctx: RunnerContext, cfg: DnsblConfig): { domains: string[]; ips: string[] } {\n const domains = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) domains.add(d.toLowerCase())\n }\n const fromDomain = ctx.config.fromDefaults?.email\n ? extractDomain(ctx.config.fromDefaults.email)\n : null\n if (fromDomain) domains.add(fromDomain)\n const txnDomain = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (txnDomain) domains.add(txnDomain)\n\n // Both IPv4 and IPv6 are valid query targets — let the lookup layer handle\n // formatting per RFC 5782. Invalid strings are dropped here so they don't\n // produce a row with errorMessage='unsupported target format' on every run.\n return {\n domains: Array.from(domains),\n ips: (cfg.dedicatedIps ?? []).filter((ip) => net.isIP(ip) !== 0),\n }\n}\n\n/**\n * Compute the DNS name to query for a (target, list) pair, honoring the\n * per-list peculiarities:\n * - IPv4: reverse octets and prepend.\n * - IPv6: reverse nibble-by-nibble per RFC 5782.\n * - Domain on a registrable-only list (SURBL/URIBL): collapse to eTLD+1.\n *\n * Returns null when the target shape isn't supported by the list (e.g.,\n * IPv4-only list given an IPv6 target).\n */\nfunction buildQueryName(target: string, kind: DnsblTargetKind, listHost: string): string | null {\n if (kind === 'ip') {\n const v = net.isIP(target)\n if (v === 4) return `${reverseIPv4(target)}.${listHost}`\n if (v === 6) return `${reverseIPv6Nibbles(target)}.${listHost}`\n return null\n }\n // Domain — collapse to registrable label for lists that demand it.\n const domain = REGISTRABLE_ONLY_LISTS.has(listHost) ? registrableDomain(target) : target\n return `${domain}.${listHost}`\n}\n\ninterface QueryResult {\n /** When true, the underlying DNS query failed transiently (SERVFAIL etc).\n * Caller should leave the existing row in place rather than overwrite it. */\n transient?: boolean\n result: DnsblResult\n returnCodes: string[]\n errorMessage: string | null\n}\n\n// Transient DNS errors we don't want to treat as a \"list error\" — these\n// indicate a resolver problem or rate-limit at the block-list side and\n// should be retried next tick rather than producing a setup-status warn.\nconst TRANSIENT_DNS_CODES = new Set(['ESERVFAIL', 'EREFUSED', 'ETIMEOUT', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'])\n\nasync function queryDnsbl(resolver: Resolver, query: string): Promise<QueryResult> {\n try {\n const records = await resolver.resolve4(query)\n return interpretRecords(records)\n } catch (err: any) {\n const code = err?.code\n // NXDOMAIN / no records → not listed.\n if (code === 'ENOTFOUND' || code === 'ENODATA') {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Transient: signal the runner to skip the upsert. Spamhaus and friends\n // SERVFAIL when rate-limiting public resolvers; storing those as 'error'\n // produces setup-status warn churn without operator-actionable signal.\n if (code && TRANSIENT_DNS_CODES.has(code)) {\n return {\n transient: true,\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n return {\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n}\n\nexport function interpretRecords(records: string[]): QueryResult {\n if (!records || records.length === 0) {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Per Spamhaus convention, 127.255.255.x is reserved for query-error /\n // public-resolver / blocked-by-list signals. Treat those as errors so they\n // don't false-positive a \"listed\" verdict.\n const errorish = records.filter((r) => r.startsWith('127.255.255.'))\n if (errorish.length === records.length) {\n return {\n result: 'error',\n returnCodes: records,\n errorMessage: `list returned reserved code(s): ${records.join(', ')}`,\n }\n }\n const listed = records.filter((r) => r.startsWith('127.') && !r.startsWith('127.255.255.'))\n if (listed.length > 0) {\n return { result: 'listed', returnCodes: records, errorMessage: null }\n }\n return { result: 'clean', returnCodes: records, errorMessage: null }\n}\n\nexport function reverseIPv4(ip: string): string {\n return ip.split('.').reverse().join('.')\n}\n\n/**\n * RFC 5782 §2.4 nibble-reversed form for IPv6. Each hex digit becomes its\n * own label in reverse order. Example:\n * 2001:db8::1\n * → 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2\n *\n * Handles IPv4-mapped form (`::ffff:1.2.3.4`) by converting the embedded\n * dot-octet portion into two hex groups before nibble-expanding.\n */\nexport function reverseIPv6Nibbles(ip: string): string {\n // First convert any embedded IPv4 (\"::ffff:1.2.3.4\" → \"::ffff:0102:0304\").\n const v4Match = /:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/.exec(ip)\n let normalized = ip\n if (v4Match) {\n const octets = v4Match[1]!.split('.').map((o) => Number(o))\n if (octets.length === 4 && octets.every((o) => o >= 0 && o <= 255)) {\n const hi = ((octets[0]! << 8) | octets[1]!).toString(16).padStart(4, '0')\n const lo = ((octets[2]! << 8) | octets[3]!).toString(16).padStart(4, '0')\n normalized = ip.slice(0, v4Match.index) + ':' + hi + ':' + lo\n }\n }\n\n // Expand `::` shorthand and zero-pad each group to 4 chars.\n const sides = normalized.split('::')\n let groups: string[]\n if (sides.length === 1) {\n groups = sides[0]!.split(':')\n } else {\n const left = sides[0]!.split(':').filter(Boolean)\n const right = sides[1]!.split(':').filter(Boolean)\n const missing = 8 - left.length - right.length\n groups = [...left, ...Array(missing).fill('0'), ...right]\n }\n if (groups.length !== 8) {\n throw new Error(`unexpected IPv6 group count for ${ip}: ${groups.length}`)\n }\n const padded = groups.map((g) => g.toLowerCase().padStart(4, '0')).join('')\n return padded.split('').reverse().join('.')\n}\n\n/**\n * Public Suffix List-aware eTLD+1 extraction. Required for SURBL / URIBL\n * which need the registrable domain — `mail.example.co.uk` must collapse to\n * `example.co.uk`, not `co.uk`. Falls back to the original input when PSL\n * can't classify the domain (e.g., a private TLD).\n */\nfunction registrableDomain(domain: string): string {\n const parsed = psl.parse(domain)\n if ('domain' in parsed && parsed.domain) return parsed.domain\n return domain\n}\n","/**\n * Google Postmaster Tools API client + daily puller.\n *\n * - Exchanges the operator-provided OAuth refresh token for short-lived\n * access tokens (cached until ~5 minutes before expiry).\n * - Pulls per-domain TrafficStats for each registered sender domain.\n * - Persists one PostmasterSnapshot per (domain, day).\n * - When a snapshot reports `domainReputation: 'BAD'`, trips the\n * (domain × marketing) health bucket so the runner stops dispatching\n * marketing mail from that domain.\n *\n * Setup is one-time and external — operator creates an OAuth client in their\n * own Google Cloud project, performs the consent flow, and configures the\n * refresh token in MailerConfig.postmaster.\n */\n\nimport type { PostmasterConfig } from '../config.js'\nimport type {\n PostmasterReputation,\n PostmasterSnapshotDoc,\n} from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\nimport { healthBucketId } from '../models/index.js'\n\nconst OAUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token'\nconst POSTMASTER_BASE = 'https://gmailpostmastertools.googleapis.com/v1'\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nasync function fetchWithTimeout(fetcher: Fetcher, url: string, init: RequestInit = {}, timeoutMs = FETCH_TIMEOUT_MS): Promise<Response> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), timeoutMs)\n try {\n return await fetcher(url, { ...init, signal: ctl.signal })\n } finally {\n clearTimeout(t)\n }\n}\n\nexport interface PostmasterClient {\n listDomains(): Promise<Array<{ name: string; createTime?: string }>>\n getLatestTrafficStats(domain: string): Promise<TrafficStat | null>\n}\n\ninterface OAuthResponse {\n access_token: string\n expires_in: number\n scope?: string\n token_type?: string\n}\n\nexport interface TrafficStat {\n /** Resource name, e.g. `domains/example.com/trafficStats/20240101`. */\n name: string\n domainReputation?: PostmasterReputation\n ipReputations?: Array<{ reputation: PostmasterReputation; ipCount: string | number }>\n userReportedSpamRatio?: number\n spfSuccessRatio?: number\n dkimSuccessRatio?: number\n dmarcSuccessRatio?: number\n inboundEncryptionRatio?: number\n outboundEncryptionRatio?: number\n deliveryErrors?: Array<{ errorType: string; errorClass: string; errorRatio: number }>\n spammyFeedbackLoops?: Array<{ id: string; spamRatio: number }>\n}\n\nexport function createPostmasterClient(\n cfg: Pick<PostmasterConfig, 'clientId' | 'clientSecret' | 'refreshToken'>,\n fetcher: Fetcher = globalThis.fetch,\n): PostmasterClient {\n let cached: { accessToken: string; expiresAt: number } | null = null\n\n async function getAccessToken(): Promise<string> {\n if (cached && cached.expiresAt > Date.now() + 5 * 60 * 1000) {\n return cached.accessToken\n }\n const body = new URLSearchParams({\n client_id: cfg.clientId,\n client_secret: cfg.clientSecret,\n refresh_token: cfg.refreshToken,\n grant_type: 'refresh_token',\n })\n const res = await fetchWithTimeout(fetcher, OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n })\n if (!res.ok) {\n throw new Error(`Postmaster OAuth token refresh failed: ${res.status} ${await safeText(res)}`)\n }\n const data = (await res.json()) as OAuthResponse\n cached = {\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n return cached.accessToken\n }\n\n async function authedGet<T>(path: string): Promise<T> {\n const token = await getAccessToken()\n const res = await fetchWithTimeout(fetcher, `${POSTMASTER_BASE}${path}`, {\n method: 'GET',\n headers: { authorization: `Bearer ${token}` },\n })\n if (!res.ok) {\n throw new Error(`Postmaster GET ${path} failed: ${res.status} ${await safeText(res)}`)\n }\n return (await res.json()) as T\n }\n\n return {\n async listDomains() {\n const data = await authedGet<{ domains?: Array<{ name: string; createTime?: string }> }>('/domains')\n return data.domains ?? []\n },\n\n async getLatestTrafficStats(domain: string) {\n // Postmaster traffic stats are reported with a ~2-day delay. Pull the\n // most recent available; the API returns them in reverse-chronological\n // order when no date range is specified.\n const data = await authedGet<{ trafficStats?: TrafficStat[] }>(\n `/domains/${encodeURIComponent(domain)}/trafficStats?pageSize=1`,\n )\n return data.trafficStats?.[0] ?? null\n },\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return '<no body>'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Puller\n// ---------------------------------------------------------------------------\n\nexport interface RunPostmasterOptions {\n client?: PostmasterClient\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunPostmasterResult {\n ran: boolean\n reason?: string\n fetched?: number\n trippedDomains?: string[]\n}\n\nexport async function runPostmasterPull(\n ctx: RunnerContext,\n opts: RunPostmasterOptions = {},\n): Promise<RunPostmasterResult> {\n const cfg = ctx.config.postmaster\n if (!cfg) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const client =\n opts.client ?? createPostmasterClient(cfg, opts.fetcher)\n const allDomains = resolveDomains(ctx, cfg)\n if (allDomains.length === 0) {\n return { ran: false, reason: 'no_domains' }\n }\n\n // Per-domain throttle — fetch only domains whose latest snapshot is\n // older than intervalHours. Previously a single global timestamp across\n // all domains locked unfetched / partially-failed domains out of the\n // next run for a full window.\n let domains = allDomains\n if (!opts.force) {\n const cutoff = Date.now() - intervalHours * 60 * 60 * 1000\n const latest = await ctx.collections.postmasterSnapshots\n .find({ domain: { $in: allDomains } }, { projection: { domain: 1, fetchedAt: 1 } })\n .sort({ fetchedAt: -1 })\n .limit(allDomains.length * 8)\n .toArray()\n const lastByDomain = new Map<string, number>()\n for (const s of latest) {\n const ts = new Date(s.fetchedAt).getTime()\n const cur = lastByDomain.get(s.domain) ?? 0\n if (ts > cur) lastByDomain.set(s.domain, ts)\n }\n domains = allDomains.filter((d) => (lastByDomain.get(d) ?? 0) < cutoff)\n if (domains.length === 0) {\n return { ran: false, reason: 'not_due' }\n }\n }\n\n // Fetch all domains in parallel — they're independent HTTP calls and\n // serial ordering only multiplies tick latency.\n const fetches = await Promise.all(\n domains.map(async (domain) => {\n try {\n const stat = await client.getLatestTrafficStats(domain)\n return { domain, stat, error: null as Error | null }\n } catch (err: any) {\n console.error(`mailery: postmaster fetch failed for ${domain}`, err)\n return { domain, stat: null, error: err as Error }\n }\n }),\n )\n\n let fetched = 0\n const trippedDomains: string[] = []\n for (const { domain, stat } of fetches) {\n if (!stat) continue\n const snapshot = toSnapshot(domain, stat)\n if (!snapshot) continue\n fetched++\n\n await ctx.collections.postmasterSnapshots.updateOne(\n { domain: snapshot.domain, date: snapshot.date },\n { $set: snapshot },\n { upsert: true },\n )\n\n if (snapshot.domainReputation === 'BAD') {\n // Trip every kind the registry says this domain is allowed to send\n // as. If the registry doesn't know this domain at all, skip the\n // auto-trip — we have no signal that the operator wants this domain\n // gated by mailery.\n const kindsToTrip = kindsForDomain(ctx, domain)\n for (const kind of kindsToTrip) {\n const tripped = await tripBucket(ctx, domain, kind, snapshot)\n if (tripped) trippedDomains.push(`${domain}|${kind}`)\n }\n }\n }\n\n return { ran: true, fetched, trippedDomains }\n}\n\nfunction kindsForDomain(ctx: RunnerContext, domain: string): Array<'marketing' | 'transactional'> {\n const registry = ctx.config.senderDomains ?? {}\n const entry = registry[domain.toLowerCase()]\n if (!entry) return []\n if (entry.kind === 'both') return ['marketing', 'transactional']\n return [entry.kind]\n}\n\nfunction resolveDomains(ctx: RunnerContext, cfg: PostmasterConfig): string[] {\n if (cfg.domains && cfg.domains.length > 0) {\n return cfg.domains.map((d) => d.toLowerCase())\n }\n const out = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) out.add(d.toLowerCase())\n }\n const f = ctx.config.fromDefaults?.email ? extractDomain(ctx.config.fromDefaults.email) : null\n if (f) out.add(f)\n const t = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (t) out.add(t)\n return Array.from(out)\n}\n\nfunction toSnapshot(domain: string, stat: TrafficStat): PostmasterSnapshotDoc | null {\n // `name` looks like `domains/example.com/trafficStats/20240115`. Bail out\n // when the format isn't recognized rather than overwriting today's snapshot\n // every run — the previous fallback to today's UTC date silently rewrote\n // legitimate data when the API format ever drifted.\n const m = /\\/trafficStats\\/(\\d{8})$/.exec(stat.name ?? '')\n if (!m) {\n console.error(`mailery: postmaster snapshot for ${domain} has unrecognized name \"${stat.name}\" — skipping`)\n return null\n }\n const yyyymmdd = m[1]!\n const date = `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`\n\n return {\n domain,\n date,\n domainReputation: stat.domainReputation ?? null,\n ipReputations: stat.ipReputations\n ? stat.ipReputations.map((r) => ({\n reputation: r.reputation,\n ipCount: typeof r.ipCount === 'string' ? Number(r.ipCount) : r.ipCount,\n }))\n : null,\n userReportedSpamRatio: stat.userReportedSpamRatio ?? null,\n spfSuccessRatio: stat.spfSuccessRatio ?? null,\n dkimSuccessRatio: stat.dkimSuccessRatio ?? null,\n dmarcSuccessRatio: stat.dmarcSuccessRatio ?? null,\n outboundEncryptionRatio: stat.outboundEncryptionRatio ?? null,\n inboundEncryptionRatio: stat.inboundEncryptionRatio ?? null,\n deliveryErrors: stat.deliveryErrors ?? null,\n spammyFeedbackLoops: stat.spammyFeedbackLoops ?? null,\n fetchedAt: new Date(),\n }\n}\n\n/**\n * Set a (domain × kind) bucket to `tripped` so the dispatcher holds matching\n * sends. The bucket is created on demand if it doesn't exist yet — Postmaster\n * can flag a domain before mailery has ever sent from it.\n */\nasync function tripBucket(\n ctx: RunnerContext,\n domain: string,\n kind: 'marketing' | 'transactional',\n snapshot: PostmasterSnapshotDoc,\n): Promise<boolean> {\n const id = healthBucketId(domain, kind)\n const reason = `Postmaster Tools reports ${domain} reputation = BAD on ${snapshot.date}`\n\n // Only update + alert when the bucket transitions to tripped — otherwise a\n // sustained BAD reputation would fire onCircuitBreakerTrip on every pull.\n const prior = await ctx.collections.health.findOne({ _id: id })\n if (prior?.status === 'tripped') {\n return false\n }\n\n await ctx.collections.health.updateOne(\n { _id: id },\n {\n $set: {\n status: 'tripped',\n trippedAt: new Date(),\n trippedReason: reason,\n updatedAt: new Date(),\n },\n $setOnInsert: {\n _id: id,\n senderDomain: domain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({ reason, rates: { userReportedSpamRatio: snapshot.userReportedSpamRatio ?? 0 } })\n } catch {\n /* swallow */\n }\n }\n return true\n}\n","/**\n * Microsoft SNDS (Smart Network Data Services) puller.\n *\n * https://sendersupport.olc.protection.outlook.com/snds/\n *\n * SNDS reports IP-level Outlook/Hotmail/Live reputation: filter verdict\n * (GREEN/YELLOW/RED), complaint rate, spam-trap hits, and sample HELO /\n * MAIL FROM strings for each activity window. Only meaningful when the\n * operator sends from a dedicated IP — shared-IP senders see nothing\n * meaningful here.\n *\n * Auth is a per-account access key (no OAuth). The data endpoint returns\n * CSV. Snapshots are stored per (ip, activityStart) so historical windows\n * accumulate.\n */\n\nimport type { SndsConfig } from '../config.js'\nimport type { SndsFilterResult, SndsSnapshotDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nconst SNDS_DATA_URL = 'https://postmaster.live.com/snds/data.aspx'\nconst FETCH_TIMEOUT_MS = 30_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface RunSndsOptions {\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunSndsResult {\n ran: boolean\n reason?: string\n rowsParsed?: number\n rowsPersisted?: number\n}\n\nexport async function runSndsPull(\n ctx: RunnerContext,\n opts: RunSndsOptions = {},\n): Promise<RunSndsResult> {\n const cfg = ctx.config.snds\n if (!cfg?.accessKey) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) return { ran: false, reason: 'disabled' }\n\n if (!opts.force) {\n const latest = await ctx.collections.sndsSnapshots\n .find({})\n .sort({ fetchedAt: -1 })\n .limit(1)\n .toArray()\n if (latest[0]) {\n const ageMs = Date.now() - new Date(latest[0].fetchedAt).getTime()\n if (ageMs < intervalHours * 60 * 60 * 1000) {\n return { ran: false, reason: 'not_due' }\n }\n }\n }\n\n const fetcher = opts.fetcher ?? globalThis.fetch\n const url = `${SNDS_DATA_URL}?key=${encodeURIComponent(cfg.accessKey)}`\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(url, { method: 'GET', signal: ctl.signal })\n } catch (err: any) {\n // Scrub the access key from any error message before it reaches a log.\n throw new Error(`SNDS data fetch failed: ${redactKey(String(err?.message ?? err), cfg.accessKey)}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n throw new Error(`SNDS data fetch failed: ${res.status} ${redactKey(await safeText(res), cfg.accessKey)}`)\n }\n const csv = await res.text()\n const rows = parseSndsCsv(csv)\n\n const ipFilter = cfg.ips?.length ? new Set(cfg.ips) : null\n const now = new Date()\n const ops = rows\n .filter((row) => !ipFilter || ipFilter.has(row.ip))\n .map((row) => ({\n updateOne: {\n filter: { ip: row.ip, activityStart: row.activityStart },\n update: { $set: { ...row, fetchedAt: now } },\n upsert: true,\n },\n }))\n let persisted = 0\n if (ops.length > 0) {\n const r = await ctx.collections.sndsSnapshots.bulkWrite(ops, { ordered: false })\n persisted = (r.modifiedCount ?? 0) + (r.upsertedCount ?? 0)\n }\n\n return { ran: true, rowsParsed: rows.length, rowsPersisted: persisted }\n}\n\nfunction redactKey(s: string, key: string): string {\n if (!key) return s\n return s.split(key).join('<redacted>').split(encodeURIComponent(key)).join('<redacted>')\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// CSV parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedSndsRow {\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n}\n\n/**\n * SNDS returns CSV with columns:\n * IP, ActivityStart, ActivityEnd, RCPTCommands, DATACommands,\n * MessageRecipients, FilterResult, ComplaintRate, TrapMessageCount,\n * SampleHELO, SampleMailFrom\n *\n * No header row. Fields may contain commas inside quoted strings (sample\n * HELO / MAIL FROM) — we handle simple double-quote escaping.\n */\nexport function parseSndsCsv(csv: string): ParsedSndsRow[] {\n const out: ParsedSndsRow[] = []\n for (const raw of csv.split(/\\r?\\n/)) {\n if (!raw.trim()) continue\n const fields = splitCsvRow(raw)\n if (fields.length < 7) continue // malformed row\n const parsed = parseRow(fields)\n if (parsed) out.push(parsed)\n }\n return out\n}\n\nfunction splitCsvRow(row: string): string[] {\n const out: string[] = []\n let cur = ''\n let inQuotes = false\n for (let i = 0; i < row.length; i++) {\n const ch = row[i]!\n if (inQuotes) {\n if (ch === '\"') {\n if (row[i + 1] === '\"') {\n cur += '\"'\n i++\n } else {\n inQuotes = false\n }\n } else {\n cur += ch\n }\n } else if (ch === '\"') {\n inQuotes = true\n } else if (ch === ',') {\n out.push(cur)\n cur = ''\n } else {\n cur += ch\n }\n }\n out.push(cur)\n return out.map((f) => f.trim())\n}\n\nfunction parseRow(fields: string[]): ParsedSndsRow | null {\n const [\n ip,\n activityStart,\n activityEnd,\n rcptCommands,\n dataCommands,\n messageRecipients,\n filterResult,\n complaintRate,\n trapMessageCount,\n sampleHelo,\n sampleMailFrom,\n ] = fields\n\n const start = parseSndsDate(activityStart ?? '')\n const end = parseSndsDate(activityEnd ?? '')\n if (!ip || !start || !end) return null\n\n return {\n ip,\n activityStart: start,\n activityEnd: end,\n rcptCommands: toInt(rcptCommands),\n dataCommands: toInt(dataCommands),\n messageRecipients: toInt(messageRecipients),\n filterResult: normalizeFilter(filterResult ?? ''),\n complaintRate: parseComplaintRate(complaintRate ?? ''),\n trapMessageCount: toInt(trapMessageCount),\n sampleHelo: sampleHelo ? sampleHelo : null,\n sampleMailFrom: sampleMailFrom ? sampleMailFrom : null,\n }\n}\n\nfunction toInt(s: string | undefined): number {\n if (!s) return 0\n const n = Number(s.replace(/[^\\d-]/g, ''))\n return Number.isFinite(n) ? n : 0\n}\n\nfunction normalizeFilter(s: string): SndsFilterResult {\n const u = s.toUpperCase().trim()\n if (u === 'GREEN' || u === 'YELLOW' || u === 'RED') return u\n return 'UNKNOWN'\n}\n\n/**\n * SNDS reports complaint rate in the formats: `<0.1%`, `0.1-0.3%`, `0.3-0.5%`,\n * `0.5-1%`, `1-2%`, `2-4%`, `>4%`. We persist the upper bound as a 0-1 fraction.\n */\nexport function parseComplaintRate(s: string): number | null {\n const trimmed = s.trim()\n if (!trimmed || trimmed === '-' || /n\\/?a/i.test(trimmed)) return null\n\n const cleaned = trimmed.replace(/%/g, '')\n // `<X` → X\n let m = /^<\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `>X` → X (lower bound; treat as the floor of what they're reporting)\n m = /^>\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `A-B` → B\n m = /^(\\d+(?:\\.\\d+)?)\\s*-\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[2]) / 100\n // Plain number\n m = /^(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n return null\n}\n\n/**\n * SNDS reports dates as `M/D/YYYY h:mm AM/PM` in Microsoft's Pacific time\n * (PST/PDT) — Microsoft's own docs are silent but community testing\n * consistently shows Pacific. Convert to UTC by applying the offset that\n * was in effect at that local timestamp.\n *\n * Daylight saving in the US runs second-Sunday-of-March → first-Sunday-of-\n * November. We compute the offset based on the parsed local-Pacific\n * timestamp; a fixed -8/-7 offset would be wrong around the boundaries.\n */\nexport function parseSndsDate(s: string): Date | null {\n const trimmed = s.trim()\n if (!trimmed) return null\n const m = /^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})\\s+(\\d{1,2}):(\\d{2})(?::(\\d{2}))?\\s*(AM|PM)?$/i.exec(trimmed)\n if (m) {\n const month = Number(m[1]) - 1\n const day = Number(m[2])\n const year = Number(m[3])\n let hour = Number(m[4])\n const minute = Number(m[5])\n const second = Number(m[6] ?? 0)\n const meridiem = m[7]?.toUpperCase()\n if (meridiem === 'PM' && hour < 12) hour += 12\n if (meridiem === 'AM' && hour === 12) hour = 0\n // First place the wall-clock instant in UTC, then add the Pacific\n // offset to convert back to a real UTC moment.\n const wallMs = Date.UTC(year, month, day, hour, minute, second)\n if (!Number.isFinite(wallMs)) return null\n const offsetHours = isUsPacificDst(year, month, day) ? 7 : 8\n return new Date(wallMs + offsetHours * 60 * 60 * 1000)\n }\n // Fallback: ISO-ish strings get parsed as expected by Date.\n const d = new Date(trimmed)\n if (!isNaN(d.getTime())) return d\n return null\n}\n\n/**\n * US daylight saving runs from the second Sunday of March through the\n * first Sunday of November. Pure date math against the wall-clock day —\n * close enough for SNDS export granularity (full-day activity windows).\n */\nfunction isUsPacificDst(year: number, month0: number, day: number): boolean {\n if (month0 > 2 && month0 < 10) return true\n if (month0 < 2 || month0 > 10) return false\n // March: starts on second Sunday.\n if (month0 === 2) {\n const dst = nthSundayOfMonth(year, 2, 2)\n return day >= dst\n }\n // November: ends on first Sunday.\n const dst = nthSundayOfMonth(year, 10, 1)\n return day < dst\n}\n\nfunction nthSundayOfMonth(year: number, month0: number, n: number): number {\n const first = new Date(Date.UTC(year, month0, 1))\n const dayOfWeek = first.getUTCDay()\n const firstSunday = 1 + ((7 - dayOfWeek) % 7)\n return firstSunday + (n - 1) * 7\n}\n","/**\n * DMARC RUA aggregate report ingestion.\n *\n * - extractDmarcXml(buffer, filename) — decompresses .zip / .gz / .xml\n * - parseDmarcReport(xml) — pure RFC 7489 XML → normalized doc + failures\n * - ingestDmarcAttachment(ctx, buffer, filename) — full ingest path:\n * extract → parse → upsert into mailer_dmarc_reports + _dmarc_failures\n *\n * Designed so the same `ingestDmarcAttachment` is used by:\n * - the admin file-upload endpoint\n * - the (future) SendGrid Inbound Parse webhook\n * - the (future) IMAP poller\n * - the `mailery ingest-dmarc` CLI\n */\n\n// Heavy parsers are loaded lazily inside the functions that need them so\n// the testing bundle doesn't drag adm-zip + fast-xml-parser through.\nimport type AdmZipType from 'adm-zip'\nimport type { XMLParser as XMLParserType } from 'fast-xml-parser'\n\nimport type {\n DmarcAuthResult,\n DmarcFailureDoc,\n DmarcPolicy,\n DmarcReportDoc,\n} from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Hard cap on decompressed bytes. A real RUA aggregate report is well under\n * 1 MB; anything above this is either malformed or an attempted zip bomb.\n */\nconst MAX_DECOMPRESSED_BYTES = 50 * 1024 * 1024\n\n/**\n * Reject zip entry names that would escape the extraction directory if we\n * were writing them to disk, plus null-byte injection. We only ever read\n * the buffer in memory, but defense-in-depth keeps us safe if the storage\n * model changes.\n */\nexport function assertSafeZipEntryName(rawName: string): void {\n if (typeof rawName !== 'string' || rawName.length === 0) {\n throw new Error(`zip entry has unsafe path: <empty>`)\n }\n if (rawName.includes('\\0')) {\n throw new Error(`zip entry has unsafe path: contains null byte`)\n }\n // POSIX absolute (`/etc/passwd`) or Windows-drive (`C:\\…`) paths.\n if (rawName.startsWith('/') || rawName.startsWith('\\\\') || /^[a-zA-Z]:[\\\\/]/.test(rawName)) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n const parts = rawName.split(/[/\\\\]/)\n if (parts.some((p) => p === '..')) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Pull DMARC XML payload(s) out of an attachment. Receivers send `.zip` or\n * `.gz` (or rarely a bare `.xml`). A multi-file zip returns each entry as a\n * separate string — concatenating them with `\\n` produces invalid XML with\n * two `<feedback>` roots.\n *\n * Defends against:\n * - decompression bombs — caps inflated bytes at MAX_DECOMPRESSED_BYTES\n * - zip-slip path traversal — rejects entries with absolute or `..` paths\n * - empty / malformed archives — throws with a useful message\n */\nexport async function extractDmarcXmls(buffer: Buffer, filename: string): Promise<string[]> {\n const lower = (filename ?? '').toLowerCase()\n const zlib = await import('node:zlib')\n\n if (lower.endsWith('.gz')) {\n const xml = await new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n let bytes = 0\n const stream = zlib.createGunzip()\n stream.on('data', (chunk: Buffer) => {\n bytes += chunk.length\n if (bytes > MAX_DECOMPRESSED_BYTES) {\n stream.destroy()\n reject(new Error(`DMARC gzip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`))\n return\n }\n chunks.push(chunk)\n })\n stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))\n stream.on('error', reject)\n stream.end(buffer)\n })\n return [xml]\n }\n\n if (lower.endsWith('.zip')) {\n const { default: AdmZip } = await import('adm-zip')\n const zip = new (AdmZip as unknown as typeof AdmZipType)(buffer)\n const entries = zip.getEntries().filter((e) => !e.isDirectory)\n if (entries.length === 0) throw new Error('zip contains no files')\n\n let total = 0\n const pieces: string[] = []\n for (const entry of entries) {\n // Zip-slip defense — adm-zip has had CVE history (CVE-2018-1002204).\n assertSafeZipEntryName(entry.entryName)\n\n // Declared size is the fast-path bail — reject before decompressing\n // when a (truthful) header already exceeds the cap. Reject entries\n // with no declared size at all (DMARC receivers always populate it).\n const declaredSize = (entry.header as any)?.size\n if (typeof declaredSize !== 'number' || declaredSize <= 0) {\n throw new Error(`zip entry ${entry.entryName} has no declared size (refusing to decompress)`)\n }\n if (declaredSize > MAX_DECOMPRESSED_BYTES || total + declaredSize > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`)\n }\n\n // Actual decompressed payload — defends against a forged header that\n // claims a tiny size but inflates huge. We pay the inflation cost for\n // this entry, but cap on cumulative real bytes before the next entry.\n const data = entry.getData()\n total += data.length\n if (total > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip decompressed payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes (forged header?)`)\n }\n // Compression-ratio sanity check only kicks in on larger entries —\n // legitimate tiny XML inflates ~64x routinely. The cumulative cap\n // above already covers the real bomb scenarios for small entries.\n if (declaredSize > 10 * 1024 && data.length > declaredSize * 64 + 1024) {\n throw new Error(`DMARC zip entry ${entry.entryName} decompressed size (${data.length}) far exceeds declared (${declaredSize})`)\n }\n pieces.push(data.toString('utf8'))\n }\n return pieces\n }\n\n // Treat as raw XML — still cap by raw buffer size.\n if (buffer.length > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes`)\n }\n return [buffer.toString('utf8')]\n}\n\n/**\n * Convenience wrapper for callers that handle a single report.\n * @deprecated prefer `extractDmarcXmls` so multi-file zips can be parsed\n * independently. Kept temporarily; remove once all callers migrate.\n */\nexport async function extractDmarcXml(buffer: Buffer, filename: string): Promise<string> {\n const xmls = await extractDmarcXmls(buffer, filename)\n return xmls.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// XML parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedDmarcReport {\n report: Omit<DmarcReportDoc, 'receivedAt'>\n failures: Array<Omit<DmarcFailureDoc, 'receivedAt'>>\n}\n\n/**\n * Parse RFC 7489 aggregate report XML. Tolerant — receivers vary slightly in\n * casing and field order. Throws if the XML can't be parsed at all or if\n * required identifiers (report_id, domain, date_range) are missing.\n */\nexport function parseDmarcReport(xml: string): ParsedDmarcReport {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { XMLParser } = require('fast-xml-parser') as { XMLParser: typeof XMLParserType }\n const parser = new XMLParser({\n ignoreAttributes: false,\n parseAttributeValue: false,\n parseTagValue: false,\n trimValues: true,\n // RFC 7489 specifies lowercase snake_case tag names, but some\n // less-careful receivers emit CamelCase. Normalize before lookup.\n transformTagName: (t: string) => t.toLowerCase(),\n })\n const root: any = parser.parse(xml)\n const fb = root?.feedback\n if (!fb) throw new Error('DMARC XML missing <feedback> root')\n\n const meta = fb.report_metadata ?? {}\n const policy = fb.policy_published ?? {}\n\n const reportId = String(meta.report_id ?? '').trim()\n const orgName = String(meta.org_name ?? '').trim()\n const email = String(meta.email ?? '').trim()\n const domain = String(policy.domain ?? '').trim().toLowerCase()\n const policyP = (policy.p ?? 'none') as DmarcPolicy\n const rawPct = Number(policy.pct ?? 100)\n // Use isFinite so pct=0 (legit \"monitor only\" config) survives.\n const policyPct = Number.isFinite(rawPct) ? Math.max(0, Math.min(100, rawPct)) : 100\n\n if (!reportId) throw new Error('DMARC XML missing report_id')\n if (!domain) throw new Error('DMARC XML missing policy_published.domain')\n\n const range = meta.date_range ?? {}\n const begin = secondsToDate(range.begin)\n const end = secondsToDate(range.end)\n if (!begin || !end) throw new Error('DMARC XML missing date_range')\n\n const records = toArray<any>(fb.record)\n const failures: ParsedDmarcReport['failures'] = []\n let totalMessages = 0\n let passCount = 0\n let failCount = 0\n\n // Day bucket = mid-point of the report window.\n const midMs = Math.floor((begin.getTime() + end.getTime()) / 2)\n const day = new Date(midMs).toISOString().slice(0, 10)\n\n for (const rec of records) {\n const row = rec?.row ?? {}\n const count = Number(row.count ?? 0) || 0\n totalMessages += count\n\n const evald = row.policy_evaluated ?? {}\n const dkim = (evald.dkim ?? 'none') as DmarcAuthResult\n const spf = (evald.spf ?? 'none') as DmarcAuthResult\n const aligned = dkim === 'pass' || spf === 'pass'\n\n if (aligned) {\n passCount += count\n continue\n }\n failCount += count\n\n const sourceIp = String(row.source_ip ?? '').trim()\n if (!sourceIp) continue\n const headerFrom = String(rec?.identifiers?.header_from ?? '').toLowerCase()\n const dispositionApplied = String(evald.disposition ?? 'none')\n\n failures.push({\n reportId,\n domain,\n sourceIp,\n count,\n headerFrom,\n dkimResult: dkim,\n spfResult: spf,\n dispositionApplied,\n day,\n })\n }\n\n return {\n report: {\n reportId,\n orgName,\n email,\n domain,\n policyP,\n policyPct,\n rangeStart: begin,\n rangeEnd: end,\n totalMessages,\n passCount,\n failCount,\n },\n failures,\n }\n}\n\nfunction secondsToDate(v: unknown): Date | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : Number(String(v))\n if (!Number.isFinite(n) || n <= 0) return null\n return new Date(n * 1000)\n}\n\nfunction toArray<T>(v: T | T[] | undefined | null): T[] {\n if (v === undefined || v === null) return []\n return Array.isArray(v) ? v : [v]\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport interface IngestResult {\n ok: true\n reportId: string\n domain: string\n rangeStart: Date\n rangeEnd: Date\n totalMessages: number\n passCount: number\n failCount: number\n duplicate: boolean\n}\n\n/**\n * Full ingest path: extract attachment → parse each XML payload → upsert\n * into mailer_dmarc_reports + mailer_dmarc_failures. Idempotent on\n * (reportId, orgName) — re-uploading the same report is a no-op. When the\n * attachment is a multi-file zip, each entry is parsed independently and\n * the first ingest result is returned (with `additionalReports` count).\n */\nexport async function ingestDmarcAttachment(\n ctx: RunnerContext,\n buffer: Buffer,\n filename: string,\n): Promise<IngestResult & { additionalReports?: number }> {\n const xmls = await extractDmarcXmls(buffer, filename)\n if (xmls.length === 0) throw new Error('attachment contained no XML payload')\n const results: IngestResult[] = []\n let firstError: unknown = null\n for (const xml of xmls) {\n try {\n const parsed = parseDmarcReport(xml)\n results.push(await ingestParsedDmarcReport(ctx, parsed))\n } catch (err) {\n if (!firstError) firstError = err\n // Continue ingesting siblings — one malformed report in a multi-file\n // archive shouldn't reject all valid siblings.\n }\n }\n if (results.length === 0) {\n throw firstError ?? new Error('no parseable DMARC reports in attachment')\n }\n return { ...results[0]!, additionalReports: results.length - 1 }\n}\n\nexport async function ingestParsedDmarcReport(\n ctx: RunnerContext,\n parsed: ParsedDmarcReport,\n): Promise<IngestResult> {\n const now = new Date()\n const { report, failures } = parsed\n\n // Race-safe duplicate detection — let the unique index on\n // (reportId, orgName) decide. The prior findOne→insertOne split admitted\n // a window where two concurrent uploads of the same report could both\n // succeed.\n let duplicate = false\n try {\n await ctx.collections.dmarcReports.insertOne({ ...report, receivedAt: now })\n } catch (err: any) {\n if (err?.code === 11000) {\n duplicate = true\n } else {\n throw err\n }\n }\n\n if (!duplicate && failures.length > 0) {\n // Idempotent: unique index on (reportId, sourceIp) — duplicates skipped.\n // BulkWriteError mixes real + duplicate-key errors; inspect each write\n // error and rethrow if any aren't 11000.\n try {\n await ctx.collections.dmarcFailures.insertMany(\n failures.map((f) => ({ ...f, receivedAt: now })),\n { ordered: false },\n )\n } catch (err: any) {\n const writeErrors: Array<{ code?: number }> | undefined = err?.writeErrors\n if (Array.isArray(writeErrors)) {\n const nonDup = writeErrors.find((w) => w?.code !== 11000)\n if (nonDup) throw err\n } else if (err?.code !== 11000) {\n throw err\n }\n }\n }\n\n return {\n ok: true,\n reportId: report.reportId,\n domain: report.domain,\n rangeStart: report.rangeStart,\n rangeEnd: report.rangeEnd,\n totalMessages: report.totalMessages,\n passCount: report.passCount,\n failCount: report.failCount,\n duplicate,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Retention\n// ---------------------------------------------------------------------------\n\n// Throttle DMARC prune so it doesn't fire on every tick (60s default). Once\n// per hour is plenty — failure rows live for retentionDays (default 90).\nlet _lastPruneAt = 0\nconst PRUNE_INTERVAL_MS = 60 * 60 * 1000\n\nexport async function pruneDmarcFailures(ctx: RunnerContext, opts: { force?: boolean } = {}): Promise<number> {\n const cfg = ctx.config.dmarc\n const days = cfg?.retentionDays ?? 90\n if (days <= 0) return 0\n if (!opts.force && Date.now() - _lastPruneAt < PRUNE_INTERVAL_MS) return 0\n _lastPruneAt = Date.now()\n const cutoff = new Date(Date.now() - days * 86_400_000)\n const r = await ctx.collections.dmarcFailures.deleteMany({ receivedAt: { $lt: cutoff } })\n return r.deletedCount ?? 0\n}\n\n// ---------------------------------------------------------------------------\n// Source tags — merge config-defined + db-defined\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedSourceTag {\n ip: string\n label: string\n ignored: boolean\n /** 'config' = read-only (set in MailerConfig), 'db' = mutable from UI. */\n source: 'config' | 'db'\n}\n\nexport async function resolveSourceTags(ctx: RunnerContext): Promise<Map<string, ResolvedSourceTag>> {\n const out = new Map<string, ResolvedSourceTag>()\n for (const t of ctx.config.dmarc?.knownSources ?? []) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: !!t.ignored, source: 'config' })\n }\n // DB tags override config tags so the operator can re-label without redeploy.\n const dbTags = await ctx.collections.dmarcSourceTags.find({}).toArray()\n for (const t of dbTags) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: t.ignored, source: 'db' })\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Policy progression suggestion\n// ---------------------------------------------------------------------------\n\nexport interface DomainProgression {\n domain: string\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n /** null when no suggestion (already at strictest, or insufficient data). */\n suggested: { policy: 'none' | 'quarantine' | 'reject'; pct: number; reason: string } | null\n}\n\n/**\n * Heuristic: walk through the DMARC ramp progression.\n * p=none → suggest p=quarantine pct=10 when last 30d alignment ≥99%\n * from non-ignored sources AND ≥30 reports AND ≥1k messages\n * p=quarantine pct<100 → ramp pct (10→25→50→100) when alignment stays high\n * p=quarantine pct=100 → suggest p=reject when alignment ≥99.9% for 14+ days\n * p=reject → no suggestion (already at strictest)\n *\n * Pure function so it's easy to unit-test.\n */\nexport interface ProgressionInput {\n reports: Array<{ rangeEnd: Date; passCount: number; failCount: number }>\n failures: Array<{ sourceIp: string; count: number; receivedAt: Date }>\n knownSourceIps: Set<string>\n ignoredSourceIps: Set<string>\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n}\n\nexport function suggestPolicyProgression(input: ProgressionInput): DomainProgression['suggested'] {\n const { reports, failures, knownSourceIps, ignoredSourceIps, currentPolicy, currentPct } = input\n\n if (currentPolicy === 'reject') return null\n\n const since30 = Date.now() - 30 * 86_400_000\n const recentReports = reports.filter((r) => r.rangeEnd.getTime() >= since30)\n const totalMsgs = recentReports.reduce((acc, r) => acc + r.passCount + r.failCount, 0)\n const totalPass = recentReports.reduce((acc, r) => acc + r.passCount, 0)\n\n if (recentReports.length < 30) return null\n if (totalMsgs < 1000) return null\n\n // Failures from untagged (and non-ignored) sources mean we don't yet know\n // who they are — never tighten policy until they're identified.\n const untaggedFailures = failures.filter(\n (f) => f.receivedAt.getTime() >= since30 && !knownSourceIps.has(f.sourceIp) && !ignoredSourceIps.has(f.sourceIp),\n )\n if (untaggedFailures.length > 0) return null\n\n const alignmentRate = totalMsgs === 0 ? 0 : totalPass / totalMsgs\n\n if (currentPolicy === null || currentPolicy === 'none') {\n if (alignmentRate >= 0.99) {\n return {\n policy: 'quarantine',\n pct: 10,\n reason: `${(alignmentRate * 100).toFixed(2)}% alignment over ${recentReports.length} reports / ${totalMsgs.toLocaleString()} messages, all known sources tagged.`,\n }\n }\n return null\n }\n\n if (currentPolicy === 'quarantine') {\n const pct = currentPct ?? 100\n if (alignmentRate < 0.995) return null\n if (pct < 25) return { policy: 'quarantine', pct: 25, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 25.` }\n if (pct < 50) return { policy: 'quarantine', pct: 50, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 50.` }\n if (pct < 100) return { policy: 'quarantine', pct: 100, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 100.` }\n\n // pct=100 + alignment ≥99.9% for 14+ days → suggest reject\n if (alignmentRate >= 0.999) {\n return { policy: 'reject', pct: 100, reason: `Alignment at ${(alignmentRate * 100).toFixed(3)}% with policy=quarantine pct=100 — safe to move to p=reject.` }\n }\n }\n\n return null\n}\n","/**\n * The mailer:tick handler. Orchestrates all the periodic work that doesn't\n * fit a delayed-job model: event-trigger scanning, recovery sweep,\n * scheduled-broadcast dispatch, outbox draining, rollups.\n */\n\nimport { processNewlyFiredEventTriggers } from './triggers.js'\nimport { processWebhookBacklog } from './webhook.js'\nimport { sweepStrandedFlowRuns } from './sweep.js'\nimport { processScheduledBroadcasts as dispatchScheduled, resumeStalledBroadcasts } from './broadcasts.js'\nimport { evaluateHealth } from './health.js'\nimport { promoteSoftBounces } from './bounce-promotion.js'\nimport { runDnsblChecks } from './dnsbl.js'\nimport { runPostmasterPull } from './postmaster.js'\nimport { runSndsPull } from './snds.js'\nimport { pruneDmarcFailures } from './dmarc.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Sends that entered the 'sending' state more than this long ago are assumed\n * to have been abandoned mid-dispatch (worker crash, OOM kill, ...). The tick\n * resets them to 'queued' and re-enqueues. Providers should treat the sendId\n * (passed in messageMeta) as an idempotency key to avoid duplicate delivery on\n * the rare case where the original call did reach the provider.\n */\nconst STRANDED_SEND_THRESHOLD_MS = 5 * 60 * 1000\n\n/**\n * Webhook events older than this and still unprocessed are assumed stranded\n * (the ingest-time queue add failed). The tick drains them; fresher rows are\n * left to the webhook worker to avoid racing it in the normal path.\n */\nconst STRANDED_WEBHOOK_THRESHOLD_MS = 5 * 60 * 1000\n\nexport async function runTick(ctx: RunnerContext): Promise<void> {\n // Heartbeat: ensure the aggregate health doc exists with an up-to-date\n // `updatedAt` so the setup-status check can detect \"workers are running.\"\n // Wrapped in try/catch — a Mongo blip should never abort the whole tick.\n try {\n await ctx.collections.health.updateOne(\n { _id: HEALTH_AGG_ID },\n {\n $set: { updatedAt: new Date() },\n $setOnInsert: {\n _id: HEALTH_AGG_ID,\n senderDomain: null,\n kind: null,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n console.error('mailery: heartbeat write failed', err)\n }\n\n // Core runners: order matters (sweep before send dispatch, drain outbox\n // before triggers re-scan, etc). Keep these serial.\n await processNewlyFiredEventTriggers(ctx).catch((err) => {\n console.error('mailery: triggers scan failed', err)\n })\n await sweepStrandedFlowRuns(ctx).catch((err) => {\n console.error('mailery: sweep failed', err)\n })\n await sweepStrandedSends(ctx).catch((err) => {\n console.error('mailery: stranded-send sweep failed', err)\n })\n await drainOutbox(ctx).catch((err) => {\n console.error('mailery: outbox drain failed', err)\n })\n await processScheduledBroadcasts(ctx).catch((err) => {\n console.error('mailery: broadcast dispatch failed', err)\n })\n await resumeStalledBroadcasts(ctx).catch((err) => {\n console.error('mailery: stalled-broadcast resume failed', err)\n })\n await evaluateHealth(ctx).catch((err) => {\n console.error('mailery: health evaluation failed', err)\n })\n await promoteSoftBounces(ctx).catch((err) => {\n console.error('mailery: soft-bounce promotion failed', err)\n })\n await processWebhookBacklog(ctx, { olderThanMs: STRANDED_WEBHOOK_THRESHOLD_MS }).catch((err) => {\n console.error('mailery: stranded-webhook drain failed', err)\n })\n\n // Independent reputation pollers + housekeeping — run in parallel so tick\n // latency is max() not sum(). Each is already throttled internally and\n // catches its own errors.\n await Promise.all([\n runDnsblChecks(ctx).catch((err) => {\n console.error('mailery: dnsbl checks failed', err)\n }),\n runPostmasterPull(ctx).catch((err) => {\n console.error('mailery: postmaster pull failed', err)\n }),\n runSndsPull(ctx).catch((err) => {\n console.error('mailery: snds pull failed', err)\n }),\n pruneDmarcFailures(ctx).catch((err) => {\n console.error('mailery: dmarc prune failed', err)\n }),\n ])\n}\n\n/**\n * Find sends stuck in 'sending' past the threshold (crashed mid-dispatch) and\n * re-enqueue them. Returning to 'queued' lets `dispatchSend` pick them back up.\n */\nasync function sweepStrandedSends(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STRANDED_SEND_THRESHOLD_MS)\n const cursor = ctx.collections.sends.find(\n { status: 'sending', updatedAt: { $lt: cutoff } },\n { projection: { _id: 1 } },\n ).limit(500)\n for await (const row of cursor) {\n const reset = await ctx.collections.sends.updateOne(\n { _id: row._id, status: 'sending', updatedAt: { $lt: cutoff } },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n if (reset.modifiedCount === 0) continue\n await ctx.queues.send.add('send', { sendId: String(row._id) }, {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n })\n }\n}\n\n/**\n * Pull pending outbox rows committed by host transactions and promote them\n * into the real collections (events / subscriptions / suppressions).\n */\nasync function drainOutbox(ctx: RunnerContext): Promise<void> {\n const batch = await ctx.collections.outbox\n .find({ status: 'pending' })\n .sort({ enqueuedAt: 1 })\n .limit(200)\n .toArray()\n\n for (const row of batch) {\n try {\n if (row.payload.type === 'event') {\n try {\n await ctx.collections.events.insertOne({\n externalId: row.payload.data.externalId as string,\n name: row.payload.data.name as string,\n properties: (row.payload.data.properties as Record<string, unknown>) ?? {},\n dedupeKey: row.payload.dedupeKey,\n occurredAt: (row.payload.data.occurredAt as Date | undefined) ?? new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n { $set: { status: 'processed', processedAt: new Date() } },\n )\n } catch (err: any) {\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n {\n $set: { lastAttemptAt: new Date(), lastError: String(err?.message ?? err) },\n $inc: { attempts: 1 },\n },\n )\n }\n }\n}\n\n/**\n * Claim broadcasts whose `scheduledAt` has passed and hand their recipient\n * enqueue to an advance job (inline for the noop driver), so a large\n * broadcast never blocks the tick. The dispatch itself streams the segment\n * cursor and bulk-enqueues sends, pausing when the send queue's waiting\n * count exceeds the configured cap (broadcastEnqueueMaxWaiting).\n */\nasync function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n await dispatchScheduled(ctx)\n}\n","/**\n * Mailer — public facade. Hosts call `Mailer.init(config)` and get an object\n * exposing the public API (fire, upsertSubscription, unsubscribe, ...) plus\n * mountable Express routers.\n *\n * See plans/10-public-api.md for the surface.\n */\n\nimport type { Db, ClientSession, ObjectId } from 'mongodb'\nimport { ObjectId as ObjectIdCtor } from 'mongodb'\n\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport {\n abortAllFlowsInputSchema,\n abortFlowInputSchema,\n fireInputSchema,\n registerEventSchema,\n sendOneOffInputSchema,\n suppressInputSchema,\n tagInputSchema,\n unsubscribeInputSchema,\n upsertSubscriptionSchema,\n type FireInput,\n type RegisterEventInput,\n type SendOneOffInput,\n type SuppressInput,\n type TagInput,\n type UnsubscribeInput,\n type UpsertSubscriptionInput,\n} from '../shared/schemas.js'\nimport { resolveConfig, type MailerConfig, type ResolvedConfig } from './config.js'\nimport {\n ensureIndexes,\n getCollections,\n} from './models/index.js'\nimport type { Collections } from './models/index.js'\nimport { EventRegistry } from './events.js'\nimport { sha256Hex, signDoiToken } from './tokens.js'\nimport {\n createQueueDriver,\n type QueueDriver,\n type Queues,\n} from './queues/index.js'\nimport {\n dispatchBroadcastById,\n dispatchSend,\n exitFlowRun,\n processOneRunStep,\n runTick,\n type RunnerContext,\n} from './runner/index.js'\nimport { processWebhookBacklog } from './runner/webhook.js'\n\nexport class Mailer {\n readonly db: Db\n readonly collections: Collections\n readonly adapter: ContactAdapter\n readonly providers: Record<string, MailProvider>\n readonly queues: Queues\n readonly config: ResolvedConfig\n readonly events: EventRegistry\n\n private queueDriver: QueueDriver\n private workersStarted = false\n private runnerContext: RunnerContext\n\n private constructor(args: {\n config: ResolvedConfig\n db: Db\n collections: Collections\n adapter: ContactAdapter\n providers: Record<string, MailProvider>\n queueDriver: QueueDriver\n events: EventRegistry\n }) {\n this.config = args.config\n this.db = args.db\n this.collections = args.collections\n this.adapter = args.adapter\n this.providers = args.providers\n this.queueDriver = args.queueDriver\n this.queues = args.queueDriver.queues\n this.events = args.events\n\n this.runnerContext = {\n db: this.db,\n collections: this.collections,\n adapter: this.adapter,\n varsAdapter: this.config.varsAdapter,\n providers: this.providers,\n queues: this.queues,\n config: this.config,\n handlebarsHelpers: this.config.handlebarsHelpers,\n audit: (entry) => this.audit(entry),\n }\n }\n\n /**\n * Construct a Mailer from environment variables. Reads:\n *\n * MAILER_MONGODB_URI — Mongo connection string (required)\n * MAILER_MONGODB_DB — database name (optional; defaults to the URI default)\n * MAILER_REDIS_URL — Redis connection URL (required)\n * MAILER_QUEUE_PREFIX — Redis key prefix to namespace this instance (optional)\n * MAILER_PUBLIC_URL — base for tracking/unsub URLs (required)\n * MAILER_UNSUBSCRIBE_SECRET — HMAC key (required)\n * MAILER_SENDER_ADDRESS — postal address for CAN-SPAM (optional)\n * MAILER_FROM_NAME / MAILER_FROM_EMAIL\n * MAILER_DEFAULT_PROVIDER — defaults to 'sendgrid' if SENDGRID_API_KEY is set\n * MAILER_SENDGRID_API_KEY / MAILER_SENDGRID_WEBHOOK_KEY\n * MAILER_HOST_USERS_COLLECTION (default 'users')\n * MAILER_HOST_USERS_EMAIL_FIELD (default 'email')\n * MAILER_HOST_USERS_ID_FIELD (default '_id')\n * MAILER_HOST_USERS_TAGS_FIELD\n * MAILER_HOST_USERS_TAGS_WRITABLE — '1' or 'true' to enable\n *\n * For anything beyond this (custom toContact, custom providers, hooks),\n * use the programmatic init.\n */\n static async fromEnv(): Promise<Mailer> {\n const env = process.env\n const required = (k: string) => {\n const v = env[k]\n if (!v) throw new Error(`Mailer.fromEnv: missing env var ${k}`)\n return v\n }\n\n const { MongoClient } = await import('mongodb')\n const mongoClient = await MongoClient.connect(required('MAILER_MONGODB_URI'))\n const db = env.MAILER_MONGODB_DB ? mongoClient.db(env.MAILER_MONGODB_DB) : mongoClient.db()\n\n const { MongoContactAdapter } = await import('./adapters/mongo.js')\n const adapter = new MongoContactAdapter({\n db,\n collection: env.MAILER_HOST_USERS_COLLECTION ?? 'users',\n emailField: env.MAILER_HOST_USERS_EMAIL_FIELD ?? 'email',\n idField: env.MAILER_HOST_USERS_ID_FIELD ?? '_id',\n tagsField: env.MAILER_HOST_USERS_TAGS_FIELD,\n tagsWritable:\n env.MAILER_HOST_USERS_TAGS_WRITABLE === '1' || env.MAILER_HOST_USERS_TAGS_WRITABLE === 'true',\n })\n\n const providers: Record<string, MailProvider> = {}\n if (env.MAILER_SENDGRID_API_KEY) {\n const { SendGridProvider } = await import('./providers/sendgrid.js')\n providers.sendgrid = new SendGridProvider({\n apiKey: env.MAILER_SENDGRID_API_KEY,\n webhookVerificationKey: env.MAILER_SENDGRID_WEBHOOK_KEY,\n sandbox: env.NODE_ENV !== 'production',\n })\n }\n if (Object.keys(providers).length === 0) {\n throw new Error('Mailer.fromEnv: no provider configured (set MAILER_SENDGRID_API_KEY, ...)')\n }\n\n const defaultProvider = env.MAILER_DEFAULT_PROVIDER ?? Object.keys(providers)[0]!\n\n const driverEnv = env.MAILER_QUEUE_DRIVER ?? 'bull'\n const queue =\n driverEnv === 'agenda'\n ? ({ driver: 'agenda' as const })\n : driverEnv === 'noop'\n ? ({ driver: 'noop' as const })\n : ({\n driver: 'bull' as const,\n redis: { url: required('MAILER_REDIS_URL') },\n prefix: env.MAILER_QUEUE_PREFIX,\n })\n\n return Mailer.init({\n db,\n adapter,\n queue,\n providers,\n defaultProvider,\n publicUrl: required('MAILER_PUBLIC_URL'),\n unsubscribeSecret: required('MAILER_UNSUBSCRIBE_SECRET'),\n senderAddress: env.MAILER_SENDER_ADDRESS,\n fromDefaults:\n env.MAILER_FROM_NAME && env.MAILER_FROM_EMAIL\n ? { name: env.MAILER_FROM_NAME, email: env.MAILER_FROM_EMAIL }\n : undefined,\n })\n }\n\n static async init(input: MailerConfig): Promise<Mailer> {\n const config = resolveConfig(input)\n if (!config.providers[config.defaultProvider]) {\n throw new Error(`defaultProvider \"${config.defaultProvider}\" not in providers map`)\n }\n if (config.varsAdapter) {\n const { assertNoReservedVarKeys } = await import('./adapters/vars.js')\n assertNoReservedVarKeys(config.varsAdapter)\n }\n\n const collections = getCollections(config.db, config.collectionPrefix)\n await ensureIndexes(config.db, config.collectionPrefix)\n\n const queueDriver = await createQueueDriver(config.queue, config.db)\n if (!config.workerless && config.queue.driver !== 'noop') {\n await queueDriver.scheduleRepeatingTick(config.tickIntervalSeconds)\n }\n\n return new Mailer({\n config,\n db: config.db,\n collections,\n adapter: config.adapter,\n providers: config.providers,\n queueDriver,\n events: new EventRegistry(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Event registration + firing\n // -------------------------------------------------------------------------\n\n registerEvent(reg: RegisterEventInput): void {\n const parsed = registerEventSchema.parse(reg)\n this.events.register(parsed)\n }\n\n async fire(\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(\n `fire(\"${input.eventName}\") missing dedupeKey and no policy registered. ` +\n `Call mailer.registerEvent(\"${input.eventName}\", { dedupePolicy }) or pass a key explicitly.`,\n )\n }\n try {\n await this.collections.events.insertOne({\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n dedupeKey: key,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // Duplicate dedupeKey — no-op by design.\n }\n }\n\n async fireFromSession(\n session: ClientSession,\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(`fireFromSession(\"${input.eventName}\") missing dedupeKey and no policy registered.`)\n }\n try {\n await this.collections.outbox.insertOne(\n {\n payload: {\n type: 'event',\n data: {\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n occurredAt: new Date(),\n },\n dedupeKey: key,\n },\n status: 'pending',\n attempts: 0,\n lastAttemptAt: null,\n lastError: null,\n enqueuedAt: new Date(),\n processedAt: null,\n },\n { session },\n )\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n\n // -------------------------------------------------------------------------\n // Subscription / unsubscribe / tags / suppression\n // -------------------------------------------------------------------------\n\n async upsertSubscription(input: UpsertSubscriptionInput): Promise<void> {\n const parsed = upsertSubscriptionSchema.parse(input)\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`adapter has no contact for externalId ${parsed.externalId}`)\n\n const status = this.config.requireDoubleOptIn ? 'pending_doi' : 'subscribed'\n const now = new Date()\n\n // Generate a DOI token up front when DOI is required. We store its hash\n // (not the raw token) on the subscription doc for audit.\n let doiToken: string | null = null\n let doiTokenHash: string | null = null\n if (status === 'pending_doi') {\n const expiresAt = new Date(now.getTime() + this.config.doiTokenLifetimeDays * 86_400_000)\n doiToken = signDoiToken({ externalId: parsed.externalId, expiresAt }, this.config.unsubscribeSecret)\n doiTokenHash = sha256Hex(doiToken)\n }\n\n await this.collections.subscriptions.updateOne(\n { externalId: parsed.externalId },\n {\n $set: {\n status,\n source: parsed.source,\n emailAtSubscribe: contact.email,\n subscribedAt: status === 'subscribed' ? (parsed.consentTimestamp ?? now) : null,\n updatedAt: now,\n ...(doiTokenHash ? { doiTokenHash, doiRequestedAt: now } : {}),\n },\n $setOnInsert: {\n externalId: parsed.externalId,\n createdAt: now,\n unsubscribedAt: null,\n unsubscribeReason: null,\n doiTokenHash: null,\n doiRequestedAt: null,\n doiConfirmedAt: null,\n doiIp: parsed.consentIp ?? null,\n doiUserAgent: parsed.consentUserAgent ?? null,\n },\n },\n { upsert: true },\n )\n\n // Send the DOI confirmation email (best-effort — failures here don't\n // unwind the subscription; the host can poll pending DOI rows + re-fire).\n if (status === 'pending_doi' && doiToken) {\n const tpl = await this.collections.templates.findOne({ slug: this.config.doiTemplateSlug })\n if (!tpl) {\n console.warn(`mailery: DOI required but template \"${this.config.doiTemplateSlug}\" not found — skipping confirmation email`)\n return\n }\n const dedupeKey = `doi:${parsed.externalId}:${now.toISOString().slice(0, 10)}`\n try {\n await this.sendOneOff({\n templateSlug: tpl.slug,\n externalId: parsed.externalId,\n vars: { confirmDoiUrl: `${this.config.publicUrl}/m/confirm-doi/${doiToken}` },\n dedupeKey,\n })\n } catch (err) {\n console.error('mailery: DOI confirmation send failed', err)\n }\n }\n }\n\n async unsubscribe(email: string, opts: Omit<UnsubscribeInput, 'email'>): Promise<void> {\n const parsed = unsubscribeInputSchema.parse({ email, ...opts })\n const normalized = parsed.email\n const now = new Date()\n\n await this.collections.suppressions.updateOne(\n { email: normalized, scope: parsed.scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope: parsed.scope,\n // mailer_suppressions canonical reason — see plans/02-data-model.md.\n reason: 'unsubscribed' as const,\n source: parsed.source,\n notes: parsed.notes ?? null,\n addedAt: now,\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await this.collections.subscriptions.updateOne(\n { emailAtSubscribe: normalized },\n {\n $set: {\n status: 'unsubscribed' as const,\n unsubscribedAt: now,\n unsubscribeReason: parsed.reason,\n updatedAt: now,\n },\n },\n )\n }\n\n async suppress(email: string, opts: Omit<SuppressInput, 'email'>): Promise<void> {\n const parsed = suppressInputSchema.parse({ email, ...opts })\n await this.collections.suppressions.updateOne(\n { email: parsed.email, scope: parsed.scope },\n {\n $setOnInsert: {\n email: parsed.email,\n emailHash: sha256Hex(parsed.email),\n scope: parsed.scope,\n reason: parsed.reason,\n source: parsed.source,\n notes: parsed.notes ?? null,\n addedAt: new Date(),\n expiresAt: parsed.expiresAt ?? null,\n },\n },\n { upsert: true },\n )\n }\n\n async tag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.addTags) {\n await this.adapter.addTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.updateOne(\n { externalId: parsed.externalId, tag: parsed.tag },\n {\n $setOnInsert: {\n externalId: parsed.externalId,\n tag: parsed.tag,\n appliedBy: 'admin',\n appliedAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n }\n\n async untag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.removeTags) {\n await this.adapter.removeTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.deleteOne({ externalId: parsed.externalId, tag: parsed.tag })\n }\n }\n\n // -------------------------------------------------------------------------\n // Flow abort\n // -------------------------------------------------------------------------\n\n /**\n * Abort every active run of one flow for a contact, immediately. Runs parked\n * in a `wait` exit too — their delayed wake-up jobs find the run exited and\n * no-op. Also cancels any of the flow's emails still sitting in the send\n * queue for this contact (queued or awaiting retry), so an abort means no\n * further mail, not just no further steps.\n *\n * No-op (returns zero counts) when nothing is active. Safe to call from the\n * same handler that processes the business event (\"user upgraded\").\n */\n async abortFlow(\n flowSlug: string,\n externalId: string,\n opts: { reason?: string; matchTriggerProperties?: Record<string, unknown> } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortFlowInputSchema.parse({\n flowSlug,\n externalId,\n reason: opts.reason,\n matchTriggerProperties: opts.matchTriggerProperties,\n })\n const flow = await this.collections.flows.findOne(\n { slug: parsed.flowSlug },\n { projection: { _id: 1 } },\n )\n if (!flow) throw new Error(`abortFlow: unknown flow slug \"${parsed.flowSlug}\"`)\n\n // Dotted paths so the match is against individual trigger properties; a\n // nested-object equality would demand the whole properties bag match.\n const triggerMatch = Object.fromEntries(\n Object.entries(parsed.matchTriggerProperties ?? {}).map(([k, v]) => [\n `triggerEvent.properties.${k}`,\n v,\n ]),\n )\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId, flowId: flow._id!, ...triggerMatch },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort',\n resource: { collection: 'mailer_flow_runs', slug: parsed.flowSlug },\n // Record the scope: without it a one-account abort and an abort-every-\n // run-for-this-contact are indistinguishable in the audit trail.\n diffSummary: `abortFlow slug=${parsed.flowSlug} externalId=${parsed.externalId} scope=${\n parsed.matchTriggerProperties ? JSON.stringify(parsed.matchTriggerProperties) : 'all'\n } runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n /**\n * Abort every active flow run for a contact across all flows. Same semantics\n * as `abortFlow` — for \"stop everything\" events (account deleted, churned).\n */\n async abortAllFlows(\n externalId: string,\n opts: { reason?: string } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortAllFlowsInputSchema.parse({ externalId, reason: opts.reason })\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort_all',\n resource: { collection: 'mailer_flow_runs' },\n diffSummary: `abortAllFlows externalId=${parsed.externalId} runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n private async abortActiveRuns(\n // Open-ended extra keys carry caller-supplied dotted paths (e.g.\n // 'triggerEvent.properties.accountId') straight into the run query.\n filter: { externalId: string; flowId?: ObjectId } & Record<string, unknown>,\n exitReason: string,\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const runs = await this.collections.flowRuns\n .find({ ...filter, status: 'active' })\n .toArray()\n if (runs.length === 0) return { abortedRuns: 0, cancelledSends: 0 }\n\n for (const run of runs) {\n await exitFlowRun(run, exitReason, this.runnerContext)\n }\n\n // Exiting the runs stops future steps; this stops mail already produced by\n // past send steps but not yet dispatched (provider retry backoff, tripped\n // circuit breaker, stranded-send sweep). 'failed' is included because the\n // send queue re-dispatches failed sends on retry.\n const cancelled = await this.collections.sends.updateMany(\n { flowRunId: { $in: runs.map((r) => r._id!) }, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${exitReason}`, updatedAt: new Date() } },\n )\n\n return { abortedRuns: runs.length, cancelledSends: cancelled.modifiedCount }\n }\n\n /**\n * GDPR right-to-erasure. Hard-deletes the contact's PII and leaves a hashed\n * suppression row to block re-import. INVARIANT 9.\n */\n async forget(externalId: string): Promise<void> {\n const sub = await this.collections.subscriptions.findOne({ externalId })\n const email = sub?.emailAtSubscribe?.toLowerCase()\n\n const collected = await Promise.all([\n this.collections.sends.find({ externalId }).map((s) => s.emailAtSend).toArray(),\n ])\n const emails = new Set<string>()\n if (email) emails.add(email)\n for (const e of collected[0]) if (e) emails.add(e.toLowerCase())\n\n await Promise.all([\n this.collections.events.deleteMany({ externalId }),\n this.collections.flowRuns.deleteMany({ externalId }),\n this.collections.sends.deleteMany({ externalId }),\n this.collections.subscriptions.deleteMany({ externalId }),\n this.collections.contactTags.deleteMany({ externalId }),\n ])\n if (email) {\n await this.collections.leads.deleteMany({ email })\n }\n\n for (const e of emails) {\n await this.collections.suppressions.updateOne(\n { emailHash: sha256Hex(e), scope: 'all' },\n {\n $setOnInsert: {\n email: null,\n emailHash: sha256Hex(e),\n scope: 'all',\n reason: 'gdpr_forget',\n source: 'gdpr_request',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n }\n\n await this.audit({\n actor: 'system:gdpr',\n action: 'gdpr.forget',\n resource: { collection: 'mailer_subscriptions', id: sub?._id },\n diffSummary: `forget externalId=${externalId}`,\n })\n }\n\n /** GDPR data export. JSON-serializable. */\n async exportContactData(externalId: string): Promise<Record<string, unknown>> {\n const subscription = await this.collections.subscriptions.findOne({ externalId })\n const [events, flowRuns, sends, suppressions, tags] = await Promise.all([\n this.collections.events.find({ externalId }).toArray(),\n this.collections.flowRuns.find({ externalId }).toArray(),\n this.collections.sends.find({ externalId }).toArray(),\n subscription?.emailAtSubscribe\n ? this.collections.suppressions.find({ email: subscription.emailAtSubscribe }).toArray()\n : Promise.resolve([]),\n this.collections.contactTags.find({ externalId }).toArray(),\n ])\n return { subscription, events, flowRuns, sends, suppressions, tags }\n }\n\n // -------------------------------------------------------------------------\n // One-off transactional send (password reset etc.)\n // -------------------------------------------------------------------------\n\n async sendOneOff(input: SendOneOffInput): Promise<{ sendId: string }> {\n const parsed = sendOneOffInputSchema.parse(input)\n const template = await this.collections.templates.findOne({ slug: parsed.templateSlug })\n if (!template) throw new Error(`template not found: ${parsed.templateSlug}`)\n\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`contact not found: ${parsed.externalId}`)\n\n const dedupeKey = `oneoff:${parsed.dedupeKey}`\n const existing = await this.collections.sends.findOne({ dedupeKey })\n if (existing) return { sendId: String(existing._id) }\n\n const providerName =\n parsed.providerOverride\n ?? template.providerOverride\n ?? (template.kind === 'transactional' ? this.config.defaultTransactionalProvider : null)\n ?? this.config.defaultProvider\n\n const sendId = new ObjectIdCtor()\n try {\n await this.collections.sends.insertOne({\n _id: sendId,\n dedupeKey,\n externalId: parsed.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: null,\n manualSendBy: 'sendOneOff',\n kind: template.kind,\n provider: providerName,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: parsed.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n })\n } catch (err: any) {\n // Concurrent call with the same dedupeKey won the insert — return its id.\n if (err?.code !== 11000) throw err\n const winner = await this.collections.sends.findOne({ dedupeKey })\n if (winner) return { sendId: String(winner._id) }\n throw err\n }\n\n await this.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: this.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n return { sendId: String(sendId) }\n }\n\n // -------------------------------------------------------------------------\n // Audit log helper\n // -------------------------------------------------------------------------\n\n async audit(entry: {\n actor: string\n action: string\n resource: { collection: string; id?: string | ObjectId; slug?: string }\n before?: Record<string, unknown> | null\n after?: Record<string, unknown> | null\n diffSummary?: string\n ip?: string\n userAgent?: string\n requestId?: string\n }): Promise<void> {\n await this.collections.auditLog.insertOne({\n actor: entry.actor,\n action: entry.action,\n resource: entry.resource,\n before: entry.before ?? null,\n after: entry.after ?? null,\n diffSummary: entry.diffSummary ?? null,\n ip: entry.ip ?? null,\n userAgent: entry.userAgent ?? null,\n requestId: entry.requestId ?? null,\n occurredAt: new Date(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Workers\n // -------------------------------------------------------------------------\n\n async startWorkers(): Promise<void> {\n if (this.workersStarted) return\n if (this.config.queue.driver === 'noop') {\n throw new Error('startWorkers requires a non-noop queue driver')\n }\n const provider = this.providers[this.config.defaultProvider]\n const sendRate = provider?.sendRatePerSecond ?? this.config.sendRatePerSecond\n\n await this.queueDriver.startWorkers({\n concurrency: { send: this.config.sendConcurrency },\n sendRateLimit: { max: sendRate, durationMs: 1_000 },\n retryAttempts: this.config.sendRetryAttempts,\n handlers: {\n tick: async () => {\n await runTick(this.runnerContext)\n },\n advance: async (data) => {\n if (data.broadcastId) {\n if (!ObjectIdCtor.isValid(data.broadcastId)) return\n await dispatchBroadcastById(new ObjectIdCtor(data.broadcastId), this.runnerContext)\n return\n }\n if (!data.flowRunId || !ObjectIdCtor.isValid(data.flowRunId)) return\n await processOneRunStep(new ObjectIdCtor(data.flowRunId), this.runnerContext)\n },\n send: async (data) => {\n if (!ObjectIdCtor.isValid(data.sendId)) return\n await dispatchSend(new ObjectIdCtor(data.sendId), this.runnerContext)\n },\n webhook: async () => {\n await this.processWebhookBacklog()\n },\n },\n })\n this.workersStarted = true\n }\n\n /** Process unprocessed webhook events in mailer_webhook_events. */\n private async processWebhookBacklog(): Promise<void> {\n await processWebhookBacklog(this.runnerContext)\n }\n\n async stop(): Promise<void> {\n await this.queueDriver.close()\n this.workersStarted = false\n }\n\n /** Used internally by the admin router and tests; not part of the public API. */\n getRunnerContext(): RunnerContext {\n return this.runnerContext\n }\n}\n","/**\n * Public exports for the `mailery` package.\n */\n\ndeclare const __PKG_VERSION__: string | undefined\n\n/**\n * Library version, stamped from package.json at build time (tsup/vitest\n * `define`). 'dev' when the source runs without a bundler define (plain tsx).\n */\nexport const VERSION = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : 'dev'\n\n// Core\nexport { Mailer } from './mailer.js'\nexport type { MailerConfig, RedisOptions, CircuitBreakerThresholds, SenderDomainConfig, SenderDomainRegistry } from './config.js'\nexport { validateSenderDomain } from './templates/sender-domain.js'\nexport type { SenderDomainValidation } from './templates/sender-domain.js'\n\n// Adapters\nexport { MongoContactAdapter } from './adapters/mongo.js'\nexport type { MongoContactAdapterOptions } from './adapters/mongo.js'\nexport { defineVars, varsJsonSchema, RESERVED_VAR_KEYS } from './adapters/vars.js'\nexport type { VarsAdapter, VarsResolveInfo } from './adapters/vars.js'\n\n// Providers\nexport { NullProvider } from './providers/null.js'\nexport { SendGridProvider } from './providers/sendgrid.js'\nexport type { SendGridProviderOptions } from './providers/sendgrid.js'\n\n// HTTP routers\nexport { createAdminRouter } from './api/admin.js'\nexport type { AdminRouterOptions } from './api/admin.js'\nexport { createPublicRouter } from './api/public.js'\nexport type { PublicRouterOptions } from './api/public.js'\n\n// Templates (host apps may want compile + render directly for previews)\nexport {\n compileTemplate,\n compileMailyTemplate,\n derivePlaintext,\n renderTemplate,\n applyTracking,\n} from './templates/render.js'\n\n// Runner internals — exported so test harnesses and advanced hosts can drive\n// the runner inline. In production let `startWorkers()` invoke these.\nexport {\n runTick,\n processOneRunStep,\n dispatchSend,\n applyWebhookEvent,\n processNewlyFiredEventTriggers,\n sweepStrandedFlowRuns,\n} from './runner/index.js'\n\n// Models (collection helpers, in case hosts need to query directly)\nexport { getCollections, ensureIndexes } from './models/index.js'\nexport type {\n Collections,\n SubscriptionDoc,\n EventDoc,\n FlowDoc,\n FlowRunDoc,\n TemplateDoc,\n SendDoc,\n SuppressionDoc,\n BroadcastDoc,\n AuditLogDoc,\n WebhookEventDoc,\n HealthDoc,\n ContactTagDoc,\n LeadDoc,\n OutboxDoc,\n FlowVersionDoc,\n TemplateVersionDoc,\n} from './models/index.js'\n\n// Token helpers (rarely needed by hosts, useful for tests)\nexport { signUnsubscribeToken, verifyUnsubscribeToken, sha256Hex } from './tokens.js'\n\n// Shared types\nexport { computeDeliveryTime } from './runner/delivery-window.js'\n\nexport type {\n Contact,\n ContactAdapter,\n AdapterFilter,\n DeliveryWindow,\n MailProvider,\n SendArgs,\n SendResult,\n NormalizedEvent,\n FlowStep,\n Predicate,\n SegmentDefinition,\n SegmentFilter,\n} from '../shared/types.js'\n\nexport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../shared/enums.js'\n\n// Option lists for tooling / admin UIs — flow step kinds, predicate kinds,\n// segment filter kinds, dedupe policies.\nexport {\n FLOW_STEP_KINDS,\n defaultFlowStep,\n PREDICATE_KINDS,\n defaultPredicate,\n predicateKind,\n SEGMENT_FILTER_KINDS,\n defaultSegmentFilter,\n DEDUPE_POLICIES,\n} from '../shared/options.js'\nexport type {\n FlowStepKindOption,\n PredicateKindOption,\n PredicateKind,\n SegmentFilterKindOption,\n SegmentFilterKind,\n DedupePolicyOption,\n} from '../shared/options.js'\n","/**\n * NullProvider — in-memory provider for tests and dev. Records every send\n * without dispatching anything. Inspect `.sent` to assert what would have\n * been delivered.\n */\n\nimport type { MailProvider, NormalizedEvent, SendArgs, SendResult } from '../../shared/types.js'\n\nlet counter = 0\n\nexport class NullProvider implements MailProvider {\n readonly name = 'null'\n readonly sendRatePerSecond = 1000\n public readonly sent: SendArgs[] = []\n\n async send(args: SendArgs): Promise<SendResult> {\n this.sent.push(args)\n return {\n providerId: `null-${Date.now()}-${++counter}`,\n status: 'accepted',\n }\n }\n\n async verifyWebhook(): Promise<boolean> {\n return true\n }\n\n parseWebhookEvents(): NormalizedEvent[] {\n return []\n }\n\n reset(): void {\n this.sent.length = 0\n }\n}\n","/**\n * Content linter for email templates. Pure function — no I/O.\n *\n * const result = lintTemplate(input, { senderDomains })\n * if (result.errors.length) refuse to publish\n *\n * The publish endpoint runs this as a gate. The editor will eventually run it\n * live for inline squiggles (PR10) — same engine, same rules.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { SenderDomainRegistry } from './sender-domain.js'\nimport { validateSenderDomain } from './sender-domain.js'\n\nexport type LintSeverity = 'error' | 'warning' | 'info'\n\nexport interface LintIssue {\n /** Stable rule identifier, e.g. 'missing_plain_text'. */\n rule: string\n severity: LintSeverity\n message: string\n /** Optional remediation hint shown in tooltips/expanders. */\n hint?: string\n}\n\nexport interface LintResult {\n errors: LintIssue[]\n warnings: LintIssue[]\n infos: LintIssue[]\n}\n\nexport interface LintInput {\n subject: string\n preheader: string\n /** MJML source, when authored that way. Empty string when authored via Maily. */\n mjml: string\n /**\n * Maily editor JSON source, when authored that way. Optional — passing it\n * helps rules that scan for merge tags survive HTML-encoding of braces\n * in body text.\n */\n editorJson?: unknown\n /** Rendered HTML. */\n html: string\n /** Rendered plain-text alternative. */\n plainText: string\n kind: TemplateKind\n fromEmail: string\n}\n\nexport interface LintConfig {\n senderDomains?: SenderDomainRegistry\n /**\n * JSON Schema of the host's varsAdapter (see `varsJsonSchema`). When set,\n * `{{paths}}` in subject/preheader/MJML/editorJson that don't exist in the\n * schema (or the built-in keys) are flagged as `unknown_variable` warnings.\n */\n varsJsonSchema?: Record<string, unknown> | null\n}\n\nconst URL_SHORTENERS = ['bit.ly', 't.co', 'tinyurl.com', 'goo.gl', 'ow.ly']\n\nconst SPAM_PHRASES: Array<{ pattern: RegExp; phrase: string }> = [\n { pattern: /\\bFREE\\b/, phrase: 'FREE' },\n { pattern: /\\bACT NOW\\b/i, phrase: 'ACT NOW' },\n { pattern: /\\b100%\\s+guaranteed\\b/i, phrase: '100% guaranteed' },\n]\n\nconst MARKETING_UNSUBSCRIBE_TAG = /\\{\\{\\s*unsubscribeUrl\\s*\\}\\}/\n\nexport function lintTemplate(rawInput: LintInput, config: LintConfig = {}): LintResult {\n // Coerce missing/undefined fields so downstream `.length` / `.test()`\n // calls don't throw. The publish path can hand us a draft with an\n // undefined subject, and we'd rather lint it (and emit a length warning)\n // than 500.\n const input: LintInput = {\n subject: typeof rawInput.subject === 'string' ? rawInput.subject : '',\n preheader: typeof rawInput.preheader === 'string' ? rawInput.preheader : '',\n mjml: typeof rawInput.mjml === 'string' ? rawInput.mjml : '',\n editorJson: rawInput.editorJson,\n html: typeof rawInput.html === 'string' ? rawInput.html : '',\n plainText: typeof rawInput.plainText === 'string' ? rawInput.plainText : '',\n kind: rawInput.kind === 'marketing' || rawInput.kind === 'transactional' ? rawInput.kind : 'transactional',\n fromEmail: typeof rawInput.fromEmail === 'string' ? rawInput.fromEmail : '',\n }\n const issues: LintIssue[] = []\n\n // 1. Missing plain-text alternative — error\n if (!input.plainText || input.plainText.trim().length === 0) {\n issues.push({\n rule: 'missing_plain_text',\n severity: 'error',\n message: 'Plain-text alternative is empty.',\n hint: 'Email clients and spam filters use the plain-text part. Add visible text content (MJML mj-text blocks, or text content in the Maily editor) — do not strip plain-text to empty.',\n })\n }\n\n // 2. Image-only body — error\n const imageCount = countMatches(input.html, /<img\\b/gi)\n const textLen = input.plainText.trim().length\n if (imageCount >= 1 && textLen < 20) {\n issues.push({\n rule: 'image_only_body',\n severity: 'error',\n message: 'Body is mostly images with little or no text.',\n hint: 'Image-only emails are heavily filtered as spam. Add at least one paragraph of meaningful text.',\n })\n }\n\n // 3. URL shortener — error\n const shortenerLinks = findShortenerLinks(input.html)\n if (shortenerLinks.length > 0) {\n issues.push({\n rule: 'url_shortener',\n severity: 'error',\n message: `Link uses a URL shortener: ${shortenerLinks.join(', ')}.`,\n hint: 'URL shorteners are strongly correlated with spam and are routinely blocked. Use a direct link to your domain.',\n })\n }\n\n // 4. Bare URL in body — warning\n if (hasBareUrlInVisibleText(input.html)) {\n issues.push({\n rule: 'bare_url',\n severity: 'warning',\n message: 'A URL appears in the body text without being wrapped in a link.',\n hint: 'Wrap visible URLs in an anchor tag — bare URLs look like spam template residue and reduce engagement.',\n })\n }\n\n // 5. Spammy phrases — warning (check both subject and plainText)\n const spam = findSpamSignals(`${input.subject}\\n${input.plainText}`)\n if (spam.length > 0) {\n issues.push({\n rule: 'spam_phrases',\n severity: 'warning',\n message: `Content contains spam-flagged phrases: ${spam.join(', ')}.`,\n hint: 'These phrases trigger content filters. Rephrase if possible.',\n })\n }\n\n // 6. All-caps subject — warning\n if (isAllCaps(input.subject)) {\n issues.push({\n rule: 'all_caps_subject',\n severity: 'warning',\n message: 'Subject line is mostly uppercase.',\n hint: 'All-caps subjects are flagged by spam filters and reduce click-through. Use sentence case.',\n })\n }\n\n // 7. Missing unsubscribe merge tag (marketing only) — error.\n // Check the raw mjml + editorJson + compiled HTML. @maily-to/render\n // HTML-encodes the `{{ }}` braces when they're placed in body text\n // (not in href), so checking only the rendered html misses legitimate\n // unsubscribe-tag placements.\n if (input.kind === 'marketing') {\n const sources = [input.mjml ?? '', input.html ?? '', JSON.stringify(input.editorJson ?? null)]\n const hasTag = sources.some((s) => MARKETING_UNSUBSCRIBE_TAG.test(s))\n if (!hasTag) {\n issues.push({\n rule: 'missing_unsubscribe_tag',\n severity: 'error',\n message: 'Marketing template is missing the {{unsubscribeUrl}} merge tag.',\n hint: 'CAN-SPAM, GDPR, and Gmail/Yahoo bulk-sender rules all require a working unsubscribe link. Add {{unsubscribeUrl}} somewhere in the body.',\n })\n }\n }\n\n // 8. From-domain mismatch — error (mirrors the publish-time check)\n const senderCheck = validateSenderDomain(input.fromEmail, input.kind, config.senderDomains)\n if (!senderCheck.ok) {\n issues.push({\n rule: 'sender_domain_invalid',\n severity: 'error',\n message: senderCheck.reason,\n hint: 'Edit the template fromEmail to use a domain declared for this kind in senderDomains, or update the registry.',\n })\n }\n\n // 9. Empty preheader — info\n if (!input.preheader || input.preheader.trim().length === 0) {\n issues.push({\n rule: 'empty_preheader',\n severity: 'info',\n message: 'No preheader set.',\n hint: 'The preheader shows next to the subject in most inbox previews. A good preheader lifts open rate 5-10%.',\n })\n }\n\n // 10. Subject too long — warning\n if (input.subject.length > 60) {\n issues.push({\n rule: 'subject_too_long',\n severity: 'warning',\n message: `Subject is ${input.subject.length} characters; mobile clients truncate around 60.`,\n hint: 'Front-load the important words so the truncated preview still makes sense.',\n })\n }\n\n // 11a. Unknown template variables — warning (only when a vars schema is provided)\n if (config.varsJsonSchema) {\n const sources = [input.subject, input.preheader, input.mjml, JSON.stringify(input.editorJson ?? null)]\n const unknown = findUnknownVariables(sources.join('\\n'), config.varsJsonSchema)\n if (unknown.length > 0) {\n issues.push({\n rule: 'unknown_variable',\n severity: 'warning',\n message: `Template references variable(s) not in the vars schema: ${unknown.join(', ')}.`,\n hint: 'These render as empty strings. Check for typos, or add the key to your varsAdapter schema. Paths inside {{#each}}/{{#with}} blocks are relative and not checked.',\n })\n }\n }\n\n // 11. Too many links — warning\n // Match href= with or without surrounding quotes — same shape as\n // extractHrefs above.\n const linkCount = countMatches(input.html, /<a\\s[^>]*\\bhref\\s*=/gi)\n if (linkCount > 10) {\n issues.push({\n rule: 'too_many_links',\n severity: 'warning',\n message: `${linkCount} links in body; promotional content with many links is flagged by content filters.`,\n hint: 'Consolidate calls-to-action. Aim for one primary action plus a footer link or two.',\n })\n }\n\n return splitBySeverity(issues)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction splitBySeverity(issues: LintIssue[]): LintResult {\n const out: LintResult = { errors: [], warnings: [], infos: [] }\n for (const i of issues) {\n if (i.severity === 'error') out.errors.push(i)\n else if (i.severity === 'warning') out.warnings.push(i)\n else out.infos.push(i)\n }\n return out\n}\n\nfunction countMatches(s: string, re: RegExp): number {\n return (s.match(re) ?? []).length\n}\n\nfunction findShortenerLinks(html: string): string[] {\n const hrefs = extractHrefs(html)\n const hits = new Set<string>()\n for (const href of hrefs) {\n const domain = hostnameOf(href)\n if (!domain) continue\n if (URL_SHORTENERS.includes(domain)) hits.add(domain)\n }\n return Array.from(hits)\n}\n\nfunction extractHrefs(html: string): string[] {\n const out: string[] = []\n // Match href values in any of: double-quoted, single-quoted, or\n // unquoted (terminated by space, `>`, or end of tag). Maily-generated\n // HTML mostly quotes but operator-edited MJML may not.\n const re = /<a\\s[^>]*\\bhref\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const href = m[1] ?? m[2] ?? m[3]\n if (href) out.push(href)\n }\n return out\n}\n\nfunction hostnameOf(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase()\n } catch {\n return null\n }\n}\n\n/**\n * Heuristic: strip anchor tags (and their contents), plus `<style>`,\n * `<script>`, and `<head>` blocks before looking for a bare URL. Otherwise\n * URLs in CSS (`@import url(...)`) or scripts trigger a false positive.\n */\nfunction hasBareUrlInVisibleText(html: string): boolean {\n const stripped = html\n .replace(/<a\\b[^>]*>.*?<\\/a>/gis, ' ')\n .replace(/<style\\b[^>]*>.*?<\\/style>/gis, ' ')\n .replace(/<script\\b[^>]*>.*?<\\/script>/gis, ' ')\n .replace(/<head\\b[^>]*>.*?<\\/head>/gis, ' ')\n return /https?:\\/\\/[^\\s<>\"']+/i.test(stripped)\n}\n\nfunction findSpamSignals(text: string): string[] {\n const out = new Set<string>()\n for (const { pattern, phrase } of SPAM_PHRASES) {\n if (pattern.test(text)) out.add(phrase)\n }\n if (/!{3,}/.test(text)) out.add('excessive \"!!!\"')\n return Array.from(out)\n}\n\n// --- unknown_variable helpers ----------------------------------------------\n\n/** Render-context keys mailery provides regardless of the host schema. */\nconst BUILTIN_VAR_ROOTS = new Set([\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n 'this',\n])\n\nconst PATH_TOKEN = /^@?[A-Za-z_][\\w$]*(\\.[A-Za-z_][\\w$]*)*$/\n\n/**\n * Extract `{{ ... }}` expressions and return the dotted paths that cannot be\n * found in the vars JSON Schema. Conservative by design: helper arguments,\n * block-relative paths, and any schema shape we can't confidently walk are\n * treated as valid — a warning here should never be a false alarm the\n * operator has to fight.\n */\nexport function findUnknownVariables(source: string, schema: Record<string, unknown>): string[] {\n // Block helpers introduce relative scopes ({{#each topics}} → {{title}}),\n // so bare single-segment identifiers can't be validated when any exist.\n const hasBlockScopes = /\\{\\{[#^]\\s*(each|with)\\b/.test(source)\n\n const unknown = new Set<string>()\n const re = /\\{\\{\\{?\\s*([^{}]+?)\\s*\\}?\\}\\}/g\n let m: RegExpExecArray | null\n while ((m = re.exec(source))) {\n const expr = m[1]!.trim()\n if (!expr || /^[#^/>!]/.test(expr) || expr === 'else') continue // blocks, partials, comments\n if (expr.includes('(')) continue // subexpressions — too dynamic to check\n\n // Helper call: skip the helper name, validate path-shaped args.\n // Single token: validate it directly.\n const parts = expr.split(/\\s+/)\n const candidates = parts.length > 1 ? parts.slice(1) : parts\n for (const raw of candidates) {\n if (!PATH_TOKEN.test(raw)) continue // quoted strings, numbers, key=val hash args\n if (raw.startsWith('@')) continue // @index, @key, @root\n const segments = raw.split('.')\n if (BUILTIN_VAR_ROOTS.has(segments[0]!)) continue\n if (hasBlockScopes && segments.length === 1) continue // possibly block-relative\n if (!schemaHasPath(schema, segments)) unknown.add(raw)\n }\n }\n return Array.from(unknown)\n}\n\n/**\n * Walk a JSON Schema along `segments`. Returns false only when we positively\n * know the path is absent (an object node with declared properties that lacks\n * the segment and forbids extras). Unions, arrays, open objects → true.\n */\nfunction schemaHasPath(node: unknown, segments: string[]): boolean {\n if (segments.length === 0) return true\n if (!node || typeof node !== 'object') return true // can't tell — accept\n const n = node as Record<string, any>\n\n // Union shapes (zod nullable/optional/union): valid if any branch accepts.\n for (const key of ['anyOf', 'oneOf', 'allOf']) {\n if (Array.isArray(n[key])) {\n return (n[key] as unknown[]).some((branch) => schemaHasPath(branch, segments))\n }\n }\n\n if (Array.isArray(n.type) && n.type.includes('object') && !n.properties) return true\n if (n.type === 'array') {\n if (segments[0] === 'length') return true // {{topics.length}}\n return schemaHasPath(n.items, segments)\n }\n\n const props = n.properties\n if (!props || typeof props !== 'object') return true // not a closed object — accept\n\n const [head, ...rest] = segments\n if (head! in props) return schemaHasPath(props[head!], rest)\n // Segment missing — only reject when the object doesn't allow extras.\n if (n.additionalProperties === undefined || n.additionalProperties === false) return false\n return true\n}\n\nfunction isAllCaps(subject: string): boolean {\n const letters = subject.replace(/[^a-zA-Z]/g, '')\n if (letters.length < 5) return false\n const upper = subject.replace(/[^A-Z]/g, '').length\n return upper / letters.length > 0.5\n}\n","/**\n * Admin router — serves the prebuilt React SPA + REST endpoints the SPA\n * consumes. Mount inside a host Express app, gated by host auth.\n *\n * app.use('/admin/mailer', requireAdmin, createAdminRouter(mailer))\n *\n * REST routes under /api/* are documented in plans/14-admin-api.md.\n */\n\nimport express, { Router, type Request, type Response, type NextFunction } from 'express'\nimport multer from 'multer'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { ObjectId } from 'mongodb'\n\nimport type { Mailer } from '../mailer.js'\nimport {\n applyTracking,\n compileMailyTemplate,\n compileTemplate,\n renderTemplate,\n} from '../templates/render.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { lintTemplate } from '../templates/linter.js'\nimport { resolveVars, varsJsonSchema, RESERVED_VAR_KEYS } from '../adapters/vars.js'\nimport type { Contact } from '../../shared/types.js'\nimport { runSetupChecks } from './setup-status.js'\nimport { sha256Hex, signUnsubscribeToken } from '../tokens.js'\nimport { effectiveOverallStatus } from '../runner/health.js'\nimport { runDnsblChecks } from '../runner/dnsbl.js'\nimport { runPostmasterPull } from '../runner/postmaster.js'\nimport { runSndsPull } from '../runner/snds.js'\nimport { ingestDmarcAttachment, resolveSourceTags, suggestPolicyProgression } from '../runner/dmarc.js'\nimport { computeListHygiene } from '../runner/hygiene.js'\nimport {\n createMailTesterClient,\n evaluateMailTesterGate,\n findCachedScore,\n mailTesterContentKey,\n persistScore,\n type MailTesterClient,\n} from '../runner/mail-tester.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nfunction defaultSpaDir(): string {\n // After tsup build: dist/index.{js,cjs} + dist/admin/spa/. __dirname = dist/.\n return path.resolve(__dirname, 'admin/spa')\n}\n\nexport interface AdminRouterOptions {\n /** Override path to the built SPA. Defaults to `dist/admin/spa` shipped with the package. */\n spaDir?: string\n /** Resolve actor metadata from a Request. Defaults to `human:${req.user?.email || 'anonymous'}`. */\n getActor?: (req: Request) => string\n /**\n * Inject a Mail-Tester client (tests use a stub). When omitted, a real\n * client is created from `mailer.config.mailTester`.\n */\n mailTesterClient?: MailTesterClient\n}\n\nexport function createAdminRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const router = Router()\n const spaDir = opts.spaDir ?? defaultSpaDir()\n const getActor =\n opts.getActor ?? ((req: Request) => `human:${(req as any).user?.email ?? 'anonymous'}`)\n\n // Static assets — long cache, hashed filenames.\n router.use(\n '/_assets',\n express.static(spaDir, {\n maxAge: '1y',\n immutable: true,\n index: false,\n }),\n )\n\n // JSON body parsing for mutating endpoints.\n router.use('/api', express.json({ limit: '1mb' }))\n\n // Inject actor on every API request (read after the host's auth middleware).\n router.use('/api', (req: Request, _res, next: NextFunction) => {\n ;(req as any).actor = getActor(req)\n next()\n })\n\n router.use('/api', apiRouter(mailer, opts))\n\n // SPA shell — any other route returns index.html so client-side routing\n // doesn't 404 on refresh.\n router.get(/.*/, (_req: Request, res: Response) => {\n res.sendFile(path.join(spaDir, 'index.html'))\n })\n\n return router\n}\n\n// ---------------------------------------------------------------------------\n// JSON API\n// ---------------------------------------------------------------------------\n\nfunction apiRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const r = Router()\n const c = mailer.collections\n\n // Computed once — the vars schema is fixed for the process lifetime.\n const varsSchema = mailer.config.varsAdapter ? varsJsonSchema(mailer.config.varsAdapter) : null\n\n function getMailTesterClient(): MailTesterClient | null {\n if (opts.mailTesterClient) return opts.mailTesterClient\n const cfg = mailer.config.mailTester\n if (!cfg?.apiKey) return null\n return createMailTesterClient(cfg)\n }\n\n // Vars contract for the template editor — JSON Schema of the host's\n // varsAdapter (null when none configured) plus the mailery-provided\n // built-in keys, so autocomplete/linting have one source of truth.\n r.get(\n '/vars-schema',\n asyncHandler(async (_req, res) => {\n res.json({ schema: varsSchema, builtins: RESERVED_VAR_KEYS })\n }),\n )\n\n r.get(\n '/me',\n asyncHandler(async (req, res) => {\n const [flows, templates, broadcasts, contacts, suppressions, healthDocs] = await Promise.all([\n c.flows.estimatedDocumentCount(),\n c.templates.estimatedDocumentCount(),\n c.broadcasts.estimatedDocumentCount(),\n c.subscriptions.countDocuments({ status: 'subscribed' }),\n c.suppressions.estimatedDocumentCount(),\n c.health.find({}).limit(500).toArray(),\n ])\n res.json({\n actor: (req as any).actor,\n counts: { flows, templates, broadcasts, contacts, suppressions },\n health: { status: effectiveOverallStatus(healthDocs) },\n providers: {\n names: Object.keys(mailer.config.providers),\n default: mailer.config.defaultProvider,\n },\n broadcastConfirmationThreshold: mailer.config.broadcastConfirmationThreshold,\n })\n }),\n )\n\n // ----- Dashboard ----------------------------------------------------------\n r.get(\n '/dashboard',\n asyncHandler(async (_req, res) => {\n const now = Date.now()\n const HOUR = 60 * 60 * 1000\n const since24h = new Date(now - 24 * HOUR)\n const since48h = new Date(now - 48 * HOUR)\n\n const [\n sentTotal, deliveredCount, bouncedCount, openedCount, clickedCount,\n sentPrev, deliveredPrev, openedPrev, clickedPrev,\n hourly,\n ] = await Promise.all([\n c.sends.countDocuments({ queuedAt: { $gt: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'bounced' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, firstClickAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, firstClickAt: { $ne: null } }),\n c.sends\n .aggregate<{ _id: number; sends: number; opens: number }>([\n { $match: { queuedAt: { $gt: since24h } } },\n {\n $project: {\n hour: {\n $toInt: {\n $divide: [{ $subtract: [now, { $toLong: '$queuedAt' }] }, HOUR],\n },\n },\n opened: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] },\n },\n },\n { $group: { _id: '$hour', sends: { $sum: 1 }, opens: { $sum: '$opened' } } },\n ])\n .toArray(),\n ])\n\n const sendSeries = new Array(24).fill(0)\n const openSeries = new Array(24).fill(0)\n for (const row of hourly) {\n const idx = 23 - Math.max(0, Math.min(23, row._id))\n sendSeries[idx] = row.sends\n openSeries[idx] = row.opens\n }\n\n const delta = (cur: number, prev: number): number | null => {\n if (prev === 0) return null\n return (cur - prev) / prev\n }\n const rateDelta = (curN: number, curD: number, prevN: number, prevD: number): number | null => {\n if (prevD === 0 || curD === 0) return null\n return curN / curD - prevN / prevD\n }\n\n const healthDocs = await c.health.find({}).limit(500).toArray()\n const healthAgg = healthDocs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const recentFlowsRaw = await c.flows.find({ enabled: true }).limit(5).toArray()\n const flowStatsMap = await computeFlowStats(mailer)\n const recentFlows = recentFlowsRaw.map((f) => ({ ...f, stats: flowStatsMap.get(f.slug) ?? emptyFlowStats() }))\n const recentSends = await c.sends.find().sort({ queuedAt: -1 }).limit(6).toArray()\n const recentAudit = await c.auditLog.find().sort({ occurredAt: -1 }).limit(5).toArray()\n\n const queueCounts = await collectQueueCounts(mailer)\n const lastSendError = await c.sends\n .findOne({ status: { $in: ['bounced', 'failed'] } }, { sort: { queuedAt: -1 } })\n const lastSendOk = await c.sends\n .findOne({ status: 'delivered' }, { sort: { queuedAt: -1 } })\n const providerOk =\n lastSendOk && lastSendError\n ? new Date(lastSendOk.queuedAt as Date).getTime() >= new Date(lastSendError.queuedAt as Date).getTime()\n : lastSendOk\n ? true\n : lastSendError\n ? false\n : null\n\n res.json({\n kpis: {\n sends: { value: sentTotal, delta: delta(sentTotal, sentPrev) },\n deliveredRate: {\n value: sentTotal === 0 ? null : deliveredCount / sentTotal,\n delta: rateDelta(deliveredCount, sentTotal, deliveredPrev, sentPrev),\n bounced: bouncedCount,\n },\n openRate: {\n value: sentTotal === 0 ? null : openedCount / sentTotal,\n delta: rateDelta(openedCount, sentTotal, openedPrev, sentPrev),\n },\n clickRate: {\n value: sentTotal === 0 ? null : clickedCount / sentTotal,\n delta: rateDelta(clickedCount, sentTotal, clickedPrev, sentPrev),\n },\n },\n series: { hourly: { sends: sendSeries, opens: openSeries } },\n health: {\n status: effectiveOverallStatus(healthDocs),\n rates: healthAgg?.rates ?? null,\n thresholds: {\n hardBounceRatePctTrip: mailer.config.circuitBreaker.hardBounceRatePctTrip,\n complaintRatePctTrip: mailer.config.circuitBreaker.complaintRatePctTrip,\n combinedBounceRatePctTrip: mailer.config.circuitBreaker.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: mailer.config.circuitBreaker.failedToSendRatePctDegrade,\n },\n },\n queue: {\n inFlight: queueCounts?.inFlight ?? null,\n delayed: queueCounts?.delayed ?? null,\n providerOk,\n providerName: mailer.config.defaultProvider,\n },\n recentFlows,\n recentSends,\n recentAudit,\n })\n }),\n )\n\n // ----- Events registry ----------------------------------------------------\n r.get(\n '/events',\n asyncHandler(async (_req, res) => {\n const registered = mailer.events.list()\n const seenNames = await c.events.distinct('name')\n const known = new Set(registered.map((r) => r.name))\n const unregistered = (seenNames as string[]).filter((n) => n && !known.has(n))\n res.json({\n registered: registered.sort((a, b) => a.name.localeCompare(b.name)),\n seen: unregistered.sort(),\n })\n }),\n )\n\n // ----- Flows --------------------------------------------------------------\n r.get(\n '/flows',\n asyncHandler(async (_req, res) => {\n const flows = await c.flows.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeFlowStats(mailer)\n res.json(flows.map((f) => ({ ...f, stats: stats.get(f.slug) ?? emptyFlowStats() })))\n }),\n )\n\n r.get(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeFlowStats(mailer, flow.slug)).get(flow.slug) ?? emptyFlowStats()\n return res.json({ ...flow, stats })\n }),\n )\n\n r.post(\n '/flows/:slug/pause',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: false, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.pause',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/resume',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: true, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.resume',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates ----------------------------------------------------------\n r.get(\n '/templates',\n asyncHandler(async (_req, res) => {\n const templates = await c.templates.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeTemplateStats(mailer)\n res.json(templates.map((t) => ({ ...t, stats: stats.get(t.slug) ?? emptyTemplateStats() })))\n }),\n )\n\n r.get(\n '/templates/:slug',\n asyncHandler(async (req, res) => {\n const template = await c.templates.findOne({ slug: req.params.slug })\n if (!template) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeTemplateStats(mailer, template.slug)).get(template.slug) ?? emptyTemplateStats()\n return res.json({ ...template, stats })\n }),\n )\n\n // ----- Broadcasts ---------------------------------------------------------\n r.get(\n '/broadcasts',\n asyncHandler(async (_req, res) => {\n const broadcasts = await c.broadcasts.find().sort({ createdAt: -1 }).toArray()\n const stats = await computeBroadcastStats(mailer)\n res.json(broadcasts.map((b) => ({ ...b, stats: stats.get(String(b._id)) ?? emptyBroadcastStats() })))\n }),\n )\n\n r.get(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const broadcast = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!broadcast) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeBroadcastStats(mailer, broadcast._id)).get(String(broadcast._id)) ?? emptyBroadcastStats()\n return res.json({ ...broadcast, stats })\n }),\n )\n\n // ----- Contacts -----------------------------------------------------------\n r.get(\n '/contacts',\n asyncHandler(async (req, res) => {\n const cursor = typeof req.query.cursor === 'string' ? req.query.cursor : undefined\n const limit = Math.min(Number(req.query.limit ?? 50), 200)\n const [{ contacts, nextCursor }, counts] = await Promise.all([\n mailer.adapter.query({}, { limit, cursor }),\n (async () => {\n const rows = await c.subscriptions\n .aggregate<{ _id: string; n: number }>([{ $group: { _id: '$status', n: { $sum: 1 } } }])\n .toArray()\n const out: Record<string, number> = { subscribed: 0, pending_doi: 0, unsubscribed: 0, bounced: 0, complained: 0 }\n let total = 0\n for (const r of rows) {\n if (r._id) out[r._id] = r.n\n total += r.n\n }\n return { ...out, total }\n })(),\n ])\n res.json({ contacts, nextCursor, counts })\n }),\n )\n\n r.get(\n '/contacts/:externalId',\n asyncHandler(async (req, res) => {\n const externalId = String(req.params.externalId)\n const [contact, subscription, recentEvents, recentSends, activeRuns] = await Promise.all([\n mailer.adapter.getById(externalId),\n c.subscriptions.findOne({ externalId }),\n c.events.find({ externalId }).sort({ occurredAt: -1 }).limit(50).toArray(),\n c.sends.find({ externalId }).sort({ queuedAt: -1 }).limit(50).toArray(),\n c.flowRuns.find({ externalId, status: 'active' }).sort({ nextActionAt: 1 }).limit(50).toArray(),\n ])\n if (!contact) return res.status(404).json({ error: 'not_found' })\n return res.json({ contact, subscription, recentEvents, recentSends, activeRuns })\n }),\n )\n\n // ----- Sends --------------------------------------------------------------\n r.get(\n '/sends',\n asyncHandler(async (req, res) => {\n const limit = Math.min(Number(req.query.limit ?? 100), 500)\n const status = typeof req.query.status === 'string' ? req.query.status : undefined\n const filter: any = {}\n if (status) filter.status = status\n const sends = await c.sends.find(filter).sort({ queuedAt: -1 }).limit(limit).toArray()\n res.json(sends)\n }),\n )\n\n r.get(\n '/sends/:id',\n asyncHandler(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const send = await c.sends.findOne({ _id: new ObjectId(id) })\n if (!send) return res.status(404).json({ error: 'not_found' })\n const events = send.providerMessageId\n ? await c.webhookEvents\n .find({ providerMessageId: send.providerMessageId })\n .sort({ receivedAt: -1 })\n .limit(100)\n .toArray()\n : []\n return res.json({ send, webhookEvents: events })\n }),\n )\n\n // ----- Suppressions -------------------------------------------------------\n r.get(\n '/suppressions',\n asyncHandler(async (_req, res) => {\n const rows = await c.suppressions.find().sort({ addedAt: -1 }).limit(500).toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/suppressions',\n asyncHandler(async (req, res) => {\n const { email, scope, reason, source, notes } = req.body ?? {}\n await mailer.suppress(email, { scope, reason, source, notes })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'suppression.add',\n resource: { collection: 'mailer_suppressions' },\n diffSummary: `${email} → ${scope}/${reason}`,\n })\n res.json({ ok: true })\n }),\n )\n\n // ----- Audit log ----------------------------------------------------------\n r.get(\n '/audit',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog.find().sort({ occurredAt: -1 }).limit(200).toArray()\n res.json(rows)\n }),\n )\n\n // ----- Setup status -------------------------------------------------------\n r.get(\n '/setup-status',\n asyncHandler(async (_req, res) => {\n const status = await runSetupChecks(mailer)\n res.json(status)\n }),\n )\n\n // ----- Health -------------------------------------------------------------\n r.get(\n '/health',\n asyncHandler(async (_req, res) => {\n const cb = mailer.config.circuitBreaker\n const thresholds = {\n hardBounceRatePctTrip: cb.hardBounceRatePctTrip,\n complaintRatePctTrip: cb.complaintRatePctTrip,\n combinedBounceRatePctTrip: cb.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: cb.failedToSendRatePctDegrade,\n }\n const docs = await c.health.find({}).limit(500).toArray()\n const aggregate = docs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n const overall = effectiveOverallStatus(docs)\n if (docs.length === 0) {\n // No tick has run yet. UI renders \"—\" / muted dots when status is null.\n res.json({ status: null, rates: null, counters: null, aggregate: null, buckets: [], thresholds })\n return\n }\n // Keep top-level `status` / `rates` for back-compat with consumers that\n // expect a single status (broadcast-new pre-flight, shell pill).\n res.json({\n status: overall,\n rates: aggregate?.rates ?? null,\n counters: aggregate?.counters ?? null,\n aggregate,\n buckets,\n thresholds,\n })\n }),\n )\n\n r.get(\n '/health/trips',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog\n .find({ action: { $in: ['health.trip', 'health.resume'] } })\n .sort({ occurredAt: -1 })\n .limit(50)\n .toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/health/resume',\n asyncHandler(async (req, res) => {\n const body = (req.body ?? {}) as { senderDomain?: string; kind?: 'marketing' | 'transactional' }\n // Half-specified body (only senderDomain or only kind) is almost\n // certainly an operator error — fail closed rather than silently\n // resume every tripped bucket.\n if ((body.senderDomain != null) !== (body.kind != null)) {\n return res.status(400).json({\n error: 'validation_failed',\n message: 'senderDomain and kind must both be provided to target a single bucket, or both omitted to resume all tripped buckets.',\n })\n }\n if (body.kind && !['marketing', 'transactional'].includes(body.kind)) {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be \"marketing\" or \"transactional\"' })\n }\n const target = body.senderDomain && body.kind\n ? { _id: healthBucketId(body.senderDomain.toLowerCase(), body.kind) }\n // Explicitly exclude the aggregate doc — it never trips, but guard\n // anyway so a future schema change can't accidentally flip its status.\n : { status: 'tripped' as const, _id: { $ne: HEALTH_AGG_ID } }\n\n const result = await c.health.updateMany(\n target,\n { $set: { status: 'healthy', manuallyResumedAt: new Date(), updatedAt: new Date() } },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'health.resume',\n resource: {\n collection: 'mailer_health',\n id: body.senderDomain && body.kind ? `${body.senderDomain}|${body.kind}` : 'all-tripped',\n },\n })\n res.json({ ok: true, resumed: result.modifiedCount })\n }),\n )\n\n // ----- DNSBL --------------------------------------------------------------\n r.get(\n '/dnsbl',\n asyncHandler(async (_req, res) => {\n const checks = await c.dnsblChecks.find({}).sort({ result: 1, target: 1, list: 1 }).limit(500).toArray()\n const latestRunAt = checks.reduce<Date | null>((acc, d) => {\n const t = new Date(d.runAt)\n return acc && acc.getTime() >= t.getTime() ? acc : t\n }, null)\n res.json({\n checks,\n latestRunAt: latestRunAt ? latestRunAt.toISOString() : null,\n intervalHours: mailer.config.dnsbl?.intervalHours ?? 24,\n })\n }),\n )\n\n r.post(\n '/dnsbl/recheck',\n asyncHandler(async (req, res) => {\n const result = await runDnsblChecks(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dnsbl.recheck',\n resource: { collection: 'mailer_dnsbl_checks' },\n diffSummary: result.ran\n ? `${result.totalChecks} checks, ${result.listedCount} listed`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Postmaster Tools ---------------------------------------------------\n r.get(\n '/postmaster',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.postmaster\n const configured = !!cfg?.clientId && !!cfg?.clientSecret && !!cfg?.refreshToken\n const all = await c.postmasterSnapshots.find({}).sort({ domain: 1, date: -1 }).limit(2000).toArray()\n // Group by domain, keep last 30 entries per domain.\n const byDomain = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byDomain.get(s.domain) ?? []\n if (arr.length < 30) arr.push(s)\n byDomain.set(s.domain, arr)\n }\n const domains = Array.from(byDomain.entries()).map(([domain, snapshots]) => ({\n domain,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n domains,\n })\n }),\n )\n\n r.post(\n '/postmaster/refresh',\n asyncHandler(async (req, res) => {\n const result = await runPostmasterPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'postmaster.refresh',\n resource: { collection: 'mailer_postmaster_snapshots' },\n diffSummary: result.ran\n ? `fetched ${result.fetched ?? 0}, tripped ${(result.trippedDomains ?? []).length}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- List Hygiene -------------------------------------------------------\n // The hygiene aggregation iterates every send doc — at scale that's\n // expensive. Cache the result for 60s and serialize concurrent requests\n // so a few rapid-fire dashboard loads can't pile up multiple full scans.\n let hygieneCache: { computedAt: number; report: Awaited<ReturnType<typeof computeListHygiene>> } | null = null\n let hygieneInFlight: Promise<Awaited<ReturnType<typeof computeListHygiene>>> | null = null\n const HYGIENE_CACHE_MS = 60_000\n\n r.get(\n '/hygiene',\n asyncHandler(async (req, res) => {\n const force = req.query.refresh === '1' || req.query.refresh === 'true'\n const now = Date.now()\n if (!force && hygieneCache && now - hygieneCache.computedAt < HYGIENE_CACHE_MS) {\n return res.json(hygieneCache.report)\n }\n if (!hygieneInFlight) {\n hygieneInFlight = (async () => {\n try {\n const report = await computeListHygiene(mailer.getRunnerContext())\n hygieneCache = { computedAt: Date.now(), report }\n return report\n } finally {\n hygieneInFlight = null\n }\n })()\n }\n const report = await hygieneInFlight\n res.json(report)\n }),\n )\n\n // ----- DMARC RUA ingestion ------------------------------------------------\n const dmarcUpload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB; reports are typically <100KB\n })\n\n r.post(\n '/dmarc/upload',\n dmarcUpload.single('file'),\n asyncHandler(async (req, res) => {\n const file = (req as any).file as Express.Multer.File | undefined\n if (!file) return res.status(400).json({ error: 'no_file', message: 'expected a \"file\" field' })\n\n try {\n const result = await ingestDmarcAttachment(mailer.getRunnerContext(), file.buffer, file.originalname)\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.ingest',\n resource: { collection: 'mailer_dmarc_reports', id: result.reportId },\n diffSummary: result.duplicate\n ? `duplicate report ${result.reportId}`\n : `ingested ${result.totalMessages} msgs (${result.passCount} pass / ${result.failCount} fail) for ${result.domain}`,\n })\n return res.json(result)\n } catch (err: any) {\n return res.status(400).json({ error: 'ingest_failed', message: String(err?.message ?? err) })\n }\n }),\n )\n\n r.get(\n '/dmarc',\n asyncHandler(async (_req, res) => {\n const ctx = mailer.getRunnerContext()\n const tagged = await resolveSourceTags(ctx)\n const reports = await c.dmarcReports.find({}).sort({ rangeEnd: -1 }).limit(200).toArray()\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n // Cap at 5k rows — busy domains can easily generate that many failure\n // rows over 30 days. We only consume these for per-domain progression\n // suggestions (untagged-source check); a partial page is fine.\n const recentFailures = await c.dmarcFailures\n .find({ receivedAt: { $gte: since30 } })\n .sort({ receivedAt: -1 })\n .limit(5000)\n .toArray()\n\n const byDomain = new Map<string, { passCount: number; failCount: number; totalMessages: number; reportCount: number; latestRangeEnd: Date | null; latestPolicy: 'none' | 'quarantine' | 'reject' | null; latestPct: number | null; reports: typeof reports }>()\n for (const r of reports) {\n const cur = byDomain.get(r.domain) ?? { passCount: 0, failCount: 0, totalMessages: 0, reportCount: 0, latestRangeEnd: null, latestPolicy: null, latestPct: null, reports: [] }\n cur.passCount += r.passCount\n cur.failCount += r.failCount\n cur.totalMessages += r.totalMessages\n cur.reportCount += 1\n const re = new Date(r.rangeEnd)\n if (!cur.latestRangeEnd || re > cur.latestRangeEnd) {\n cur.latestRangeEnd = re\n cur.latestPolicy = r.policyP\n cur.latestPct = r.policyPct\n }\n cur.reports.push(r)\n byDomain.set(r.domain, cur)\n }\n\n // Build per-day alignment series (last 14 days) per domain for sparklines.\n const since14 = Date.now() - 14 * 86_400_000\n\n const domains = Array.from(byDomain.entries()).map(([domain, s]) => {\n // Sparkline series — pass rate per day from recent reports.\n const dayTotals = new Map<string, { pass: number; total: number }>()\n for (const r of s.reports) {\n if (new Date(r.rangeEnd).getTime() < since14) continue\n const day = new Date(r.rangeEnd).toISOString().slice(0, 10)\n const d = dayTotals.get(day) ?? { pass: 0, total: 0 }\n d.pass += r.passCount\n d.total += r.passCount + r.failCount\n dayTotals.set(day, d)\n }\n const series = Array.from(dayTotals.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([day, d]) => ({ day, alignmentRate: d.total === 0 ? null : d.pass / d.total }))\n\n // Policy progression suggestion.\n const knownIps = new Set(Array.from(tagged.values()).filter((t) => !t.ignored).map((t) => t.ip))\n const ignoredIps = new Set(Array.from(tagged.values()).filter((t) => t.ignored).map((t) => t.ip))\n const suggested = suggestPolicyProgression({\n reports: s.reports.map((r) => ({ rangeEnd: new Date(r.rangeEnd), passCount: r.passCount, failCount: r.failCount })),\n failures: recentFailures.filter((f) => f.domain === domain).map((f) => ({ sourceIp: f.sourceIp, count: f.count, receivedAt: new Date(f.receivedAt) })),\n knownSourceIps: knownIps,\n ignoredSourceIps: ignoredIps,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n })\n\n return {\n domain,\n passCount: s.passCount,\n failCount: s.failCount,\n totalMessages: s.totalMessages,\n reportCount: s.reportCount,\n latestRangeEnd: s.latestRangeEnd,\n alignmentRate: s.totalMessages === 0 ? null : s.passCount / s.totalMessages,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n progression: suggested\n ? { ...suggested, current: { policy: s.latestPolicy, pct: s.latestPct } }\n : null,\n series,\n }\n })\n\n const topFailures = await c.dmarcFailures\n .aggregate<{ _id: { sourceIp: string; domain: string }; total: number; days: number; lastSeen: Date; sample: any }>([\n { $match: { receivedAt: { $gte: since30 } } },\n {\n $group: {\n _id: { sourceIp: '$sourceIp', domain: '$domain' },\n total: { $sum: '$count' },\n days: { $addToSet: '$day' },\n lastSeen: { $max: '$receivedAt' },\n sample: { $first: '$$ROOT' },\n },\n },\n { $project: { sourceIp: '$_id.sourceIp', domain: '$_id.domain', total: 1, days: { $size: '$days' }, lastSeen: 1, sample: 1 } },\n { $sort: { total: -1 } },\n { $limit: 50 },\n ])\n .toArray()\n\n const sources = topFailures.map((f) => {\n const tag = tagged.get(f._id.sourceIp)\n return {\n sourceIp: f._id.sourceIp,\n domain: f._id.domain,\n totalMessages: f.total,\n daysSeen: f.days,\n lastSeen: f.lastSeen,\n dkimResult: f.sample.dkimResult,\n spfResult: f.sample.spfResult,\n dispositionApplied: f.sample.dispositionApplied,\n label: tag?.label ?? null,\n ignored: !!tag?.ignored,\n tagSource: tag?.source ?? null,\n }\n })\n\n res.json({\n domains,\n sources,\n recentReports: reports.slice(0, 30),\n retentionDays: mailer.config.dmarc?.retentionDays ?? 90,\n })\n }),\n )\n\n // ----- DMARC source tags (mutable from UI) --------------------------------\n r.put(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const body = (req.body ?? {}) as { label?: string; ignored?: boolean }\n if (!body.label || typeof body.label !== 'string') {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const label = body.label.trim().slice(0, 200)\n if (!label) {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const ignored = !!body.ignored\n await c.dmarcSourceTags.updateOne(\n { ip },\n { $set: { ip, label, ignored, setBy: (req as any).actor ?? 'unknown', setAt: new Date() } },\n { upsert: true },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.upsert',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n diffSummary: `${ip} → \"${label}\"${ignored ? ' (ignored)' : ''}`,\n })\n res.json({ ok: true })\n }),\n )\n\n r.delete(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const result = await c.dmarcSourceTags.deleteOne({ ip })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.delete',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n })\n res.json({ ok: true, deleted: result.deletedCount })\n }),\n )\n\n // ----- Microsoft SNDS -----------------------------------------------------\n r.get(\n '/snds',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.snds\n const configured = !!cfg?.accessKey\n const all = await c.sndsSnapshots.find({}).sort({ ip: 1, activityStart: -1 }).limit(2000).toArray()\n const byIp = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byIp.get(s.ip) ?? []\n if (arr.length < 30) arr.push(s)\n byIp.set(s.ip, arr)\n }\n const ips = Array.from(byIp.entries()).map(([ip, snapshots]) => ({\n ip,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n ips,\n })\n }),\n )\n\n r.post(\n '/snds/refresh',\n asyncHandler(async (req, res) => {\n const result = await runSndsPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'snds.refresh',\n resource: { collection: 'mailer_snds_snapshots' },\n diffSummary: result.ran\n ? `parsed ${result.rowsParsed ?? 0}, persisted ${result.rowsPersisted ?? 0}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Flows: create / edit / publish ------------------------------------\n r.post(\n '/flows',\n asyncHandler(async (req, res) => {\n const { slug, name, description, trigger, goal, audience } = req.body ?? {}\n if (!slug || !name || !trigger?.eventName) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, and trigger.eventName required' })\n }\n const now = new Date()\n const doc = {\n slug,\n name,\n description: description ?? '',\n trigger: { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false },\n enabled: false,\n steps: [],\n version: 0,\n draft: {\n steps: [],\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor ?? 'unknown',\n lastModifiedAt: now,\n },\n goal: goal ?? 'activation',\n audience: audience ?? '',\n expectedVolumePerWeek: null,\n stats: { activeRuns: 0, completedRuns: 0, sendsTotal: 0, sendsLast7Days: 0 },\n lastTriggerScanAt: null,\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n }\n try {\n await c.flows.insertOne(doc as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.create',\n resource: { collection: 'mailer_flows', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/flows/:slug/draft',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const { steps, notes, trigger, name, description, goal, audience } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (Array.isArray(steps)) set['draft.steps'] = steps\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (trigger?.eventName) set.trigger = { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false }\n if (typeof name === 'string') set.name = name\n if (typeof description === 'string') set.description = description\n if (typeof goal === 'string') set.goal = goal\n if (typeof audience === 'string') set.audience = audience\n\n await c.flows.updateOne({ _id: flow._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.draft.update',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Updated draft (${steps ? `${steps.length} steps` : 'metadata only'})`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/publish',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const draftSteps = flow.draft?.steps ?? flow.steps\n if (!Array.isArray(draftSteps) || draftSteps.length === 0) {\n return res.status(400).json({ error: 'empty_flow', message: 'flow has no steps to publish' })\n }\n const nextVersion = (flow.version ?? 0) + 1\n const now = new Date()\n await c.flowVersions.insertOne({\n flowId: flow._id!,\n version: nextVersion,\n steps: draftSteps,\n trigger: flow.trigger,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n await c.flows.updateOne(\n { _id: flow._id },\n {\n $set: {\n steps: draftSteps,\n version: nextVersion,\n enabled: true,\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.publish',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({ ok: true, version: nextVersion })\n }),\n )\n\n r.delete(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const everRan = await c.flowRuns.countDocuments({ flowId: flow._id }, { limit: 1 })\n if (everRan > 0) return res.status(409).json({ error: 'has_runs', message: 'flow has runs — pause it instead' })\n await c.flows.deleteOne({ _id: flow._id })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.delete',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates: create / edit / publish --------------------------------\n r.post(\n '/templates',\n asyncHandler(async (req, res) => {\n const { slug, name, kind, subject, preheader, fromName, fromEmail } = req.body ?? {}\n if (!slug || !name || !kind) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, kind required' })\n }\n if (kind !== 'marketing' && kind !== 'transactional') {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be marketing or transactional' })\n }\n const resolvedFromEmail =\n fromEmail ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.email : undefined) ??\n mailer.config.fromDefaults?.email ??\n 'noreply@example.com'\n const senderCheck = validateSenderDomain(resolvedFromEmail, kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n const now = new Date()\n try {\n await c.templates.insertOne({\n slug,\n name,\n description: '',\n kind,\n fromName:\n fromName ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.name : undefined) ??\n mailer.config.fromDefaults?.name ??\n 'Mailery',\n fromEmail: resolvedFromEmail,\n replyTo: null,\n providerOverride: null,\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n body: { mjml: '', editorJson: null, html: '', plainText: '', compiledAt: null },\n variablesSchema: {},\n draft: {\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n mjml: '',\n editorJson: null,\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor,\n lastModifiedAt: now,\n },\n tags: [],\n trackOpens: kind === 'marketing',\n trackClicks: kind === 'marketing',\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0, lastSentAt: null },\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.create',\n resource: { collection: 'mailer_templates', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/templates/:slug/draft',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const { subject, preheader, mjml, editorJson, notes, name, fromName, fromEmail, replyTo, kind, trackOpens, trackClicks } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (typeof subject === 'string') set['draft.subject'] = subject\n if (typeof preheader === 'string') set['draft.preheader'] = preheader\n if (typeof mjml === 'string') set['draft.mjml'] = mjml\n if (editorJson !== undefined) set['draft.editorJson'] = editorJson\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (typeof name === 'string') set.name = name\n if (typeof fromName === 'string') set.fromName = fromName\n if (typeof fromEmail === 'string') set.fromEmail = fromEmail\n if (typeof replyTo === 'string' || replyTo === null) set.replyTo = replyTo\n if (kind === 'marketing' || kind === 'transactional') set.kind = kind\n\n // Validate resulting (kind, fromEmail) against the senderDomains registry\n // whenever either field is being touched.\n if (typeof fromEmail === 'string' || kind === 'marketing' || kind === 'transactional') {\n const resultingKind = (set.kind as typeof tpl.kind) ?? tpl.kind\n const resultingFromEmail = (set.fromEmail as string) ?? tpl.fromEmail\n const senderCheck = validateSenderDomain(resultingFromEmail, resultingKind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n }\n if (typeof trackOpens === 'boolean') set.trackOpens = trackOpens\n if (typeof trackClicks === 'boolean') set.trackClicks = trackClicks\n\n await c.templates.updateOne({ _id: tpl._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.draft.update',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Mail-Tester deliverability check ----------------------------------\n r.get(\n '/templates/:slug/mail-tester',\n asyncHandler(async (req, res) => {\n const cfg = mailer.config.mailTester\n const configured = !!cfg?.apiKey\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Cache key must reflect the same fingerprint the check + publish gate\n // use — render the *current* draft if there is one, otherwise the\n // most recent published body. Previously this mixed draft.subject\n // with published body.html, which always missed pre-first-publish\n // and drifted whenever a subject edit followed a publish.\n let bodyHash = ''\n let subject = tpl.subject ?? ''\n if (tpl.draft) {\n try {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : tpl.draft.mjml\n ? await compileTemplate(tpl.draft.mjml)\n : null\n if (compiled) {\n bodyHash = sha256Hex(compiled.html)\n subject = tpl.draft.subject || subject\n }\n } catch {\n // If the draft no longer compiles, fall back to the published body.\n }\n }\n if (!bodyHash && tpl.body?.html) {\n bodyHash = sha256Hex(tpl.body.html)\n }\n const key = bodyHash ? mailTesterContentKey({ bodyHash, subject, fromEmail: tpl.fromEmail }) : null\n const cached = key ? await findCachedScore(mailer.getRunnerContext(), key) : null\n\n res.json({\n configured,\n minScore: cfg?.minScore ?? 8.0,\n requireScore: !!cfg?.requireScore,\n cacheHours: cfg?.cacheHours ?? 24,\n score: cached,\n })\n }),\n )\n\n r.post(\n '/templates/:slug/mail-tester-check',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) {\n return res.status(400).json({\n error: 'not_configured',\n message: 'Mail-Tester is not configured. Set mailer.config.mailTester.apiKey to enable.',\n })\n }\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Save a draft before running a deliverability check.' })\n\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n\n const bodyHash = sha256Hex(compiled.html)\n const contentKey = mailTesterContentKey({ bodyHash, subject: draft.subject, fromEmail: tpl.fromEmail })\n const ctx = mailer.getRunnerContext()\n\n // Cache hit — return without burning a credit.\n const cached = await findCachedScore(ctx, contentKey)\n if (cached) {\n return res.json({ cached: true, status: 'ready', score: cached })\n }\n\n // Provision a new test address and send the rendered draft to it.\n const { checkId, emailAddress } = await client.provisionCheck()\n const provider = mailer.providers[tpl.providerOverride ?? mailer.config.defaultProvider]\n if (!provider) {\n return res.status(500).json({ error: 'provider_unknown', message: `default provider ${mailer.config.defaultProvider} is not registered` })\n }\n\n try {\n await provider.send({\n to: emailAddress,\n fromName: tpl.fromName,\n fromEmail: tpl.fromEmail,\n replyTo: tpl.replyTo ?? undefined,\n subject: draft.subject,\n html: compiled.html,\n text: compiled.plainText,\n headers: {},\n messageMeta: { mailTesterCheckId: checkId },\n })\n } catch (err: any) {\n return res.status(502).json({ error: 'send_failed', message: String(err?.message ?? err) })\n }\n\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.start',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Sent draft to ${emailAddress} for Mail-Tester check ${checkId}`,\n })\n\n res.json({\n cached: false,\n status: 'pending',\n checkId,\n contentKey,\n message: 'Test email sent. Poll /mail-tester-result?checkId=...&contentKey=... for the score.',\n })\n }),\n )\n\n r.get(\n '/templates/:slug/mail-tester-result',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) return res.status(400).json({ error: 'not_configured' })\n\n const checkId = String(req.query.checkId ?? '')\n if (!checkId) return res.status(400).json({ error: 'validation_failed', message: 'checkId is required' })\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Draft no longer exists.' })\n\n // Re-derive the content key server-side from the current draft so an\n // attacker can't land a score under an arbitrary fingerprint and game\n // the publish gate. We must recompile to recompute bodyHash.\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n const contentKey = mailTesterContentKey({\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n\n const result = await client.fetchResult(checkId)\n if (!result.ready) {\n return res.json({ status: 'pending', score: null })\n }\n\n const ctx = mailer.getRunnerContext()\n const persisted = await persistScore(ctx, { templateSlug: tpl.slug, contentKey, checkId, result })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.complete',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Score ${result.score.toFixed(1)}`,\n })\n res.json({ status: 'ready', score: persisted })\n }),\n )\n\n r.post(\n '/templates/:slug/lint',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Lint against the supplied draft if present, otherwise the saved draft,\n // otherwise the last-published body. Keep this tolerant so the editor\n // can call it without juggling round-trips.\n const body = (req.body ?? {}) as {\n subject?: string\n preheader?: string\n mjml?: string\n editorJson?: Record<string, unknown> | null\n fromEmail?: string\n kind?: 'marketing' | 'transactional'\n }\n\n const subject = body.subject ?? tpl.draft?.subject ?? tpl.subject ?? ''\n const preheader = body.preheader ?? tpl.draft?.preheader ?? tpl.preheader ?? ''\n const mjml = body.mjml ?? tpl.draft?.mjml ?? tpl.body?.mjml ?? ''\n const editorJson = body.editorJson !== undefined ? body.editorJson : (tpl.draft?.editorJson ?? tpl.body?.editorJson ?? null)\n const fromEmail = body.fromEmail ?? tpl.fromEmail\n // Whitelist kind — otherwise body.kind:'foo' bypasses the marketing-\n // only missing_unsubscribe_tag check by hitting neither branch.\n const kind = body.kind === 'marketing' || body.kind === 'transactional' ? body.kind : tpl.kind\n\n let html = ''\n let plainText = ''\n try {\n if (editorJson) {\n const compiled = await compileMailyTemplate(editorJson)\n html = compiled.html\n plainText = compiled.plainText\n } else if (mjml) {\n const compiled = await compileTemplate(mjml)\n html = compiled.html\n plainText = compiled.plainText\n }\n } catch (err: any) {\n return res.status(200).json({\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n compileFailed: true,\n })\n }\n\n // Script-seeded templates can have no draft source at all (body.html +\n // body.plainText inserted directly, editorJson/mjml empty). Fall back to\n // the stored body so lint judges what actually sends instead of\n // reporting an empty template.\n if (!html && typeof tpl.body?.html === 'string') html = tpl.body.html\n if (!plainText && typeof tpl.body?.plainText === 'string') plainText = tpl.body.plainText\n\n const lint = lintTemplate(\n { subject, preheader, mjml, editorJson, html, plainText, kind, fromEmail },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n res.json({ ...lint, compileFailed: false })\n }),\n )\n\n r.post(\n '/templates/:slug/publish',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft' })\n\n // Short-circuit sender-domain check — preserves the pre-linter 400\n // sender_domain_invalid contract so external callers (and the SPA's\n // own publish modal) can key on it without conflating with lint errors.\n const senderCheck = validateSenderDomain(tpl.fromEmail, tpl.kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n\n let compiled: { html: string; plainText: string; errors: any[] }\n try {\n if (draft.editorJson) {\n compiled = await compileMailyTemplate(draft.editorJson)\n } else if (draft.mjml) {\n compiled = await compileTemplate(draft.mjml)\n } else {\n return res.status(400).json({ error: 'empty_draft', message: 'draft has no MJML or editorJson content' })\n }\n } catch (err: any) {\n // Same shape as the lint endpoint's compileFailed branch so the UI\n // can surface compile errors uniformly with lint errors.\n return res.status(422).json({\n error: 'compile_failed',\n message: String(err?.message ?? err),\n lint: {\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n },\n })\n }\n\n const lint = lintTemplate(\n {\n subject: draft.subject,\n preheader: draft.preheader,\n mjml: draft.mjml ?? '',\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n kind: tpl.kind,\n fromEmail: tpl.fromEmail,\n },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n\n if (lint.errors.length > 0) {\n return res.status(422).json({\n error: 'lint_failed',\n message: `Template publish blocked by ${lint.errors.length} content issue(s).`,\n lint,\n })\n }\n\n // Mail-Tester gate. Blocks when a cached score for this exact content is\n // below minScore, and — when `requireScore` is configured — when no score\n // for this content exists at all. Operator can override either with\n // `bypassMailTester: true` in the request body.\n const bypass = Boolean(req.body?.bypassMailTester)\n if (!bypass) {\n const gate = await evaluateMailTesterGate(mailer.getRunnerContext(), {\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n if (!gate.allowed) {\n return res.status(422).json({\n error: 'mail_tester_blocked',\n code: gate.code,\n message: gate.reason,\n score: gate.score,\n hint:\n gate.code === 'no_score'\n ? 'POST to `/templates/:slug/mail-tester-check`, poll `/mail-tester-result`, then publish — or POST `bypassMailTester: true` to publish anyway.'\n : 'Re-run the deliverability check after fixing the feedback, or POST `bypassMailTester: true` to publish anyway.',\n })\n }\n }\n\n const now = new Date()\n const nextVersion = await c.templateVersions.countDocuments({ templateId: tpl._id }) + 1\n await c.templateVersions.insertOne({\n templateId: tpl._id!,\n version: nextVersion,\n mjml: draft.mjml,\n html: compiled.html,\n plainText: compiled.plainText,\n subject: draft.subject,\n preheader: draft.preheader,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n\n await c.templates.updateOne(\n { _id: tpl._id },\n {\n $set: {\n subject: draft.subject,\n preheader: draft.preheader,\n body: {\n mjml: draft.mjml,\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n compiledAt: now,\n },\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.publish',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({\n ok: true,\n version: nextVersion,\n warnings: compiled.errors,\n lint, // warnings + infos for UI\n })\n }),\n )\n\n r.post(\n '/templates/:slug/preview',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const useDraft = req.body?.useDraft !== false\n let html = ''\n let plainText = ''\n if (useDraft && tpl.draft) {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : await compileTemplate(tpl.draft.mjml || '<mjml><mj-body></mj-body></mjml>')\n html = compiled.html\n plainText = compiled.plainText\n } else {\n if (!tpl.body?.html) {\n return res.status(409).json({ error: 'not_published', message: 'Template has not been published yet.' })\n }\n html = tpl.body.html\n plainText = tpl.body.plainText\n }\n\n // Preview as a real contact when contactId is given — pulls the actual\n // contact through the adapter and runs the host's varsAdapter, so the\n // preview shows exactly what that person would receive.\n let contact: Contact\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : null\n if (contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = found\n } else {\n contact = req.body?.sampleContact ?? {\n externalId: 'preview-contact',\n email: 'preview@example.com',\n tags: [],\n fields: { firstName: 'Alex' },\n }\n }\n\n // Optional simulated trigger-event properties, so account/topic-scoped\n // templates ({{event.*}} or resolver branching) preview realistically.\n const eventProperties =\n req.body?.eventProperties && typeof req.body.eventProperties === 'object'\n ? (req.body.eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'preview',\n templateSlug: tpl.slug,\n eventProperties,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: req.body?.vars ?? {},\n event: eventProperties ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/preview`,\n senderAddress: mailer.config.senderAddress,\n }\n\n const previewTpl = { ...tpl, body: { ...tpl.body, html, plainText } }\n const rendered = await renderTemplate(previewTpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n return res.json({\n subject: rendered.subject,\n preheader: rendered.preheader,\n html: rendered.html,\n plainText: rendered.plainText,\n contact: { externalId: contact.externalId, email: contact.email },\n })\n }),\n )\n\n r.post(\n '/templates/:slug/send-test',\n asyncHandler(async (req, res) => {\n const { to, sampleData, contactId, eventProperties } = req.body ?? {}\n if (!to) return res.status(400).json({ error: 'to_required' })\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Render as a real contact when contactId is given (vars included),\n // but always deliver to the operator-typed address.\n let contact: Contact\n if (typeof contactId === 'string' && contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = { ...found, email: to }\n } else {\n contact = sampleData?.contact ?? {\n externalId: 'test-recipient',\n email: to,\n tags: [],\n fields: { firstName: 'Test' },\n }\n contact.email = to\n }\n\n const evProps =\n eventProperties && typeof eventProperties === 'object'\n ? (eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'test',\n templateSlug: tpl.slug,\n eventProperties: evProps,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: sampleData?.vars ?? {},\n event: evProps ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/test`,\n senderAddress: mailer.config.senderAddress,\n }\n const rendered = await renderTemplate(tpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n const tracking = applyTracking(rendered.html, {\n sendId: `test-${Date.now()}`,\n publicUrl: mailer.config.publicUrl,\n trackOpens: false,\n trackClicks: false,\n })\n\n const provider = mailer.providers[tpl.providerOverride ?? mailer.config.defaultProvider]!\n const result = await provider.send({\n to,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: `[TEST] ${rendered.subject}`,\n html: tracking.html,\n text: rendered.plainText,\n })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.send-test',\n resource: { collection: 'mailer_templates', slug: tpl.slug },\n diffSummary: `to=${to}`,\n })\n // Avoid unused — sign helper is exposed for future preview routes.\n void signUnsubscribeToken\n return res.json({ ok: true, providerId: result.providerId })\n }),\n )\n\n // ----- Broadcasts: create / patch / schedule / cancel --------------------\n r.post(\n '/broadcasts',\n asyncHandler(async (req, res) => {\n const { slug, name, templateSlug, segmentDefinition } = req.body ?? {}\n if (!slug || !name || !templateSlug) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, templateSlug required' })\n }\n const now = new Date()\n try {\n await c.broadcasts.insertOne({\n slug,\n name,\n templateSlug,\n segmentDefinition: segmentDefinition ?? { filters: [{ kind: 'subscriptionStatus', equals: 'subscribed' }] },\n status: 'draft',\n scheduledAt: null,\n startedAt: null,\n completedAt: null,\n confirmationRequired: true,\n confirmedCount: null,\n confirmedAt: null,\n confirmedBy: null,\n recipientCount: null,\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0 },\n createdAt: now,\n createdBy: (req as any).actor,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.create',\n resource: { collection: 'mailer_broadcasts', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { name, templateSlug, segmentDefinition } = req.body ?? {}\n const set: Record<string, unknown> = { updatedAt: new Date() }\n if (typeof name === 'string') set.name = name\n if (typeof templateSlug === 'string') set.templateSlug = templateSlug\n if (segmentDefinition) set.segmentDefinition = segmentDefinition\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/segment/count',\n asyncHandler(async (req, res) => {\n const segmentDefinition = req.body?.segmentDefinition\n if (!segmentDefinition?.filters) return res.status(400).json({ error: 'segment_required' })\n const t0 = Date.now()\n // V1: only host-side filter translation. Mailer-side filters\n // (subscription status, fired events, etc.) and the suppression check\n // are applied at dispatch time over the streamed cursor, so the live\n // counter would have to scan-and-filter the full audience to be\n // precise. We return the upper-bound count and tell the UI it's an\n // estimate. When richer estimation lands, swap this for a sampled\n // pass that includes mailer-side filters + suppression.\n const hostFilter: any = {}\n for (const f of segmentDefinition.filters) {\n if (f.kind === 'hasTag') hostFilter.hasTag = f.tag\n if (f.kind === 'fieldEquals') hostFilter.fieldEquals = { field: f.field, value: f.value }\n }\n const hasMailerFilters = segmentDefinition.filters.some((f: any) =>\n ['subscriptionStatus', 'firedEvent', 'notFiredEvent', 'notHasTag', 'opened', 'notOpened', 'subscribedAfter', 'subscribedBefore'].includes(f.kind),\n )\n const upperBound = await mailer.adapter.count(hostFilter)\n return res.json({\n upperBound,\n approximate: hasMailerFilters,\n computedMs: Date.now() - t0,\n })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/schedule',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { scheduledAt, confirmedCount, respectRecipientTimezone } = req.body ?? {}\n if (!scheduledAt) return res.status(400).json({ error: 'scheduledAt_required' })\n const scheduled = new Date(scheduledAt)\n if (Number.isNaN(scheduled.getTime())) return res.status(400).json({ error: 'bad_scheduledAt' })\n\n const threshold = mailer.config.broadcastConfirmationThreshold\n if (typeof confirmedCount !== 'number') {\n return res.status(400).json({ error: 'confirmedCount_required' })\n }\n\n const set: Record<string, unknown> = {\n status: 'scheduled',\n scheduledAt: scheduled,\n confirmedCount,\n confirmedAt: new Date(),\n confirmedBy: (req as any).actor,\n updatedAt: new Date(),\n }\n if (respectRecipientTimezone) set.respectRecipientTimezone = true\n\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.schedule',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n diffSummary: `scheduled at ${scheduled.toISOString()} · confirmedCount=${confirmedCount} · threshold=${threshold}`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/cancel',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n await c.broadcasts.updateOne({ _id: b._id }, { $set: { status: 'cancelled', updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.cancel',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // Catch-all 404 for /api.\n r.use((_req, res) => res.status(404).json({ error: 'not_found' }))\n\n return r\n}\n\ntype AsyncHandler = (req: Request, res: Response, next: NextFunction) => Promise<unknown>\nfunction asyncHandler(fn: AsyncHandler) {\n return (req: Request, res: Response, next: NextFunction) => {\n fn(req, res, next).catch(next)\n }\n}\n\n/**\n * Sum inFlight and delayed across every queue the driver exposes. Returns\n * `null` for either count when the driver doesn't implement that accessor\n * (e.g. Agenda/Noop), so the UI can render \"—\" instead of a misleading 0.\n */\nasync function collectQueueCounts(\n mailer: Mailer,\n): Promise<{ inFlight: number | null; delayed: number | null }> {\n const qs = Object.values(mailer.queues) as Array<{\n getInFlightCount?: () => Promise<number | null>\n getDelayedCount?: () => Promise<number | null>\n }>\n const sum = async (key: 'getInFlightCount' | 'getDelayedCount'): Promise<number | null> => {\n let total = 0\n let supported = false\n for (const q of qs) {\n const fn = q[key]\n if (!fn) continue\n try {\n const v = await fn.call(q)\n if (v == null) continue\n total += v\n supported = true\n } catch {\n // Treat one queue's failure as \"unknown\" — surface as null upstream.\n return null\n }\n }\n return supported ? total : null\n }\n const [inFlight, delayed] = await Promise.all([sum('getInFlightCount'), sum('getDelayedCount')])\n return { inFlight, delayed }\n}\n\n// ---------------------------------------------------------------------------\n// Live stats aggregation\n//\n// The flow / template / broadcast list endpoints used to return zeros for\n// every metric because no rollup ever wrote to `stats.*` on those docs. We\n// now compute them on-the-fly from the canonical `sends` and `flowRuns`\n// collections. Optional slug/id filters keep single-resource reads cheap.\n// ---------------------------------------------------------------------------\n\ninterface FlowStats {\n activeRuns: number\n completedRuns: number\n sendsLast7Days: number\n sendsTotal: number\n}\nfunction emptyFlowStats(): FlowStats {\n return { activeRuns: 0, completedRuns: 0, sendsLast7Days: 0, sendsTotal: 0 }\n}\n\nasync function computeFlowStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, FlowStats>> {\n const out = new Map<string, FlowStats>()\n const match = slugFilter ? { flowSlug: slugFilter } : {}\n\n const runRows = await mailer.collections.flowRuns\n .aggregate<{ _id: { flowSlug: string; status: string }; count: number }>([\n { $match: match },\n { $group: { _id: { flowSlug: '$flowSlug', status: '$status' }, count: { $sum: 1 } } },\n ])\n .toArray()\n for (const row of runRows) {\n const slug = row._id.flowSlug\n if (!slug) continue\n const cur = out.get(slug) ?? emptyFlowStats()\n if (row._id.status === 'active') cur.activeRuns += row.count\n else if (row._id.status === 'completed') cur.completedRuns += row.count\n out.set(slug, cur)\n }\n\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n const sendRows = await mailer.collections.sends\n .aggregate<{ _id: string; total: number; last7: number }>([\n { $match: { flowRunId: { $ne: null } } },\n {\n $lookup: {\n from: mailer.collections.flowRuns.collectionName,\n localField: 'flowRunId',\n foreignField: '_id',\n as: 'run',\n pipeline: slugFilter\n ? [{ $match: { flowSlug: slugFilter } }, { $project: { flowSlug: 1 } }]\n : [{ $project: { flowSlug: 1 } }],\n },\n },\n { $unwind: '$run' },\n {\n $group: {\n _id: '$run.flowSlug',\n total: { $sum: 1 },\n last7: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of sendRows) {\n if (!row._id) continue\n const cur = out.get(row._id) ?? emptyFlowStats()\n cur.sendsTotal = row.total\n cur.sendsLast7Days = row.last7\n out.set(row._id, cur)\n }\n\n return out\n}\n\ninterface TemplateStats {\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n}\nfunction emptyTemplateStats(): TemplateStats {\n return { sent: 0, opened: 0, clicked: 0, bounced: 0, sentLast7Days: 0, lastSentAt: null }\n}\n\nasync function computeTemplateStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, TemplateStats>> {\n const out = new Map<string, TemplateStats>()\n const match: Record<string, unknown> = {}\n if (slugFilter) match.templateSlug = slugFilter\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: string\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n }>([\n { $match: match },\n {\n $group: {\n _id: '$templateSlug',\n sent: { $sum: 1 },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n sentLast7Days: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n lastSentAt: { $max: '$queuedAt' },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(row._id, {\n sent: row.sent,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n sentLast7Days: row.sentLast7Days,\n lastSentAt: row.lastSentAt ?? null,\n })\n }\n return out\n}\n\ninterface BroadcastStats {\n delivered: number\n opened: number\n clicked: number\n bounced: number\n}\nfunction emptyBroadcastStats(): BroadcastStats {\n return { delivered: 0, opened: 0, clicked: 0, bounced: 0 }\n}\n\nasync function computeBroadcastStats(\n mailer: Mailer,\n idFilter?: ObjectId,\n): Promise<Map<string, BroadcastStats>> {\n const out = new Map<string, BroadcastStats>()\n const match: Record<string, unknown> = { broadcastId: { $ne: null } }\n if (idFilter) match.broadcastId = idFilter\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: ObjectId\n delivered: number\n opened: number\n clicked: number\n bounced: number\n }>([\n { $match: match },\n {\n $group: {\n _id: '$broadcastId',\n delivered: { $sum: { $cond: [{ $eq: ['$status', 'delivered'] }, 1, 0] } },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(String(row._id), {\n delivered: row.delivered,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n })\n }\n return out\n}\n","/**\n * Setup-status: a small suite of synchronous checks the admin dashboard\n * surfaces as a banner. Each check returns an `ok | warn | error` verdict\n * with a short message and optional hint. The endpoint exists to catch the\n * \"silent misconfiguration that breaks sends\" class of bug — missing DOI\n * template, workers not running, fromDefaults on a domain that doesn't pass\n * the senderDomains registry, etc.\n */\n\nimport type { Mailer } from '../mailer.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { resolveSourceTags } from '../runner/dmarc.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\n\nexport type CheckSeverity = 'ok' | 'warn' | 'error'\n\nexport interface SetupCheck {\n /** Stable identifier, e.g. 'mongo', 'workers_heartbeat'. */\n name: string\n /** Human-readable label, e.g. \"MongoDB connection\". */\n label: string\n severity: CheckSeverity\n message: string\n /** Optional remediation hint shown when the user expands the row. */\n hint?: string\n}\n\nexport interface SetupStatus {\n overall: CheckSeverity\n generatedAt: string\n checks: SetupCheck[]\n}\n\nexport async function runSetupChecks(mailer: Mailer): Promise<SetupStatus> {\n const checks: SetupCheck[] = []\n\n checks.push(await checkMongo(mailer))\n checks.push(await checkQueue(mailer))\n if (mailer.config.queue.driver !== 'noop' && !mailer.config.workerless) {\n checks.push(await checkWorkersHeartbeat(mailer))\n }\n checks.push(await checkCircuitBreaker(mailer))\n checks.push(await checkDnsbl(mailer))\n checks.push(await checkPostmaster(mailer))\n checks.push(await checkSnds(mailer))\n const jmrp = checkJmrp(mailer)\n if (jmrp) checks.push(jmrp)\n checks.push(await checkDmarc(mailer))\n checks.push(...checkFromDefaultsAgainstRegistry(mailer))\n checks.push(...(await checkPublishedTemplates(mailer)))\n checks.push(await checkPostalAddress(mailer))\n checks.push(await checkDoiTemplate(mailer))\n\n const overall: CheckSeverity = checks.some((c) => c.severity === 'error')\n ? 'error'\n : checks.some((c) => c.severity === 'warn')\n ? 'warn'\n : 'ok'\n\n return {\n overall,\n generatedAt: new Date().toISOString(),\n checks,\n }\n}\n\nasync function checkMongo(mailer: Mailer): Promise<SetupCheck> {\n try {\n await mailer.db.admin().ping()\n return { name: 'mongo', label: 'MongoDB connection', severity: 'ok', message: 'reachable' }\n } catch (err) {\n return {\n name: 'mongo',\n label: 'MongoDB connection',\n severity: 'error',\n message: `MongoDB ping failed: ${(err as Error)?.message ?? err}`,\n hint: 'Mailery is configured against an unreachable Mongo. Sends, flow advancement, and admin reads will all fail.',\n }\n }\n}\n\nasync function checkQueue(mailer: Mailer): Promise<SetupCheck> {\n const driver = mailer.config.queue.driver\n if (driver === 'noop') {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'ok',\n message: 'driver: noop (synchronous-only mode)',\n }\n }\n try {\n await mailer.queues.send.getWaitingCount()\n return { name: 'queue', label: 'Queue driver', severity: 'ok', message: `driver: ${driver}` }\n } catch (err) {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'error',\n message: `${driver} queue is not responding: ${(err as Error)?.message ?? err}`,\n hint:\n driver === 'bull'\n ? 'Check Redis connectivity (queue.redis.url).'\n : 'Check the @hokify/agenda + Mongo connection.',\n }\n }\n}\n\nasync function checkWorkersHeartbeat(mailer: Mailer): Promise<SetupCheck> {\n // The aggregate doc's updatedAt is touched on every counter increment and\n // on every evaluate tick, so it's the canonical worker-heartbeat marker.\n const h = await mailer.collections.health.findOne(\n {},\n { sort: { updatedAt: -1 } },\n )\n const tickIntervalMs = mailer.config.tickIntervalSeconds * 1000\n const staleAfterMs = Math.max(tickIntervalMs * 3, 30_000) // tolerate a couple missed ticks\n\n if (!h) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'warn',\n message: 'no tick has run yet',\n hint: 'If your separate worker process is started, the heartbeat will appear within one tick interval. If you forgot to run `mailer.startWorkers()`, sends will sit queued indefinitely.',\n }\n }\n\n const ageMs = Date.now() - new Date(h.updatedAt).getTime()\n if (ageMs > staleAfterMs) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'error',\n message: `last tick ${humanDuration(ageMs)} ago (expected within ${humanDuration(tickIntervalMs)})`,\n hint: 'Workers appear to be down. Sends and flow advancement are halted. Restart your worker process (`mailer.startWorkers()`).',\n }\n }\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'ok',\n message: `last tick ${humanDuration(ageMs)} ago`,\n }\n}\n\nasync function checkCircuitBreaker(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.health.find({}).toArray()\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n\n if (buckets.length === 0) {\n // No telemetry yet (heartbeat-only state, no sends recorded). Claiming\n // \"healthy\" misleads — there's nothing to base it on.\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'ok',\n message: 'no telemetry yet',\n hint: 'The breaker tracks bounce / complaint rates per (sender domain × kind) and starts evaluating once enough sends have been recorded. Send some mail to populate.',\n }\n }\n\n const tripped = buckets.filter((d) => d.status === 'tripped')\n if (tripped.length > 0) {\n const summary = tripped\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'error',\n message: `tripped: ${summary}`,\n hint: 'Marketing sends are held for the listed bucket(s). Investigate the underlying bounce / complaint cause, then POST /api/health/resume (with optional senderDomain + kind to resume one bucket).',\n }\n }\n\n const degraded = buckets.filter((d) => d.status === 'degraded')\n if (degraded.length > 0) {\n const summary = degraded\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'warn',\n message: `degraded: ${summary}`,\n hint: 'Marketing sends still flow but failure rate is above the degraded threshold for the listed bucket(s). Investigate provider errors before they escalate to tripped.',\n }\n }\n\n return { name: 'circuit_breaker', label: 'Circuit breaker', severity: 'ok', message: 'healthy' }\n}\n\nasync function checkDnsbl(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.dnsblChecks.find({}).toArray()\n if (docs.length === 0) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: 'no checks run yet',\n hint: 'Checks run automatically once per dnsbl.intervalHours (default 24h). To run now, POST /api/dnsbl/recheck.',\n }\n }\n const listed = docs.filter((d) => d.result === 'listed')\n if (listed.length > 0) {\n const summary = listed\n .map((d) => `${d.target} on ${d.listLabel}`)\n .slice(0, 3)\n .join('; ')\n const more = listed.length > 3 ? ` (+${listed.length - 3} more)` : ''\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'error',\n message: `${listed.length} listing(s): ${summary}${more}`,\n hint: 'A sender domain or IP is listed on a public DNSBL. Investigate the listing source — most lists publish a removal procedure on their website. Mail to the affected (domain, kind) bucket will likely land in spam until delisted.',\n }\n }\n const errored = docs.filter((d) => d.result === 'error')\n if (errored.length === docs.length) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'warn',\n message: `all ${docs.length} checks errored`,\n hint: 'Lookups against block lists are failing — usually a DNS-resolution problem on the host running mailery, or a list rate-limiting your public resolver. Verify outbound DNS works.',\n }\n }\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: `clean (${docs.length} checks)`,\n }\n}\n\nasync function checkPostmaster(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.postmaster\n if (!cfg?.clientId || !cfg?.clientSecret || !cfg?.refreshToken) {\n // Postmaster is opt-in (needs OAuth setup) and only meaningful at >100/day\n // to Gmail. Treat \"not configured\" as ok so it doesn't spam every operator\n // with a permanent warning banner.\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n message: 'not configured (optional)',\n hint: 'Set mailer.config.postmaster with an OAuth client + refresh token to pull authoritative Gmail reputation data. Only meaningful at >100 sends/day to Gmail.',\n }\n }\n\n const snapshots = await mailer.collections.postmasterSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs once per postmaster.intervalHours (default 24h). To run now, POST /api/postmaster/refresh. Postmaster only reports for domains with >100 messages/day to Gmail; smaller senders see empty responses.',\n }\n }\n\n // Find the latest snapshot per domain (snapshots are already sorted by fetchedAt desc).\n const latestByDomain = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByDomain.has(s.domain)) latestByDomain.set(s.domain, s)\n }\n const bad: string[] = []\n const low: string[] = []\n for (const s of latestByDomain.values()) {\n if (s.domainReputation === 'BAD') bad.push(s.domain)\n else if (s.domainReputation === 'LOW') low.push(s.domain)\n }\n\n if (bad.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'error',\n message: `BAD reputation on ${bad.join(', ')}`,\n hint: 'Gmail considers these domains spammy. Most mail to Gmail addresses will land in spam folder. Marketing breaker has been tripped for affected domains. See docs/guide/warming.md §6 for recovery.',\n }\n }\n if (low.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: `LOW reputation on ${low.join(', ')}`,\n hint: 'Reputation has slipped below Medium. Review recent complaint + bounce activity, slow down marketing volume, and re-engage your most active segment only.',\n }\n }\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n // Includes REPUTATION_CATEGORY_UNSPECIFIED (\"no data yet\") domains —\n // surface that explicitly so the operator isn't misled.\n message: (() => {\n const tiers = new Set(Array.from(latestByDomain.values()).map((d) => d.domainReputation))\n const hasUnspec = tiers.has('REPUTATION_CATEGORY_UNSPECIFIED' as any)\n return `${latestByDomain.size} domain(s) tracked${hasUnspec ? ' (some have no reputation data yet)' : ', all High/Medium'}`\n })(),\n }\n}\n\n/**\n * JMRP enrolment is a manual one-time setup on the Microsoft sender-support\n * portal — there's no API to confirm completion. We surface a persistent\n * info-level reminder whenever the operator has configured a dedicated IP,\n * regardless of whether SNDS itself is set up. Operators can suppress this\n * by setting `dnsbl.dedicatedIps = []` once they've confirmed enrolment in\n * their runbook.\n */\nfunction checkJmrp(mailer: Mailer): SetupCheck | null {\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n if (!hasDedicatedIp) return null\n return {\n name: 'snds_jmrp',\n label: 'Microsoft JMRP enrolment',\n severity: 'ok',\n message: 'manual setup — confirm in your runbook',\n hint: 'Outlook spam complaints only land in mailery if you enrol each sending IP in JMRP. Visit https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx and complete the form for each IP. There is no API to verify completion; mailery shows this reminder whenever dedicatedIps is non-empty.',\n }\n}\n\nasync function checkSnds(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.snds\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n\n if (!cfg?.accessKey) {\n if (!hasDedicatedIp) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: 'not applicable (no dedicated IP)',\n hint: 'SNDS reports IP-level Outlook/Hotmail reputation. Only meaningful when you send from a dedicated IP. Skip unless you do.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'dedicated IP configured but SNDS access key not set',\n hint: 'Sign in at https://sendersupport.olc.protection.outlook.com/snds/ , request access for your IP(s), then set mailer.config.snds.accessKey to enable daily pulls. Also enrol in JMRP at https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx so Outlook complaints flow back to your suppression list.',\n }\n }\n\n const snapshots = await mailer.collections.sndsSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs every snds.intervalHours (default 24h). To run now, POST /api/snds/refresh. If you just enrolled, SNDS data can take 1-2 days to populate.',\n }\n }\n\n const latestByIp = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByIp.has(s.ip)) latestByIp.set(s.ip, s)\n }\n const red: string[] = []\n const yellow: string[] = []\n for (const s of latestByIp.values()) {\n if (s.filterResult === 'RED') red.push(s.ip)\n else if (s.filterResult === 'YELLOW') yellow.push(s.ip)\n }\n\n if (red.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'error',\n message: `RED filter on ${red.join(', ')}`,\n hint: 'Outlook/Hotmail is filtering mail from these IPs as spam. Reduce volume, audit recent complaints / trap hits, fix any auth alignment problems, and wait for reputation to recover (typically 1-2 weeks).',\n }\n }\n if (yellow.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: `YELLOW filter on ${yellow.join(', ')}`,\n hint: 'Outlook is putting some mail from these IPs in the junk folder. Investigate recent complaint rate and trap hits before reputation slips to RED.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: `${latestByIp.size} IP(s) tracked, all GREEN`,\n }\n}\n\nasync function checkDmarc(mailer: Mailer): Promise<SetupCheck> {\n const reportCount = await mailer.collections.dmarcReports.estimatedDocumentCount()\n if (reportCount === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: 'no reports ingested yet',\n hint: 'Publish DMARC `rua=mailto:<your-mailbox>` in DNS, then upload received reports via /admin/mailer/api/dmarc/upload (or drag-drop in the Health screen). RUA tells you who is sending mail as your domain — both legitimate sources and spoofers.',\n }\n }\n\n const since = new Date(Date.now() - 7 * 86_400_000)\n const recent = await mailer.collections.dmarcReports.find({ rangeEnd: { $gte: since } }).toArray()\n if (recent.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `no reports in the last 7 days (${reportCount} total)`,\n hint: 'Receivers email RUA reports daily. A gap suggests inbound delivery is broken or the rua= mailbox is no longer monitored. Check inbound mail flow.',\n }\n }\n\n // Merge config-defined tags with DB-defined tags so operator tags set via\n // the admin UI count. Both labeled (non-ignored) and ignored sources are\n // treated as \"known\" — operator already triaged them.\n const tagged = await resolveSourceTags(mailer.getRunnerContext())\n const known = new Set(Array.from(tagged.keys()))\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n const failures = await mailer.collections.dmarcFailures.find({ receivedAt: { $gte: since30 } }).toArray()\n const unknownFailing = failures.filter((f) => !known.has(f.sourceIp))\n\n if (unknownFailing.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: `${recent.length} report(s) this week, no failing unknown sources`,\n }\n }\n\n const totalFailing = unknownFailing.reduce((acc, f) => acc + f.count, 0)\n const ips = Array.from(new Set(unknownFailing.map((f) => f.sourceIp))).slice(0, 3)\n const more = unknownFailing.length > 3 ? ` (+${unknownFailing.length - 3} more)` : ''\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `${totalFailing} failing message(s) from ${ips.join(', ')}${more}`,\n hint: 'These IPs sent mail claiming to be from your domain that failed DMARC alignment. Tag known-legit sources in mailer.config.dmarc.knownSources to silence them. Untagged sources are likely either forgotten SaaS tools or active spoofing.',\n }\n}\n\nfunction checkFromDefaultsAgainstRegistry(mailer: Mailer): SetupCheck[] {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const out: SetupCheck[] = []\n const from = mailer.config.fromDefaults?.email\n const tx = mailer.config.transactionalFromDefaults?.email\n\n if (from) {\n const r = validateSenderDomain(from, 'marketing', registry)\n if (!r.ok) {\n out.push({\n name: 'from_defaults_marketing',\n label: 'fromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New marketing templates that fall back to fromDefaults will fail to publish.',\n })\n }\n }\n\n if (tx) {\n const r = validateSenderDomain(tx, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_from_defaults',\n label: 'transactionalFromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New transactional templates that fall back to transactionalFromDefaults will fail to publish.',\n })\n }\n } else if (from) {\n // No transactional defaults set; transactional creates will fall back to\n // fromDefaults. Check whether that fallback is valid for transactional.\n const r = validateSenderDomain(from, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_fallback',\n label: 'Transactional fallback',\n severity: 'warn',\n message: `transactionalFromDefaults is unset and fromDefaults (${from}) is invalid for transactional templates`,\n hint: 'Set transactionalFromDefaults to a transactional-kind domain, or set senderDomains entry for the existing one to \"both\".',\n })\n }\n }\n\n return out\n}\n\nasync function checkPublishedTemplates(mailer: Mailer): Promise<SetupCheck[]> {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const published = await mailer.collections.templates\n .find({ publishedAt: { $ne: null } }, { projection: { slug: 1, kind: 1, fromEmail: 1 } })\n .toArray()\n\n const broken: Array<{ slug: string; reason: string }> = []\n for (const tpl of published) {\n const r = validateSenderDomain(tpl.fromEmail, tpl.kind, registry)\n if (!r.ok) broken.push({ slug: tpl.slug, reason: r.reason })\n }\n\n if (broken.length === 0) return []\n const list = broken.slice(0, 5).map((b) => `${b.slug} (${b.reason})`).join('; ')\n const more = broken.length > 5 ? ` …and ${broken.length - 5} more` : ''\n return [\n {\n name: 'published_template_domains',\n label: 'Published templates',\n severity: 'error',\n message: `${broken.length} published template${broken.length === 1 ? '' : 's'} use a fromEmail that no longer matches senderDomains: ${list}${more}`,\n hint: 'These templates will still send with their stored fromEmail until re-published. Edit each template and republish to surface the validation, or update senderDomains.',\n },\n ]\n}\n\nasync function checkPostalAddress(mailer: Mailer): Promise<SetupCheck> {\n if (mailer.config.senderAddress) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'set' }\n }\n const marketingCount = await mailer.collections.templates.countDocuments({\n kind: 'marketing',\n publishedAt: { $ne: null },\n })\n if (marketingCount === 0) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'no published marketing templates yet' }\n }\n return {\n name: 'postal_address',\n label: 'CAN-SPAM postal address',\n severity: 'warn',\n message: `${marketingCount} published marketing template${marketingCount === 1 ? '' : 's'} but senderAddress is unset`,\n hint: 'CAN-SPAM requires a postal address in marketing emails. Set `senderAddress` in your Mailer config and reference the `{{senderAddress}}` render variable in your templates.',\n }\n}\n\nasync function checkDoiTemplate(mailer: Mailer): Promise<SetupCheck> {\n if (!mailer.config.requireDoubleOptIn) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: 'DOI not required' }\n }\n const tpl = await mailer.collections.templates.findOne({\n slug: mailer.config.doiTemplateSlug,\n publishedAt: { $ne: null },\n })\n if (tpl) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: `template \"${tpl.slug}\" published` }\n }\n return {\n name: 'doi_template',\n label: 'DOI template',\n severity: 'error',\n message: `requireDoubleOptIn is true but no published template with slug \"${mailer.config.doiTemplateSlug}\"`,\n hint: 'New subscriptions will silently fail to send confirmation emails. Create and publish a template with this slug, or unset requireDoubleOptIn.',\n }\n}\n\nfunction humanDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`\n return `${Math.round(ms / 3_600_000)}h`\n}\n","/**\n * List hygiene aggregations. Reports the engagement health of the\n * subscriber list: how many contacts engaged recently, how many are\n * stale, and what the bounce/complaint impact of sunsetting the stale\n * cohort would be.\n *\n * Pure read — no writes. Caller decides when to run.\n */\n\nimport type { RunnerContext } from './index.js'\n\nconst DAY_MS = 86_400_000\n\nexport const HYGIENE_BUCKETS = [\n { label: 'Engaged (last 30 days)', maxDays: 30 },\n { label: 'Engaged (31-60 days)', minDays: 30, maxDays: 60 },\n { label: 'Engaged (61-90 days)', minDays: 60, maxDays: 90 },\n { label: 'Engaged (91-180 days)', minDays: 90, maxDays: 180 },\n { label: 'Inactive (>180 days)', minDays: 180 },\n { label: 'Never engaged', neverEngaged: true },\n] as const\n\nexport interface HygieneBucket {\n label: string\n /** Lower bound of \"days since last engagement\" inclusive. Null for never-engaged. */\n minDays?: number | null\n /** Upper bound of \"days since last engagement\" exclusive. Null = unbounded. */\n maxDays?: number | null\n /** True for the \"never engaged\" bucket (sent but no open/click ever). */\n neverEngaged?: boolean\n count: number\n pctOfTotal: number\n}\n\nexport interface HygieneReport {\n totalSubscribers: number\n totalWithSends: number\n buckets: HygieneBucket[]\n sunsetCandidate: {\n /** Cohort: subscribed contacts whose lastEngagedAt is >180 days ago, or who have never engaged after >180 days of being subscribed. */\n count: number\n pctOfTotal: number\n /** Lifetime metrics for the cohort, when data exists. */\n cohortLifetime: {\n totalSends: number\n bouncedRate: number\n hardBouncedRate: number\n complaintRate: number\n } | null\n /** Projected impact: how recent (90d) rates would change if this cohort were sunset. */\n projectedImpact: {\n recentTotalSends: number\n recentBounced: number\n recentComplained: number\n cohortRecentSends: number\n cohortRecentBounced: number\n cohortRecentComplained: number\n currentOverallBounceRate: number\n projectedBounceRate: number\n currentOverallComplaintRate: number\n projectedComplaintRate: number\n } | null\n }\n computedAt: string\n}\n\nexport interface ComputeHygieneOptions {\n /** Override now() for tests. */\n now?: number\n /** Days of inactivity considered \"stale\" enough to sunset. Default 180. */\n sunsetThresholdDays?: number\n /** Window for projected-impact calculations. Default 90. */\n recentWindowDays?: number\n}\n\nexport async function computeListHygiene(\n ctx: RunnerContext,\n opts: ComputeHygieneOptions = {},\n): Promise<HygieneReport> {\n const now = opts.now ?? Date.now()\n const sunsetDays = opts.sunsetThresholdDays ?? 180\n const recentDays = opts.recentWindowDays ?? 90\n const recentCutoff = new Date(now - recentDays * DAY_MS)\n\n const totalSubscribers = await ctx.collections.subscriptions.countDocuments({ status: 'subscribed' })\n\n // Restrict the engagement aggregation to currently-subscribed contacts.\n // We materialize the subscriber externalId set in memory (one short\n // string per row). At ~10M subscribers this would be ~hundreds of MB —\n // a real concern at that scale. Below ~1M it's negligible. If list\n // sizes ever push past that, move to a server-side $lookup join inside\n // the sends aggregation.\n const subscribedIds = new Set<string>()\n {\n const cursor = ctx.collections.subscriptions\n .find({ status: 'subscribed' }, { projection: { externalId: 1 } })\n for await (const s of cursor) subscribedIds.add(s.externalId)\n }\n\n type EngagementRow = {\n _id: string\n lastOpened: Date | null\n lastClicked: Date | null\n firstSent: Date | null\n totalSends: number\n bounced: number\n hardBounced: number\n complained: number\n recentSends: number\n recentBounced: number\n recentComplained: number\n }\n\n // Single aggregation: group by externalId, computing engagement + lifetime\n // counts + recent-window counts in one pass. Cursor iteration avoids\n // loading the full per-contact map at once; allowDiskUse keeps Mongo from\n // OOMing on the $group stage at scale.\n const cursor = ctx.collections.sends.aggregate<EngagementRow>(\n [\n {\n $group: {\n _id: '$externalId',\n lastOpened: { $max: '$openedAt' },\n lastClicked: { $max: '$firstClickAt' },\n firstSent: { $min: '$queuedAt' },\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n hardBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $eq: ['$bounceType', 'hard'] }] },\n 1,\n 0,\n ],\n },\n },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n recentSends: { $sum: { $cond: [{ $gte: ['$queuedAt', recentCutoff] }, 1, 0] } },\n recentBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n recentComplained: {\n $sum: {\n $cond: [\n { $and: [{ $ne: ['$complainedAt', null] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n },\n },\n ],\n { allowDiskUse: true },\n )\n\n const buckets: HygieneBucket[] = HYGIENE_BUCKETS.map((b) => ({\n label: b.label,\n minDays: 'minDays' in b ? b.minDays : null,\n maxDays: 'maxDays' in b ? b.maxDays : null,\n neverEngaged: 'neverEngaged' in b && b.neverEngaged,\n count: 0,\n pctOfTotal: 0,\n }))\n\n let totalWithSends = 0\n let sunsetCount = 0\n\n const cohortLifetimeAcc = { totalSends: 0, bounced: 0, hardBounced: 0, complained: 0 }\n const cohortRecentAcc = { totalSends: 0, bounced: 0, complained: 0 }\n\n for await (const row of cursor) {\n if (!subscribedIds.has(row._id)) continue\n totalWithSends++\n\n const lastOpened = row.lastOpened ? new Date(row.lastOpened).getTime() : null\n const lastClicked = row.lastClicked ? new Date(row.lastClicked).getTime() : null\n const lastEngaged = lastOpened == null && lastClicked == null\n ? null\n : Math.max(lastOpened ?? 0, lastClicked ?? 0)\n\n let isSunset = false\n if (lastEngaged == null) {\n const firstSent = row.firstSent ? new Date(row.firstSent).getTime() : null\n buckets[5]!.count++\n if (firstSent != null && now - firstSent > sunsetDays * DAY_MS) {\n isSunset = true\n }\n } else {\n const daysSince = (now - lastEngaged) / DAY_MS\n if (daysSince <= 30) buckets[0]!.count++\n else if (daysSince <= 60) buckets[1]!.count++\n else if (daysSince <= 90) buckets[2]!.count++\n else if (daysSince <= 180) buckets[3]!.count++\n else {\n buckets[4]!.count++\n isSunset = true\n }\n }\n\n if (isSunset) {\n sunsetCount++\n cohortLifetimeAcc.totalSends += row.totalSends\n cohortLifetimeAcc.bounced += row.bounced\n cohortLifetimeAcc.hardBounced += row.hardBounced\n cohortLifetimeAcc.complained += row.complained\n cohortRecentAcc.totalSends += row.recentSends\n cohortRecentAcc.bounced += row.recentBounced\n cohortRecentAcc.complained += row.recentComplained\n }\n }\n\n for (const b of buckets) {\n b.pctOfTotal = totalSubscribers === 0 ? 0 : b.count / totalSubscribers\n }\n\n const cohortLifetime: HygieneReport['sunsetCandidate']['cohortLifetime'] =\n cohortLifetimeAcc.totalSends > 0\n ? {\n totalSends: cohortLifetimeAcc.totalSends,\n bouncedRate: cohortLifetimeAcc.bounced / cohortLifetimeAcc.totalSends,\n hardBouncedRate: cohortLifetimeAcc.hardBounced / cohortLifetimeAcc.totalSends,\n complaintRate: cohortLifetimeAcc.complained / cohortLifetimeAcc.totalSends,\n }\n : null\n\n // Recent-window overall stats are bounded by the date window and small at\n // any realistic volume.\n let projectedImpact: HygieneReport['sunsetCandidate']['projectedImpact'] = null\n const recentAll = await ctx.collections.sends\n .aggregate<{ totalSends: number; bounced: number; complained: number }>([\n { $match: { queuedAt: { $gte: recentCutoff } } },\n {\n $group: {\n _id: null,\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n\n if (recentAll[0] && recentAll[0].totalSends > 0) {\n const all = recentAll[0]\n const cohort = cohortRecentAcc\n const currentBounceRate = all.bounced / all.totalSends\n const currentComplaintRate = all.complained / all.totalSends\n const remainingSends = all.totalSends - cohort.totalSends\n const remainingBounces = all.bounced - cohort.bounced\n const remainingComplaints = all.complained - cohort.complained\n const projectedBounceRate = remainingSends > 0 ? remainingBounces / remainingSends : 0\n const projectedComplaintRate = remainingSends > 0 ? remainingComplaints / remainingSends : 0\n\n projectedImpact = {\n recentTotalSends: all.totalSends,\n recentBounced: all.bounced,\n recentComplained: all.complained,\n cohortRecentSends: cohort.totalSends,\n cohortRecentBounced: cohort.bounced,\n cohortRecentComplained: cohort.complained,\n currentOverallBounceRate: currentBounceRate,\n projectedBounceRate,\n currentOverallComplaintRate: currentComplaintRate,\n projectedComplaintRate,\n }\n }\n\n return {\n totalSubscribers,\n totalWithSends,\n buckets,\n sunsetCandidate: {\n count: sunsetCount,\n pctOfTotal: totalSubscribers === 0 ? 0 : sunsetCount / totalSubscribers,\n cohortLifetime,\n projectedImpact,\n },\n computedAt: new Date(now).toISOString(),\n }\n}\n","/**\n * Mail-Tester deliverability check.\n *\n * 1. Operator clicks \"Run deliverability check\" in the template editor.\n * 2. Mailery provisions a check (gets a unique test address from Mail-Tester).\n * 3. Mailery sends the rendered draft to that address via the operator's\n * default provider.\n * 4. Mailery polls Mail-Tester for the score (typically arrives 10-30s after\n * receipt) and caches it keyed on a content fingerprint.\n * 5. If the score is below `minScore` the publish endpoint refuses unless\n * the operator passes `bypassMailTester: true` in the publish request.\n *\n * The client interface is pluggable so tests inject a stub. Real\n * implementation hits https://mail-tester.com/api/.\n */\n\nimport crypto from 'node:crypto'\n\nimport type { MailTesterConfig } from '../config.js'\nimport type { MailTesterFeedback, MailTesterScoreDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface ProvisionedCheck {\n checkId: string\n emailAddress: string\n}\n\nexport interface MailTesterResult {\n ready: boolean\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n}\n\nexport interface MailTesterClient {\n provisionCheck(): Promise<ProvisionedCheck>\n fetchResult(checkId: string): Promise<MailTesterResult>\n}\n\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport function createMailTesterClient(\n cfg: MailTesterConfig,\n fetcher: Fetcher = globalThis.fetch,\n): MailTesterClient {\n const base = cfg.baseUrl ?? 'https://mail-tester.com/api'\n\n function sanitize(s: string): string {\n if (!cfg.apiKey) return s\n return s.split(cfg.apiKey).join('<redacted>').split(encodeURIComponent(cfg.apiKey)).join('<redacted>')\n }\n\n async function call(method: string, path: string, body?: unknown): Promise<any> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(`${base}/${encodeURIComponent(cfg.apiKey)}${path}`, {\n method,\n headers: { 'content-type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n signal: ctl.signal,\n })\n } catch (err: any) {\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} failed: ${sanitize(String(err?.message ?? err))}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n const text = await safeText(res)\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} → ${res.status}: ${sanitize(text)}`)\n }\n return res.json()\n }\n\n return {\n async provisionCheck() {\n const data = await call('POST', '/new')\n const checkId = String(data.check_id ?? data.checkId ?? '')\n const emailAddress = String(data.email_address ?? data.email ?? '')\n if (!checkId || !emailAddress) throw new Error('Mail-Tester /new returned an unexpected shape')\n return { checkId, emailAddress }\n },\n async fetchResult(checkId) {\n const data = await call('GET', `/${encodeURIComponent(checkId)}`)\n // Ready is decided independently from score finiteness so a malformed\n // score number can't accidentally surface as `score: 0` and trip the\n // publish gate.\n const ready = Boolean(data.ready ?? data.complete ?? data.score != null)\n const scoreRaw = Number(data.score)\n const score = Number.isFinite(scoreRaw) ? scoreRaw : 0\n const feedback: MailTesterFeedback[] = Array.isArray(data.feedback)\n ? data.feedback.map(normalizeFeedback)\n : []\n const rawSummary = typeof data.summary === 'string' ? data.summary : null\n return { ready: ready && Number.isFinite(scoreRaw), score, feedback, rawSummary }\n },\n }\n}\n\nfunction normalizeFeedback(raw: any): MailTesterFeedback {\n const severity = String(raw.severity ?? 'info').toLowerCase()\n return {\n category: String(raw.category ?? 'other'),\n severity: severity === 'error' || severity === 'warning' || severity === 'info' ? severity : 'info',\n message: String(raw.message ?? ''),\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// Content fingerprint + cache lookups\n// ---------------------------------------------------------------------------\n\nexport function mailTesterContentKey(input: { bodyHash: string; subject: string; fromEmail: string }): string {\n return crypto\n .createHash('sha256')\n .update(`${input.bodyHash}|${input.subject}|${input.fromEmail}`)\n .digest('hex')\n}\n\nexport async function findCachedScore(\n ctx: RunnerContext,\n contentKey: string,\n): Promise<MailTesterScoreDoc | null> {\n const doc = await ctx.collections.mailTesterScores.findOne({ contentKey })\n if (!doc) return null\n if (new Date(doc.expiresAt).getTime() < Date.now()) return null\n return doc\n}\n\nexport async function persistScore(\n ctx: RunnerContext,\n input: {\n templateSlug: string\n contentKey: string\n checkId: string\n result: MailTesterResult\n },\n): Promise<MailTesterScoreDoc> {\n const cfg = ctx.config.mailTester\n const hours = cfg?.cacheHours ?? 24\n const now = new Date()\n const expiresAt = new Date(now.getTime() + hours * 60 * 60 * 1000)\n const doc: MailTesterScoreDoc = {\n templateSlug: input.templateSlug,\n contentKey: input.contentKey,\n checkId: input.checkId,\n score: input.result.score,\n feedback: input.result.feedback,\n rawSummary: input.result.rawSummary,\n fetchedAt: now,\n expiresAt,\n }\n await ctx.collections.mailTesterScores.updateOne(\n { contentKey: input.contentKey },\n { $set: doc },\n { upsert: true },\n )\n return doc\n}\n\n// ---------------------------------------------------------------------------\n// Publish gate\n// ---------------------------------------------------------------------------\n\nexport interface MailTesterGateResult {\n allowed: boolean\n /** Reason for blocking. Null when allowed. */\n reason: string | null\n /** The cached score (if one exists for the content being published). */\n score: MailTesterScoreDoc | null\n /**\n * Why the gate blocked, for callers that render different guidance:\n * - 'low_score' — a score exists and is below minScore\n * - 'no_score' — requireScore is on and this content was never checked\n * Null when allowed.\n */\n code: 'low_score' | 'no_score' | null\n}\n\n/**\n * Check whether a publish is allowed under the Mail-Tester gate.\n *\n * Default mode (`requireScore` unset/false) blocks only content already known\n * to score below `minScore`. That is a ratchet on known-bad content, not a\n * gate: the content key covers body + subject + fromEmail, so any edit misses\n * the cache and publishes freely — a failing score is one whitespace change\n * away from irrelevant.\n *\n * With `requireScore: true`, a cache miss blocks too, so every publish is\n * backed by a score for that exact content. Costs one Mail-Tester credit per\n * content revision. Either mode is overridable per-request with\n * `bypassMailTester: true`.\n *\n * We never auto-trigger a check at publish time — that would send mail as a\n * side effect of a publish request.\n */\nexport async function evaluateMailTesterGate(\n ctx: RunnerContext,\n input: { bodyHash: string; subject: string; fromEmail: string },\n): Promise<MailTesterGateResult> {\n const cfg = ctx.config.mailTester\n if (!cfg?.apiKey) return { allowed: true, reason: null, score: null, code: null }\n\n const minScore = cfg.minScore ?? 8.0\n const key = mailTesterContentKey(input)\n const cached = await findCachedScore(ctx, key)\n\n if (!cached) {\n if (cfg.requireScore) {\n return {\n allowed: false,\n reason:\n 'No Mail-Tester score for this exact content. Run a deliverability check before publishing.',\n score: null,\n code: 'no_score',\n }\n }\n return { allowed: true, reason: null, score: null, code: null }\n }\n\n if (cached.score < minScore) {\n return {\n allowed: false,\n reason: `Mail-Tester score ${cached.score.toFixed(1)} is below minimum ${minScore.toFixed(1)}`,\n score: cached,\n code: 'low_score',\n }\n }\n return { allowed: true, reason: null, score: cached, code: null }\n}\n","/**\n * Public router — endpoints that must be reachable by email clients and\n * provider webhooks. Mount under your tracking base path (default `/m`).\n *\n * app.use('/m', createPublicRouter(mailer))\n *\n * Routes:\n * GET /open/:sendId.png — open pixel (records open, returns 1×1 PNG)\n * GET /click/:sendId/:linkId — click redirect (records click, 302 → target)\n * GET /unsub/:token — confirmation page (one-click POST link)\n * POST /unsub/:token — RFC 8058 one-click unsubscribe\n * POST /webhooks/:provider — inbound provider event webhook\n */\n\nimport express, { Router, type Request, type Response } from 'express'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { ObjectId } from 'mongodb'\n\nimport { sha256Hex, verifyUnsubscribeToken, verifyDoiToken } from '../tokens.js'\nimport type { Mailer } from '../mailer.js'\n\nexport interface PublicRouterOptions {\n /**\n * Path on disk where unsubscribe events fall back to when Mongo is degraded.\n * Defaults to /tmp/mailery-pending-unsubs.jsonl.\n */\n pendingUnsubsPath?: string\n}\n\n// 1×1 transparent PNG (43 bytes)\nconst PIXEL = Buffer.from(\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',\n 'base64',\n)\n\nexport function createPublicRouter(mailer: Mailer, opts: PublicRouterOptions = {}): Router {\n const router = Router()\n const pendingUnsubsPath = opts.pendingUnsubsPath ?? '/tmp/mailery-pending-unsubs.jsonl'\n\n // Parse JSON for webhooks — capture raw body for signature verification.\n router.use(\n '/webhooks',\n express.json({\n limit: '5mb',\n verify: (req: any, _res, buf) => {\n req.rawBody = buf\n },\n }),\n )\n\n // Pre-parsed JSON for the POST one-click unsubscribe path (RFC 8058 sends a\n // small form/JSON body; we accept either by reading the URL only).\n router.use('/unsub', express.urlencoded({ extended: false }))\n\n // -------------------------------------------------------------------------\n // GET /open/:sendId.png\n // -------------------------------------------------------------------------\n router.get('/open/:sendId.png', async (req: Request, res: Response) => {\n res.setHeader('Content-Type', 'image/png')\n res.setHeader('Content-Length', String(PIXEL.length))\n res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')\n res.status(200).end(PIXEL)\n\n // Async update — never block the response.\n const id = (req.params as any).sendId as string\n if (!ObjectId.isValid(id)) return\n const sendId = new ObjectId(id)\n try {\n const send = await mailer.collections.sends.findOne({ _id: sendId }, { projection: { openedAt: 1 } })\n if (!send) return\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: {\n openedAt: send.openedAt ?? new Date(),\n status: 'delivered' as const,\n },\n $inc: { openCount: 1 },\n },\n )\n } catch (err) {\n console.error('mailery: open pixel update failed', err)\n }\n })\n\n // -------------------------------------------------------------------------\n // GET /click/:sendId/:linkId\n // -------------------------------------------------------------------------\n router.get('/click/:sendId/:linkId', async (req: Request, res: Response) => {\n const { sendId: sendIdStr, linkId } = req.params as { sendId: string; linkId: string }\n if (!ObjectId.isValid(sendIdStr)) return res.status(400).end()\n const sendId = new ObjectId(sendIdStr)\n\n const send = await mailer.collections.sends.findOne(\n { _id: sendId },\n { projection: { links: 1, firstClickAt: 1 } },\n )\n if (!send) return res.status(404).end()\n\n const link = (send.links ?? []).find((l) => l.linkId === linkId)\n if (!link) return res.status(404).end()\n\n res.redirect(302, link.url)\n\n try {\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: { firstClickAt: send.firstClickAt ?? new Date() },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: link.url,\n linkId,\n clickedAt: new Date(),\n },\n },\n },\n )\n } catch (err) {\n console.error('mailery: click recording failed', err)\n }\n })\n\n // -------------------------------------------------------------------------\n // GET + POST /unsub/:token\n // -------------------------------------------------------------------------\n router.get('/unsub/:token', (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) return sendUnsubError(res, 'Invalid or expired link.')\n\n res.status(200).type('html').send(`<!doctype html>\n<html><head>\n <meta charset=\"utf-8\" />\n <title>Unsubscribe</title>\n <style>body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:48px auto;padding:0 16px;color:#1c1917;line-height:1.5}h1{font-size:20px}button{padding:10px 18px;background:#dc2626;color:#fff;border:0;border-radius:6px;font-size:14px;cursor:pointer}</style>\n</head><body>\n <h1>Confirm unsubscribe</h1>\n <p>Click the button below to unsubscribe <strong>${escapeHtml(decoded.email)}</strong>${decoded.scope === 'all' ? ' from everything' : ' from marketing emails'}.</p>\n <form method=\"POST\" action=\"${escapeHtml(req.originalUrl)}\">\n <button type=\"submit\">Unsubscribe</button>\n </form>\n</body></html>`)\n })\n\n router.post('/unsub/:token', async (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n res.status(200).end() // never 5xx; let provider stop retrying\n return\n }\n\n // Reply 200 immediately. INVARIANT 8: bulletproof unsubscribe.\n res.status(200).type('html').send('<!doctype html><html><body><p>You are unsubscribed.</p></body></html>')\n\n try {\n await mailer.unsubscribe(decoded.email, {\n scope: decoded.scope,\n reason: 'user_request',\n source: 'one-click',\n })\n } catch (err) {\n try {\n fs.appendFileSync(\n pendingUnsubsPath,\n JSON.stringify({ email: decoded.email, scope: decoded.scope, at: Date.now() }) + '\\n',\n )\n } catch (diskErr) {\n console.error('mailery: unsub disk fallback failed', { err, diskErr })\n }\n }\n })\n\n // -------------------------------------------------------------------------\n // GET /confirm-doi/:token\n // -------------------------------------------------------------------------\n router.get('/confirm-doi/:token', async (req: Request, res: Response) => {\n const token = (req.params as any).token as string\n const decoded = verifyDoiToken(token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n return res.status(400).type('html').send('<!doctype html><html><body><p>Confirmation link is invalid or expired.</p></body></html>')\n }\n const now = new Date()\n const result = await mailer.collections.subscriptions.updateOne(\n { externalId: decoded.externalId, status: 'pending_doi' },\n {\n $set: {\n status: 'subscribed',\n subscribedAt: now,\n doiConfirmedAt: now,\n doiIp: req.ip ?? null,\n doiUserAgent: (req.headers['user-agent'] as string | undefined) ?? null,\n updatedAt: now,\n },\n },\n )\n if (result.matchedCount === 0) {\n return res.status(200).type('html').send('<!doctype html><html><body><p>Already confirmed. Thanks.</p></body></html>')\n }\n try {\n await mailer.fire('subscription.confirmed', decoded.externalId, {}, `doi-confirmed:${decoded.externalId}`)\n } catch {\n /* swallow — subscription is confirmed regardless */\n }\n return res.status(200).type('html').send('<!doctype html><html><body><p>Thanks — you\\'re subscribed.</p></body></html>')\n })\n\n // -------------------------------------------------------------------------\n // POST /webhooks/:provider\n // -------------------------------------------------------------------------\n router.post('/webhooks/:provider', async (req: Request, res: Response) => {\n const providerName = (req.params as any).provider as string\n const provider = mailer.providers[providerName]\n if (!provider) return res.status(404).end()\n\n const rawBody = (req as any).rawBody as Buffer | undefined\n if (!rawBody) return res.status(400).end()\n\n const headers = lowercaseHeaders(req.headers)\n const valid = await provider.verifyWebhook(rawBody, headers)\n if (!valid) return res.status(401).end()\n\n const events = provider.parseWebhookEvents(req.body, headers)\n\n // Always 200 fast — fail-open, retry inbound is wasted bandwidth.\n res.status(200).end()\n\n // Preserve the original provider payload alongside each normalized event so the\n // audit trail isn't reduced to just our extracted fields. The raw body is the\n // full provider response array; we record it once per parsed event for clarity.\n const rawBodyRef = req.body as unknown\n for (const evt of events) {\n try {\n await mailer.collections.webhookEvents.updateOne(\n { provider: providerName, providerEventId: evt.providerEventId },\n {\n $setOnInsert: {\n provider: providerName,\n providerEventId: evt.providerEventId,\n eventType: evt.type,\n normalizedType: evt.type,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n receivedAt: new Date(),\n processed: false,\n raw: { normalized: evt, providerBody: rawBodyRef },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n console.error('mailery: webhook dedupe insert failed', err)\n }\n }\n\n if (events.length > 0) {\n try {\n await mailer.queues.webhook.add('webhook', { provider: providerName })\n } catch {\n /* will be picked up by next tick */\n }\n }\n\n // Bypass linting — `path` import retained for any future on-disk fallback.\n void path\n })\n\n return router\n}\n\nfunction sendUnsubError(res: Response, msg: string): Response {\n return res.status(400).type('html').send(`<!doctype html><html><body><p>${escapeHtml(msg)}</p></body></html>`)\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\nfunction lowercaseHeaders(h: any): Record<string, string> {\n const out: Record<string, string> = {}\n for (const k of Object.keys(h)) {\n const v = h[k]\n out[k.toLowerCase()] = Array.isArray(v) ? v.join(',') : String(v ?? '')\n }\n return out\n}\n\n// silence unused\nvoid sha256Hex\n","/**\n * Enumerable option lists for the union types in `./types.ts`. Used by the\n * admin client to render dropdowns + by tooling to enumerate the surface.\n *\n * Kept in `shared/` so the client and server agree on the canonical labels +\n * default constructors. Pure data + pure functions — no React, no DOM.\n */\n\nimport type { FlowStep, Predicate, SegmentFilter } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Flow step types\n// ---------------------------------------------------------------------------\n\nexport interface FlowStepKindOption {\n value: FlowStep['type']\n label: string\n /** Icon name from the client's icon set (lookup at render time). */\n icon: string\n /** Visual class on the canvas chip. */\n iconClass: string\n /** One-line description for tooltips / docs generation. */\n description: string\n}\n\nexport const FLOW_STEP_KINDS: readonly FlowStepKindOption[] = [\n { value: 'wait', label: 'Wait', icon: 'Clock', iconClass: 'wait', description: 'Pause the run for a duration before continuing.' },\n { value: 'condition', label: 'Condition', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Exit or skip on false.' },\n { value: 'branch', label: 'Branch', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Recurse into one of two sub-lists.' },\n { value: 'send', label: 'Send', icon: 'Mail', iconClass: 'send', description: 'Send a template to the contact.' },\n { value: 'tag', label: 'Tag', icon: 'Tag', iconClass: 'tag', description: 'Add or remove tags on the contact.' },\n { value: 'fire_event', label: 'Fire event', icon: 'Activity', iconClass: 'send', description: 'Insert a synthetic event (cross-flow handoff).' },\n { value: 'webhook', label: 'Webhook', icon: 'Webhook', iconClass: 'tag', description: 'POST to an external URL.' },\n { value: 'exit', label: 'Exit', icon: 'Exit', iconClass: 'exit', description: 'End the run with an optional reason.' },\n] as const\n\nexport function defaultFlowStep(type: FlowStep['type']): FlowStep {\n switch (type) {\n case 'wait': return { type: 'wait', value: 1, unit: 'days' }\n case 'condition': return { type: 'condition', test: { hasTag: 'engaged' }, ifFalse: 'exit' }\n case 'branch': return { type: 'branch', test: { hasTag: 'vip' }, ifTrueSteps: [], ifFalseSteps: [] }\n case 'send': return { type: 'send', templateSlug: '' }\n case 'tag': return { type: 'tag', addTags: [], removeTags: [] }\n case 'fire_event': return { type: 'fire_event', eventName: '' }\n case 'webhook': return { type: 'webhook', url: '', method: 'POST' }\n case 'exit': return { type: 'exit' }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Predicate kinds (the union variants of Predicate, minus composites)\n// ---------------------------------------------------------------------------\n\nexport type PredicateKind =\n | 'hasTag'\n | 'notHasTag'\n | 'fieldEquals'\n | 'fieldExists'\n | 'triggerPropertyEquals'\n | 'triggerPropertyTruthy'\n | 'hasFiredEvent'\n | 'notHasFiredEvent'\n | 'subscriptionStatus'\n | 'hasOpened'\n | 'hasClicked'\n | 'hasOpenedExcludingBots'\n | 'hasClickedExcludingBots'\n | 'openedAtLeastN'\n | 'clickedAtLeastN'\n\nexport interface PredicateKindOption {\n value: PredicateKind\n label: string\n /** True when this predicate's signal is noisy (Apple MPP, bot prefetch). */\n noisy?: boolean\n}\n\nexport const PREDICATE_KINDS: readonly PredicateKindOption[] = [\n { value: 'hasTag', label: 'has tag' },\n { value: 'notHasTag', label: 'does NOT have tag' },\n { value: 'fieldEquals', label: 'field equals' },\n { value: 'fieldExists', label: 'field exists' },\n { value: 'triggerPropertyEquals', label: 'trigger property equals' },\n { value: 'triggerPropertyTruthy', label: 'trigger property is set' },\n { value: 'hasFiredEvent', label: 'fired event' },\n { value: 'notHasFiredEvent', label: 'has NOT fired event' },\n { value: 'subscriptionStatus', label: 'subscription status' },\n { value: 'hasOpened', label: 'opened', noisy: true },\n { value: 'hasClicked', label: 'clicked', noisy: true },\n { value: 'hasOpenedExcludingBots', label: 'opened (excl. bots)' },\n { value: 'hasClickedExcludingBots', label: 'clicked (excl. bots)' },\n { value: 'openedAtLeastN', label: 'opened at least N' },\n { value: 'clickedAtLeastN', label: 'clicked at least N' },\n] as const\n\n/** Identify which kind of predicate this object is (or null for composites/unknown). */\nexport function predicateKind(p: Predicate | null | undefined): PredicateKind | null {\n if (!p) return null\n for (const k of PREDICATE_KINDS) {\n if (k.value in (p as object)) return k.value\n }\n return null\n}\n\nexport function defaultPredicate(kind: PredicateKind): Predicate {\n switch (kind) {\n case 'hasTag': return { hasTag: 'engaged' }\n case 'notHasTag': return { notHasTag: 'cold' }\n case 'fieldEquals': return { fieldEquals: { field: 'tier', value: 'Pro' } }\n case 'fieldExists': return { fieldExists: 'tier' }\n case 'triggerPropertyEquals': return { triggerPropertyEquals: { key: 'plan', value: 'pro' } }\n case 'triggerPropertyTruthy': return { triggerPropertyTruthy: 'wasReferred' }\n case 'hasFiredEvent': return { hasFiredEvent: 'Activated app' }\n case 'notHasFiredEvent': return { notHasFiredEvent: 'Cancelled' }\n case 'subscriptionStatus': return { subscriptionStatus: 'subscribed' }\n case 'hasOpened': return { hasOpened: { sinceFlowStart: true } }\n case 'hasClicked': return { hasClicked: { sinceFlowStart: true } }\n case 'hasOpenedExcludingBots': return { hasOpenedExcludingBots: { sinceFlowStart: true } }\n case 'hasClickedExcludingBots': return { hasClickedExcludingBots: { sinceFlowStart: true } }\n case 'openedAtLeastN': return { openedAtLeastN: { count: 1, withinDays: 7 } }\n case 'clickedAtLeastN': return { clickedAtLeastN: { count: 1, withinDays: 7 } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Segment filter kinds\n// ---------------------------------------------------------------------------\n\nexport type SegmentFilterKind = SegmentFilter['kind']\n\nexport interface SegmentFilterKindOption {\n value: SegmentFilterKind\n label: string\n /** Where the filter is evaluated: host-side via adapter, or mailer-side post-filter. */\n side: 'host' | 'mailer' | 'composite'\n}\n\nexport const SEGMENT_FILTER_KINDS: readonly SegmentFilterKindOption[] = [\n { value: 'subscriptionStatus', label: 'Subscription status', side: 'mailer' },\n { value: 'hasTag', label: 'Has tag', side: 'host' },\n { value: 'notHasTag', label: 'Does NOT have tag', side: 'host' },\n { value: 'fieldEquals', label: 'Field equals', side: 'host' },\n { value: 'fieldIn', label: 'Field in list', side: 'host' },\n { value: 'fieldExists', label: 'Field exists', side: 'host' },\n { value: 'firedEvent', label: 'Fired event', side: 'mailer' },\n { value: 'notFiredEvent', label: 'Has NOT fired event', side: 'mailer' },\n { value: 'subscribedAfter', label: 'Subscribed after', side: 'mailer' },\n { value: 'subscribedBefore', label: 'Subscribed before', side: 'mailer' },\n { value: 'opened', label: 'Opened', side: 'mailer' },\n { value: 'notOpened', label: 'Did NOT open', side: 'mailer' },\n { value: 'any', label: 'Any of (OR)', side: 'composite' },\n { value: 'not', label: 'NOT', side: 'composite' },\n] as const\n\nexport function defaultSegmentFilter(kind: SegmentFilterKind): SegmentFilter {\n switch (kind) {\n case 'subscriptionStatus': return { kind: 'subscriptionStatus', equals: 'subscribed' }\n case 'hasTag': return { kind: 'hasTag', tag: '' }\n case 'notHasTag': return { kind: 'notHasTag', tag: '' }\n case 'fieldEquals': return { kind: 'fieldEquals', field: '', value: '' }\n case 'fieldIn': return { kind: 'fieldIn', field: '', values: [] }\n case 'fieldExists': return { kind: 'fieldExists', field: '' }\n case 'firedEvent': return { kind: 'firedEvent', eventName: '', withinDays: 30 }\n case 'notFiredEvent': return { kind: 'notFiredEvent', eventName: '', withinDays: 90 }\n case 'subscribedAfter': return { kind: 'subscribedAfter', date: new Date(Date.now() - 30 * 86_400_000) }\n case 'subscribedBefore': return { kind: 'subscribedBefore', date: new Date() }\n case 'opened': return { kind: 'opened', withinDays: 14 }\n case 'notOpened': return { kind: 'notOpened', withinDays: 14 }\n case 'any': return { kind: 'any', filters: [] }\n case 'not': return { kind: 'not', filter: { kind: 'hasTag', tag: '' } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dedupe policies for event registration\n// ---------------------------------------------------------------------------\n\nexport interface DedupePolicyOption {\n value: 'once-per-contact' | 'once-per-day' | 'every-time'\n label: string\n description: string\n derivedKeyShape: string\n}\n\nexport const DEDUPE_POLICIES: readonly DedupePolicyOption[] = [\n {\n value: 'once-per-contact',\n label: 'Once per contact',\n description: 'Lifecycle markers (Created, Activated)',\n derivedKeyShape: '${externalId}:${eventName}',\n },\n {\n value: 'once-per-day',\n label: 'Once per day',\n description: 'Daily behaviors (Viewed Storyboard)',\n derivedKeyShape: '${externalId}:${eventName}:${YYYY-MM-DD}',\n },\n {\n value: 'every-time',\n label: 'Every time',\n description: 'True every-occurrence events (Imported)',\n derivedKeyShape: '${externalId}:${eventName}:${UUIDv4}',\n },\n] as const\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/adapters/vars.ts","../src/server/adapters/mongo.ts","../src/server/providers/sendgrid.ts","../src/shared/schemas.ts","../src/server/config.ts","../src/server/models/index.ts","../src/server/events.ts","../src/server/tokens.ts","../src/server/queues/bull.ts","../src/server/queues/agenda.ts","../src/server/queues/noop.ts","../src/server/queues/index.ts","../src/server/runner/triggers.ts","../src/server/templates/sender-domain.ts","../src/server/runner/health.ts","../src/server/runner/webhook.ts","../src/server/runner/predicate.ts","../src/server/runner/delivery-window.ts","../src/server/templates/render.ts","../src/server/runner/send.ts","../src/server/runner/suppression.ts","../src/server/runner/step.ts","../src/server/runner/sweep.ts","../src/server/runner/broadcasts.ts","../src/server/runner/bounce-promotion.ts","../src/server/runner/dnsbl.ts","../src/server/runner/postmaster.ts","../src/server/runner/snds.ts","../src/server/runner/dmarc.ts","../src/server/runner/tick.ts","../src/server/mailer.ts","../src/server/index.ts","../src/server/providers/null.ts","../src/server/templates/linter.ts","../src/server/api/admin.ts","../src/server/api/setup-status.ts","../src/server/runner/hygiene.ts","../src/server/runner/mail-tester.ts","../src/server/api/public.ts","../src/shared/options.ts"],"names":["RESERVED_VAR_KEYS","z","MongoContactAdapter","ObjectId","SendGridProvider","sgMail","crypto","IORedis","QUEUE_NAMES","counter","mjml2html","htmlToText","Handlebars","branchKey","DAY_MS","dns","net","psl","path","FETCH_TIMEOUT_MS","safeText","dst","processScheduledBroadcasts","assertNoReservedVarKeys","ObjectIdCtor","cursor","__filename","fileURLToPath","__dirname","Router","express","r","report","multer","fs"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * VarsAdapter — host-provided template variables, resolved at render time.\n *\n * The host declares a zod schema (the contract templates can rely on) plus a\n * `resolve` function that loads those values from the host's own database for\n * a given contact. Resolved keys are merged into the render context root, so\n * a schema key `user` is referenced in templates as `{{user.name}}`.\n *\n * The schema does double duty: it is exposed to the admin SPA as JSON Schema\n * (GET /vars-schema) to drive editor autocomplete, and the content linter\n * uses it to flag `{{paths}}` that don't exist.\n */\n\nimport { z } from 'zod'\n\nimport type { Contact } from '../../shared/types.js'\n\nexport interface VarsResolveInfo {\n /** Why the vars are being resolved. Previews and tests should be side-effect free. */\n reason: 'send' | 'preview' | 'test'\n /** Slug of the template being rendered, when known. */\n templateSlug?: string\n /** Slug of the flow the send belongs to, when the render is part of a flow run. */\n flowSlug?: string\n /** Name of the event that triggered the flow run, when applicable. */\n eventName?: string\n /**\n * Properties of the triggering event (`mailer.fire(name, id, properties)`).\n * This is how a resolver scopes lookups for account/topic flows:\n * `info.eventProperties?.accountId` tells it WHICH account the run is about.\n * Also available raw in templates as `{{event.*}}`.\n */\n eventProperties?: Record<string, unknown>\n}\n\nexport interface VarsAdapter<S extends z.ZodType = z.ZodType> {\n /** Contract for what `resolve` returns. Root keys become root template variables. */\n schema: S\n /** Load the variables for one contact from the host's data. */\n resolve(contact: Contact, info: VarsResolveInfo): Promise<z.infer<S>> | z.infer<S>\n}\n\n/**\n * Identity helper that pins `resolve`'s return type to `z.infer<schema>` —\n * without it, TypeScript widens the schema generic and the return type is\n * unchecked.\n *\n * const varsAdapter = defineVars({\n * schema: z.object({ user: z.object({ name: z.string() }) }),\n * async resolve(contact) {\n * return { user: { name: await lookupName(contact.externalId) } }\n * },\n * })\n */\nexport function defineVars<S extends z.ZodType>(adapter: VarsAdapter<S>): VarsAdapter<S> {\n return adapter\n}\n\n/**\n * Render-context keys mailery owns. Resolved vars never override these — a\n * schema that declares one is rejected at Mailer.init.\n */\nexport const RESERVED_VAR_KEYS = [\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n] as const\n\n/**\n * Throw if the schema's root keys collide with reserved render-context keys.\n * Called once at Mailer.init — fail fast, not per send.\n */\nexport function assertNoReservedVarKeys(adapter: VarsAdapter): void {\n const json = varsJsonSchema(adapter)\n const props = json && typeof json === 'object' ? (json as any).properties : undefined\n if (!props) return\n const clashes = RESERVED_VAR_KEYS.filter((k) => k in props)\n if (clashes.length > 0) {\n throw new Error(\n `varsAdapter schema declares reserved key(s): ${clashes.join(', ')}. ` +\n `These names are provided by mailery itself — rename them in your schema.`,\n )\n }\n}\n\n/** JSON Schema for the adapter's zod schema (wire format for the admin SPA + linter). */\nexport function varsJsonSchema(adapter: VarsAdapter): Record<string, unknown> {\n return z.toJSONSchema(adapter.schema, { io: 'output' }) as Record<string, unknown>\n}\n\n/**\n * Resolve vars for a contact, or `{}` when no adapter is configured.\n * Errors propagate to the caller — send paths let the queue retry, preview\n * paths surface the message to the operator.\n */\nexport async function resolveVars(\n adapter: VarsAdapter | undefined,\n contact: Contact,\n info: VarsResolveInfo,\n): Promise<Record<string, unknown>> {\n if (!adapter) return {}\n const resolved = await adapter.resolve(contact, info)\n if (!resolved || typeof resolved !== 'object') return {}\n // Belt-and-braces: drop reserved keys even if the init-time assert was\n // bypassed (e.g. a hand-built adapter object with a lying schema).\n const out: Record<string, unknown> = { ...(resolved as Record<string, unknown>) }\n for (const k of RESERVED_VAR_KEYS) delete out[k]\n return out\n}\n","/**\n * MongoContactAdapter — reads contacts directly from the host's `users`\n * collection (read-mostly; optional narrow tag writes). Mailer never\n * duplicates identity data — the host is the source of truth.\n */\n\nimport type { Collection, Db, Filter } from 'mongodb'\nimport { ObjectId } from 'mongodb'\n\nimport type {\n AdapterFilter,\n Contact,\n ContactAdapter,\n} from '../../shared/types.js'\n\nexport interface MongoContactAdapterOptions {\n db: Db\n collection: string\n emailField?: string\n idField?: string\n /** Path to the tags array on the user document. */\n tagsField?: string\n /** When true, mailer writes tags via `$addToSet` / `$pull` on the user doc. */\n tagsWritable?: boolean\n /** 'strings' = ['vip','beta'], 'objects' = [{ name: 'vip' }]. */\n tagsArrayShape?: 'strings' | 'objects'\n /** Customize the projection mailer sees. Defaults pick up email + tags + a few common fields. */\n toContact?: (userDoc: any) => Contact\n /** Customize how AdapterFilter becomes a Mongo query. */\n translateFilter?: (filter: AdapterFilter) => Filter<any>\n /** Per-call default for query() limit. */\n batchSize?: number\n}\n\nexport class MongoContactAdapter implements ContactAdapter {\n private readonly col: Collection<any>\n private readonly emailField: string\n private readonly idField: string\n private readonly tagsField: string | null\n private readonly tagsWritable: boolean\n private readonly tagsArrayShape: 'strings' | 'objects'\n private readonly toContactFn: (doc: any) => Contact\n private readonly translateFilterFn: (filter: AdapterFilter) => Filter<any>\n private readonly batchSize: number\n\n constructor(opts: MongoContactAdapterOptions) {\n this.col = opts.db.collection(opts.collection)\n this.emailField = opts.emailField ?? 'email'\n this.idField = opts.idField ?? '_id'\n this.tagsField = opts.tagsField ?? null\n this.tagsWritable = !!opts.tagsWritable\n this.tagsArrayShape = opts.tagsArrayShape ?? 'strings'\n this.toContactFn = opts.toContact ?? this.defaultToContact.bind(this)\n this.translateFilterFn = opts.translateFilter ?? this.defaultTranslateFilter.bind(this)\n this.batchSize = opts.batchSize ?? 500\n\n // Only expose tag write methods if the host opted in.\n if (this.tagsWritable && this.tagsField) {\n this.addTags = this.addTagsImpl.bind(this)\n this.removeTags = this.removeTagsImpl.bind(this)\n }\n }\n\n async getById(externalId: string): Promise<Contact | null> {\n const filter = this.idFilter(externalId)\n const doc = await this.col.findOne(filter)\n return doc ? this.toContactFn(doc) : null\n }\n\n async getByEmail(email: string): Promise<Contact | null> {\n const doc = await this.col.findOne({ [this.emailField]: email.toLowerCase() })\n return doc ? this.toContactFn(doc) : null\n }\n\n async getBatch(externalIds: string[]): Promise<Map<string, Contact>> {\n if (externalIds.length === 0) return new Map()\n const tryObjectId = externalIds.every(canBeObjectId)\n const ids: any[] = tryObjectId ? externalIds.map((s) => new ObjectId(s)) : externalIds\n const docs = await this.col.find({ [this.idField]: { $in: ids } }).toArray()\n const out = new Map<string, Contact>()\n for (const doc of docs) {\n const c = this.toContactFn(doc)\n out.set(c.externalId, c)\n }\n return out\n }\n\n async query(\n filter: AdapterFilter,\n opts: { limit: number; cursor?: string },\n ): Promise<{ contacts: Contact[]; nextCursor?: string }> {\n const query = this.translateFilterFn(filter)\n const limit = Math.min(opts.limit, this.batchSize)\n\n // Cursor is an ObjectId-or-externalId encoded as a string; we use it as a >\n // bound on the idField for stable pagination ordered by id.\n if (opts.cursor) {\n const cursorVal = canBeObjectId(opts.cursor) ? new ObjectId(opts.cursor) : opts.cursor\n ;(query as any)[this.idField] = { ...((query as any)[this.idField] ?? {}), $gt: cursorVal }\n }\n\n const docs = await this.col\n .find(query)\n .sort({ [this.idField]: 1 })\n .limit(limit + 1)\n .toArray()\n\n const hasMore = docs.length > limit\n const slice = hasMore ? docs.slice(0, limit) : docs\n const contacts = slice.map((d) => this.toContactFn(d))\n const last = slice[slice.length - 1]\n const nextCursor = hasMore && last ? String((last as any)[this.idField]) : undefined\n return { contacts, nextCursor }\n }\n\n async count(filter: AdapterFilter): Promise<number> {\n const query = this.translateFilterFn(filter)\n return await this.col.countDocuments(query)\n }\n\n addTags?: (externalId: string, tags: string[]) => Promise<void>\n removeTags?: (externalId: string, tags: string[]) => Promise<void>\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private idFilter(externalId: string): Filter<any> {\n if (this.idField === '_id' && canBeObjectId(externalId)) {\n return { _id: new ObjectId(externalId) } as Filter<any>\n }\n return { [this.idField]: externalId }\n }\n\n private defaultToContact(doc: any): Contact {\n const tagsRaw = this.tagsField ? doc[this.tagsField] ?? [] : []\n const tags: string[] =\n this.tagsArrayShape === 'objects'\n ? (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t.name ?? t))\n : (Array.isArray(tagsRaw) ? tagsRaw : []).map((t: any) => String(t))\n\n const externalId = String(doc[this.idField] ?? '')\n const email = String(doc[this.emailField] ?? '').toLowerCase()\n\n // Default projection: everything that's not _id / email / tags becomes a field.\n const fields: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(doc)) {\n if (k === this.idField || k === this.emailField || k === this.tagsField) continue\n fields[k] = v\n }\n\n return {\n externalId,\n email,\n tags,\n fields,\n timezone: typeof doc.timezone === 'string' ? doc.timezone : undefined,\n locale: typeof doc.locale === 'string' ? doc.locale : undefined,\n }\n }\n\n private defaultTranslateFilter(filter: AdapterFilter): Filter<any> {\n const q: Record<string, unknown> = {}\n\n if (filter.emailIn && filter.emailIn.length > 0) {\n q[this.emailField] = { $in: filter.emailIn.map((e) => e.toLowerCase()) }\n }\n if (filter.externalIdIn && filter.externalIdIn.length > 0) {\n const tryObjectId = filter.externalIdIn.every(canBeObjectId)\n q[this.idField] = {\n $in: tryObjectId ? filter.externalIdIn.map((s) => new ObjectId(s)) : filter.externalIdIn,\n }\n }\n if (filter.fieldEquals) {\n q[filter.fieldEquals.field] = filter.fieldEquals.value\n }\n if (filter.fieldIn) {\n q[filter.fieldIn.field] = { $in: filter.fieldIn.values }\n }\n if (filter.fieldExists) {\n q[filter.fieldExists] = { $exists: true }\n }\n if (filter.createdAfter || filter.createdBefore) {\n const r: any = {}\n if (filter.createdAfter) r.$gte = filter.createdAfter\n if (filter.createdBefore) r.$lte = filter.createdBefore\n q.createdAt = r\n }\n if (this.tagsField) {\n if (filter.hasTag) {\n q[this.tagsField] = filter.hasTag\n }\n if (filter.hasTagIn && filter.hasTagIn.length > 0) {\n q[this.tagsField] = { $in: filter.hasTagIn }\n }\n }\n return q\n }\n\n private async addTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? tags.map((name) => ({ name }))\n : tags\n await this.col.updateOne(this.idFilter(externalId), {\n $addToSet: { [this.tagsField]: { $each: value } } as any,\n })\n }\n\n private async removeTagsImpl(externalId: string, tags: string[]): Promise<void> {\n if (!this.tagsField || tags.length === 0) return\n const value =\n this.tagsArrayShape === 'objects'\n ? { $in: tags.map((name) => ({ name })) }\n : { $in: tags }\n await this.col.updateOne(this.idFilter(externalId), {\n $pull: { [this.tagsField]: value } as any,\n })\n }\n}\n\nfunction canBeObjectId(s: string): boolean {\n return typeof s === 'string' && /^[a-f0-9]{24}$/i.test(s)\n}\n","/**\n * SendGridProvider — sends mail through @sendgrid/mail, verifies the Event\n * Webhook signature with the ECDSA public key configured in SendGrid, and\n * normalizes inbound event payloads into our shared shape.\n *\n * Setup steps required on the SendGrid side (one-time):\n * 1. Authenticate sender domain (SPF, DKIM, DMARC).\n * 2. Configure event webhook → POST to https://your.host/m/webhooks/sendgrid\n * 3. Enable: delivered, open, click, bounce, dropped, spamreport, unsubscribe\n * 4. Generate Signed Event Webhook key → store as webhookVerificationKey\n */\n\nimport crypto from 'node:crypto'\nimport sgMail from '@sendgrid/mail'\n\nimport type {\n MailProvider,\n NormalizedEvent,\n SendArgs,\n SendResult,\n} from '../../shared/types.js'\n\nexport interface SendGridProviderOptions {\n apiKey: string\n /** ECDSA public key (PEM) from SendGrid → Settings → Mail Settings → Signed Event Webhook. */\n webhookVerificationKey?: string\n /** Send-rate cap per second (BullMQ group limiter consults this). */\n sendRatePerSecond?: number\n /** Sandbox mode bypasses actual delivery — useful in dev/test. */\n sandbox?: boolean\n}\n\nconst SG_SIG_HEADER = 'x-twilio-email-event-webhook-signature'\nconst SG_TS_HEADER = 'x-twilio-email-event-webhook-timestamp'\n\nexport class SendGridProvider implements MailProvider {\n readonly name = 'sendgrid'\n readonly sendRatePerSecond: number\n\n constructor(private readonly opts: SendGridProviderOptions) {\n sgMail.setApiKey(opts.apiKey)\n this.sendRatePerSecond = opts.sendRatePerSecond ?? 10\n }\n\n async send(args: SendArgs): Promise<SendResult> {\n const msg: sgMail.MailDataRequired = {\n to: args.to,\n from: { name: args.fromName, email: args.fromEmail },\n replyTo: args.replyTo,\n subject: args.subject,\n text: args.text,\n html: args.html,\n headers: args.headers,\n customArgs: args.messageMeta,\n trackingSettings: {\n // We do our own click/open tracking — let provider stay out of it.\n clickTracking: { enable: false, enableText: false },\n openTracking: { enable: false },\n },\n mailSettings: {\n sandboxMode: { enable: this.opts.sandbox ?? false },\n },\n }\n\n const [response] = await sgMail.send(msg)\n const providerId =\n (response.headers['x-message-id'] as string | undefined) ?? `sg-${Date.now()}`\n return {\n providerId,\n status: response.statusCode < 300 ? 'accepted' : 'rejected',\n raw: response,\n }\n }\n\n async verifyWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<boolean> {\n if (!this.opts.webhookVerificationKey) return false\n const sig = headers[SG_SIG_HEADER]\n const ts = headers[SG_TS_HEADER]\n if (!sig || !ts) return false\n\n const payload = Buffer.concat([Buffer.from(ts, 'utf8'), rawBody])\n try {\n const verifier = crypto.createVerify('sha256')\n verifier.update(payload)\n return verifier.verify(this.opts.webhookVerificationKey, sig, 'base64')\n } catch {\n return false\n }\n }\n\n parseWebhookEvents(payload: unknown): NormalizedEvent[] {\n if (!Array.isArray(payload)) return []\n return payload\n .map((raw) => normalizeSendGridEvent(raw))\n .filter((e): e is NormalizedEvent => e !== null)\n }\n}\n\nfunction normalizeSendGridEvent(e: any): NormalizedEvent | null {\n const type = mapEventType(e.event)\n if (!type) return null\n return {\n type,\n providerEventId: String(e.sg_event_id ?? e['smtp-id'] ?? `${e.event}-${e.timestamp}-${e.email}`),\n providerMessageId: String(e.sg_message_id ?? e['smtp-id'] ?? ''),\n email: String(e.email ?? '').toLowerCase(),\n occurredAt: new Date(Number(e.timestamp) * 1000),\n details: {\n bounceType:\n e.event === 'bounce' ? (e.type === 'bounce' ? 'hard' : 'soft') : undefined,\n bounceReason: e.reason,\n clickedUrl: e.url,\n userAgent: e.useragent,\n ipAddress: e.ip,\n },\n }\n}\n\nfunction mapEventType(sgEvent: string): NormalizedEvent['type'] | null {\n switch (sgEvent) {\n case 'delivered':\n return 'delivered'\n case 'open':\n return 'open'\n case 'click':\n return 'click'\n case 'bounce':\n case 'dropped':\n return 'bounce'\n case 'spamreport':\n return 'spam_report'\n case 'unsubscribe':\n case 'group_unsubscribe':\n return 'unsubscribe'\n default:\n return null\n }\n}\n","/**\n * Zod schemas for runtime validation at write boundaries — public API entry\n * points (fire, upsertSubscription, suppress, sendOneOff, scheduleBroadcast)\n * and REST handler bodies.\n *\n * Domain TypeScript types live in `./types.ts`; these schemas overlap with\n * those types deliberately so we get both compile-time and runtime checking\n * at the surfaces that need it.\n */\n\nimport { z } from 'zod'\n\n// ---------------------------------------------------------------------------\n// Primitive helpers\n// ---------------------------------------------------------------------------\n\nexport const externalIdSchema = z.string().min(1).max(256)\nexport const emailSchema = z.string().email().toLowerCase().trim()\nexport const slugSchema = z\n .string()\n .min(1)\n .max(128)\n .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/, 'must be kebab-case slug')\n\n// ---------------------------------------------------------------------------\n// Public API inputs\n// ---------------------------------------------------------------------------\n\nexport const fireInputSchema = z.object({\n eventName: z.string().min(1).max(128),\n externalId: externalIdSchema,\n properties: z.record(z.string(), z.unknown()).optional(),\n dedupeKey: z.string().min(1).max(512).optional(),\n})\nexport type FireInput = z.infer<typeof fireInputSchema>\n\nexport const registerEventSchema = z.object({\n name: z.string().min(1).max(128),\n dedupePolicy: z.enum(['once-per-contact', 'once-per-day', 'every-time']),\n})\nexport type RegisterEventInput = z.infer<typeof registerEventSchema>\n\nexport const upsertSubscriptionSchema = z.object({\n externalId: externalIdSchema,\n source: z.string().min(1).max(256),\n consentTimestamp: z.date().optional(),\n consentIp: z.string().optional(),\n consentUserAgent: z.string().optional(),\n})\nexport type UpsertSubscriptionInput = z.infer<typeof upsertSubscriptionSchema>\n\nexport const unsubscribeScopeSchema = z.enum(['all', 'marketing', 'transactional'])\nexport const unsubscribeReasonSchema = z.enum([\n 'user_request',\n 'hard_bounce',\n 'complaint',\n 'manual',\n 'gdpr_forget',\n 'list_cleaning',\n])\n\nexport const unsubscribeInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: unsubscribeReasonSchema.default('user_request'),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n})\nexport type UnsubscribeInput = z.infer<typeof unsubscribeInputSchema>\n\nexport const suppressInputSchema = z.object({\n email: emailSchema,\n scope: unsubscribeScopeSchema,\n reason: z.enum(['unsubscribed', 'hard_bounce', 'complaint', 'manual', 'list_cleaning', 'gdpr_forget']),\n source: z.string().max(256).default('manual'),\n notes: z.string().max(1024).optional(),\n expiresAt: z.date().optional(),\n})\nexport type SuppressInput = z.infer<typeof suppressInputSchema>\n\nexport const tagInputSchema = z.object({\n externalId: externalIdSchema,\n tag: z.string().min(1).max(128),\n})\nexport type TagInput = z.infer<typeof tagInputSchema>\n\nexport const abortFlowInputSchema = z.object({\n flowSlug: slugSchema,\n externalId: externalIdSchema,\n reason: z.string().min(1).max(200).optional(),\n /**\n * Restrict the abort to runs whose trigger event carried these properties —\n * e.g. `{ accountId }` to cancel one account's series while the same\n * contact's other accounts keep running. Omit to abort every active run for\n * the contact on this flow.\n *\n * Keys and values are both constrained because these go straight into a\n * Mongo query. Values are primitives only: an object value like\n * `{ $ne: null }` would reach the query as an OPERATOR and match every\n * scoped run, turning a one-account abort into abort-everything. Hosts\n * typically pass an id from a request body, so treat it as untrusted. The\n * key regex likewise blocks `$`-prefixed keys and dots (a dot would silently\n * extend the path and change match semantics).\n */\n matchTriggerProperties: z\n .record(\n z.string().regex(/^[A-Za-z0-9_]+$/),\n z.union([z.string(), z.number(), z.boolean(), z.null()]),\n )\n .optional(),\n})\nexport type AbortFlowInput = z.infer<typeof abortFlowInputSchema>\n\nexport const abortAllFlowsInputSchema = abortFlowInputSchema.omit({ flowSlug: true })\nexport type AbortAllFlowsInput = z.infer<typeof abortAllFlowsInputSchema>\n\nexport const sendOneOffInputSchema = z.object({\n templateSlug: slugSchema,\n externalId: externalIdSchema,\n vars: z.record(z.string(), z.unknown()).optional(),\n providerOverride: z.string().optional(),\n dedupeKey: z.string().min(1).max(512),\n})\nexport type SendOneOffInput = z.infer<typeof sendOneOffInputSchema>\n\n// ---------------------------------------------------------------------------\n// Flow step + predicate schemas (mirror types.ts)\n// ---------------------------------------------------------------------------\n\nexport const flowStepSchema: z.ZodType<unknown> = z.lazy(() =>\n z.discriminatedUnion('type', [\n z.object({\n type: z.literal('wait'),\n value: z.number().int().positive(),\n unit: z.enum(['minutes', 'hours', 'days', 'weeks']),\n }),\n z.object({\n type: z.literal('condition'),\n test: predicateSchema,\n ifFalse: z.enum(['continue', 'exit']),\n }),\n z.object({\n type: z.literal('branch'),\n test: predicateSchema,\n ifTrueSteps: z.array(flowStepSchema),\n ifFalseSteps: z.array(flowStepSchema),\n }),\n z.object({\n type: z.literal('send'),\n templateSlug: slugSchema,\n providerOverride: z.string().optional(),\n vars: z.record(z.string(), z.unknown()).optional(),\n delivery: z\n .object({\n weekdaysOnly: z.boolean().optional(),\n timeOfDay: z.string().regex(/^([01]\\d|2[0-3]):[0-5]\\d$/, 'expected HH:mm').optional(),\n useContactTimezone: z.boolean().optional(),\n timezone: z.string().optional(),\n })\n .optional(),\n }),\n z.object({\n type: z.literal('tag'),\n addTags: z.array(z.string()).optional(),\n removeTags: z.array(z.string()).optional(),\n }),\n z.object({\n type: z.literal('fire_event'),\n eventName: z.string().min(1).max(128),\n properties: z.record(z.string(), z.unknown()).optional(),\n }),\n z.object({\n type: z.literal('webhook'),\n url: z.string().url(),\n method: z.enum(['POST', 'PUT']).optional(),\n payload: z.record(z.string(), z.unknown()).optional(),\n failureMode: z.enum(['soft', 'fail_run']).optional(),\n }),\n z.object({\n type: z.literal('exit'),\n reason: z.string().optional(),\n }),\n ]),\n)\n\nexport const predicateSchema: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.object({ hasTag: z.string() }),\n z.object({ notHasTag: z.string() }),\n z.object({ fieldEquals: z.object({ field: z.string(), value: z.unknown() }) }),\n z.object({ fieldExists: z.string() }),\n z.object({\n triggerPropertyEquals: z.object({\n key: z.string().min(1),\n value: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n }),\n }),\n z.object({ triggerPropertyTruthy: z.string().min(1) }),\n z.object({\n hasFiredEvent: z.string(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n notHasFiredEvent: z.string(),\n withinDays: z.number().int().positive().optional(),\n }),\n z.object({\n subscriptionStatus: z.enum(['subscribed', 'unsubscribed', 'pending_doi', 'bounced', 'complained']),\n }),\n z.object({\n hasOpened: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClicked: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasOpenedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n hasClickedExcludingBots: z.object({\n templateSlug: slugSchema.optional(),\n sinceFlowStart: z.boolean().optional(),\n withinDays: z.number().int().positive().optional(),\n }),\n }),\n z.object({\n openedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({\n clickedAtLeastN: z.object({ count: z.number().int().positive(), withinDays: z.number().int().positive() }),\n }),\n z.object({ all: z.array(predicateSchema) }),\n z.object({ any: z.array(predicateSchema) }),\n z.object({ not: predicateSchema }),\n ]),\n)\n","/**\n * Mailer configuration shape. Required + optional surfaces with sane defaults.\n */\n\nimport type { Db } from 'mongodb'\nimport type Handlebars from 'handlebars'\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport type { QueueDriverConfig } from './queues/types.js'\nimport type { SenderDomainRegistry } from './templates/sender-domain.js'\nimport type { VarsAdapter } from './adapters/vars.js'\n\nexport type { SenderDomainConfig, SenderDomainRegistry } from './templates/sender-domain.js'\n\nexport interface RedisOptions {\n host?: string\n port?: number\n password?: string\n url?: string\n db?: number\n username?: string\n tls?: boolean\n}\n\nexport interface DnsblListSpec {\n /** DNS suffix to query, e.g. `'dbl.spamhaus.org'`. */\n host: string\n /** Display label for the UI, e.g. `'Spamhaus DBL'`. */\n label: string\n}\n\nexport interface DnsblConfig {\n /** Domain block lists (DBLs) — queried as `<domain>.<host>`. */\n domainLists?: DnsblListSpec[]\n /** IP block lists — queried as `<reversed-octets>.<host>`. */\n ipLists?: DnsblListSpec[]\n /** Dedicated sending IPs to check. Most operators on shared ESPs leave empty. */\n dedicatedIps?: string[]\n /** Hours between automatic runs. Default 24. Set to 0 to disable scheduled runs. */\n intervalHours?: number\n}\n\nexport const DEFAULT_DOMAIN_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'dbl.spamhaus.org', label: 'Spamhaus DBL' },\n { host: 'multi.surbl.org', label: 'SURBL' },\n { host: 'multi.uribl.com', label: 'URIBL' },\n]\n\nexport const DEFAULT_IP_DNSBL_LISTS: DnsblListSpec[] = [\n { host: 'zen.spamhaus.org', label: 'Spamhaus ZEN' },\n { host: 'b.barracudacentral.org', label: 'Barracuda' },\n { host: 'dnsbl.sorbs.net', label: 'SORBS' },\n { host: 'bl.spamcop.net', label: 'SpamCop' },\n]\n\nexport interface MailTesterConfig {\n /** API key from your Mail-Tester paid plan. */\n apiKey: string\n /** Minimum score (0-10) below which publish is blocked. Default 8.0. */\n minScore?: number\n /**\n * When true, publishing content that has no cached score is blocked too —\n * the operator must run a deliverability check for that exact content first.\n * Default false, which only blocks content already known to score below\n * `minScore`; in that mode any edit (even whitespace) changes the content\n * key, misses the cache, and publishes freely.\n */\n requireScore?: boolean\n /**\n * How long a successful score remains cached for the same content. Default 24.\n * Re-publishing the same body within the window does not burn a credit.\n */\n cacheHours?: number\n /** API base URL. Defaults to `https://mail-tester.com/api`. Override for staging or alternate provider. */\n baseUrl?: string\n}\n\nexport interface DmarcSourceTag {\n /** Source IP, e.g. `'149.72.45.10'`. */\n ip: string\n /** Operator-provided label, e.g. `'SendGrid (transactional)'` or `'Hubspot'`. */\n label: string\n /** When true, ignore failures from this source in the alignment-trend headline. */\n ignored?: boolean\n}\n\nexport interface DmarcConfig {\n /**\n * Operator-tagged sources. After RUA reports start arriving, the operator\n * marks each source IP as known/legit (with a label) or rogue. Tagged\n * sources are excluded from the headline failure count, surfacing only\n * unknown senders.\n */\n knownSources?: DmarcSourceTag[]\n /**\n * How many days of failure rows to retain. Default 90. Older rows are\n * trimmed by the daily tick to keep the collection bounded.\n */\n retentionDays?: number\n}\n\nexport interface SndsConfig {\n /**\n * SNDS automated-access key. Obtained per-account from the SNDS portal at\n * https://sendersupport.olc.protection.outlook.com/snds/ once each\n * sending IP has been added and verified.\n */\n accessKey: string\n /**\n * Optional IP filter — when set, only rows for these IPs are persisted.\n * Useful when an SNDS account covers a wider IP pool than this mailery\n * deployment uses. Defaults to keeping all rows the API returns.\n */\n ips?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface PostmasterConfig {\n /** OAuth client ID from a Google Cloud project with Postmaster Tools API enabled. */\n clientId: string\n clientSecret: string\n /**\n * A refresh token obtained via the OAuth consent flow with scope\n * `https://www.googleapis.com/auth/postmaster.readonly` for the user that\n * verified the domain(s) in Postmaster Tools. See\n * docs/guide/deliverability.md → \"Google Postmaster Tools\" for the\n * one-time setup procedure.\n */\n refreshToken: string\n /**\n * Domains to pull data for. When omitted, mailery uses every domain from the\n * senderDomains registry plus the From defaults. Each must be verified in\n * Postmaster Tools under the same Google account.\n */\n domains?: string[]\n /** Hours between automatic pulls. Default 24. Set to 0 to disable scheduled pulls. */\n intervalHours?: number\n}\n\nexport interface CircuitBreakerThresholds {\n /** Trip when last-hour hard-bounce rate >= this percent (e.g. 2 = 2%). */\n hardBounceRatePctTrip: number\n complaintRatePctTrip: number\n combinedBounceRatePctTrip: number\n failedToSendRatePctDegrade: number\n windowMinutes: number\n minSendsBeforeEval: number\n}\n\nexport interface MailerConfig {\n // ---- Storage --------------------------------------------------------------\n db: Db\n collectionPrefix?: string\n adapter: ContactAdapter\n /**\n * Optional host-provided template variables. `resolve(contact)` runs at\n * send/preview/test render time; its result is merged into the template\n * context root (schema key `user` → `{{user.name}}`). The zod schema\n * drives admin-editor autocomplete and the `unknown_variable` lint rule.\n * Build one with `defineVars({ schema, resolve })`.\n */\n varsAdapter?: VarsAdapter<any>\n\n // ---- Queue ----------------------------------------------------------------\n /**\n * Queue driver selection. One of:\n * - `{ driver: 'bull', redis: ... }` — BullMQ (default for prod; requires Redis)\n * - `{ driver: 'agenda' }` — @hokify/agenda using this Mongo (no Redis required, single-process)\n * - `{ driver: 'noop' }` — no background workers (tests, synchronous-only hosts)\n */\n queue: QueueDriverConfig\n\n // ---- Providers ------------------------------------------------------------\n providers: Record<string, MailProvider>\n defaultProvider: string\n defaultTransactionalProvider?: string\n\n // ---- Identity / URLs ------------------------------------------------------\n publicUrl: string\n unsubscribeSecret: string\n senderAddress?: string\n fromDefaults?: { name: string; email: string }\n transactionalFromDefaults?: { name: string; email: string }\n /**\n * Optional registry of sender domains by kind. When set, mailery enforces at\n * template publish time that a template's `fromEmail` domain is declared and\n * matches the template's `kind`. Used to keep marketing reputation isolated\n * from transactional reputation by sending from separate verified domains.\n *\n * Domains are case-insensitive. If unset, no enforcement happens.\n */\n senderDomains?: SenderDomainRegistry\n\n // ---- Compliance -----------------------------------------------------------\n requireDoubleOptIn?: boolean\n unsubscribeTokenLifetimeDays?: number\n transactionalRespectUnsubscribe?: boolean\n /** Slug of the transactional template sent for DOI confirmation. Defaults to 'doi-confirmation'. */\n doiTemplateSlug?: string\n /** How long the DOI token stays valid. Default 7 days. */\n doiTokenLifetimeDays?: number\n\n // ---- Circuit breaker ------------------------------------------------------\n circuitBreaker?: Partial<CircuitBreakerThresholds>\n\n // ---- DNSBL monitoring -----------------------------------------------------\n /**\n * Daily DNS-based block-list checks on sender domains and (optionally) any\n * dedicated sending IPs. Results surface in setup-status and on the Health\n * screen. No external API needed — plain DNS lookups.\n */\n dnsbl?: DnsblConfig\n\n // ---- Google Postmaster Tools ---------------------------------------------\n /**\n * Pulls daily reputation tiers + spam ratio + auth pass rates from Google\n * Postmaster Tools. Trips the (domain × marketing) circuit breaker when a\n * domain falls to reputation `BAD`. Only meaningful at >100/day to Gmail.\n */\n postmaster?: PostmasterConfig\n\n // ---- Microsoft SNDS ------------------------------------------------------\n /**\n * Pulls daily Outlook/Hotmail/Live IP reputation from Microsoft's Smart\n * Network Data Services. IP-level rather than domain-level — only useful\n * if you send from a dedicated IP. Visibility-only: RED filter results\n * surface as a setup-status error, no auto-trip.\n */\n snds?: SndsConfig\n\n // ---- Mail-Tester deliverability check ------------------------------------\n /**\n * Optional Mail-Tester integration. When set, the template editor exposes\n * a \"Run deliverability check\" button that sends a copy of the rendered\n * draft to a Mail-Tester address and polls for a score (0-10) covering\n * SpamAssassin verdict, auth alignment, content red flags, and link\n * reputation. Score < minScore blocks publish until re-run or overridden.\n */\n mailTester?: MailTesterConfig\n\n // ---- DMARC aggregate report ingestion ------------------------------------\n /**\n * DMARC RUA aggregate reports tell you who is sending mail that claims to\n * be from your domain — both legitimate sources and spoofers. Operator\n * uploads the report attachments (or POSTs them via SendGrid Inbound Parse\n * to /admin/mailer/api/dmarc/upload). Mailery decompresses, parses, and\n * surfaces alignment failures + unknown senders.\n */\n dmarc?: DmarcConfig\n\n // ---- Broadcast safety + throughput ---------------------------------------\n broadcastConfirmationThreshold?: number\n broadcastEnqueueBatchSize?: number\n broadcastEnqueueMaxWaiting?: number\n\n // ---- Worker behavior ------------------------------------------------------\n workerless?: boolean\n tickIntervalSeconds?: number\n sendConcurrency?: number\n sendRatePerSecond?: number\n softBouncePromotionThreshold?: number\n softBouncePromotionWindowDays?: number\n webhookRetryAttempts?: number\n sendRetryAttempts?: number\n\n // ---- Tracking -------------------------------------------------------------\n trackOpens?: boolean\n trackClicks?: boolean\n storeTrackingIp?: boolean\n storeRenderedBody?: boolean\n\n // ---- Hooks ----------------------------------------------------------------\n getAdminActor?: (req: any) => string\n onCircuitBreakerTrip?: (info: { reason: string; rates: Record<string, number> }) => Promise<void> | void\n onSendFailure?: (info: { send: any; error: Error }) => Promise<void> | void\n handlebarsHelpers?: Record<string, Handlebars.HelperDelegate>\n}\n\nexport type ResolvedConfig = Required<\n Pick<\n MailerConfig,\n | 'collectionPrefix'\n | 'requireDoubleOptIn'\n | 'unsubscribeTokenLifetimeDays'\n | 'transactionalRespectUnsubscribe'\n | 'doiTemplateSlug'\n | 'doiTokenLifetimeDays'\n | 'broadcastConfirmationThreshold'\n | 'broadcastEnqueueBatchSize'\n | 'broadcastEnqueueMaxWaiting'\n | 'workerless'\n | 'tickIntervalSeconds'\n | 'sendConcurrency'\n | 'sendRatePerSecond'\n | 'softBouncePromotionThreshold'\n | 'softBouncePromotionWindowDays'\n | 'webhookRetryAttempts'\n | 'sendRetryAttempts'\n | 'trackOpens'\n | 'trackClicks'\n | 'storeTrackingIp'\n | 'storeRenderedBody'\n >\n> & {\n circuitBreaker: CircuitBreakerThresholds\n} & MailerConfig\n\nexport const DEFAULTS = {\n collectionPrefix: 'mailer_',\n requireDoubleOptIn: false,\n unsubscribeTokenLifetimeDays: 90,\n transactionalRespectUnsubscribe: false,\n doiTemplateSlug: 'doi-confirmation',\n doiTokenLifetimeDays: 7,\n broadcastConfirmationThreshold: 1000,\n broadcastEnqueueBatchSize: 1000,\n broadcastEnqueueMaxWaiting: 5000,\n workerless: false,\n tickIntervalSeconds: 60,\n sendConcurrency: 5,\n sendRatePerSecond: 10,\n softBouncePromotionThreshold: 3,\n softBouncePromotionWindowDays: 30,\n webhookRetryAttempts: 3,\n sendRetryAttempts: 4,\n trackOpens: true,\n trackClicks: true,\n storeTrackingIp: false,\n storeRenderedBody: false,\n} as const\n\nexport const CIRCUIT_BREAKER_DEFAULTS: CircuitBreakerThresholds = {\n hardBounceRatePctTrip: 2,\n complaintRatePctTrip: 0.3,\n combinedBounceRatePctTrip: 5,\n failedToSendRatePctDegrade: 10,\n windowMinutes: 60,\n minSendsBeforeEval: 100,\n}\n\nexport function resolveConfig(c: MailerConfig): ResolvedConfig {\n return {\n ...c,\n collectionPrefix: c.collectionPrefix ?? DEFAULTS.collectionPrefix,\n requireDoubleOptIn: c.requireDoubleOptIn ?? DEFAULTS.requireDoubleOptIn,\n unsubscribeTokenLifetimeDays: c.unsubscribeTokenLifetimeDays ?? DEFAULTS.unsubscribeTokenLifetimeDays,\n transactionalRespectUnsubscribe: c.transactionalRespectUnsubscribe ?? DEFAULTS.transactionalRespectUnsubscribe,\n doiTemplateSlug: c.doiTemplateSlug ?? DEFAULTS.doiTemplateSlug,\n doiTokenLifetimeDays: c.doiTokenLifetimeDays ?? DEFAULTS.doiTokenLifetimeDays,\n broadcastConfirmationThreshold: c.broadcastConfirmationThreshold ?? DEFAULTS.broadcastConfirmationThreshold,\n broadcastEnqueueBatchSize: c.broadcastEnqueueBatchSize ?? DEFAULTS.broadcastEnqueueBatchSize,\n broadcastEnqueueMaxWaiting: c.broadcastEnqueueMaxWaiting ?? DEFAULTS.broadcastEnqueueMaxWaiting,\n workerless: c.workerless ?? DEFAULTS.workerless,\n tickIntervalSeconds: c.tickIntervalSeconds ?? DEFAULTS.tickIntervalSeconds,\n sendConcurrency: c.sendConcurrency ?? DEFAULTS.sendConcurrency,\n sendRatePerSecond: c.sendRatePerSecond ?? DEFAULTS.sendRatePerSecond,\n softBouncePromotionThreshold: c.softBouncePromotionThreshold ?? DEFAULTS.softBouncePromotionThreshold,\n softBouncePromotionWindowDays: c.softBouncePromotionWindowDays ?? DEFAULTS.softBouncePromotionWindowDays,\n webhookRetryAttempts: c.webhookRetryAttempts ?? DEFAULTS.webhookRetryAttempts,\n sendRetryAttempts: c.sendRetryAttempts ?? DEFAULTS.sendRetryAttempts,\n trackOpens: c.trackOpens ?? DEFAULTS.trackOpens,\n trackClicks: c.trackClicks ?? DEFAULTS.trackClicks,\n storeTrackingIp: c.storeTrackingIp ?? DEFAULTS.storeTrackingIp,\n storeRenderedBody: c.storeRenderedBody ?? DEFAULTS.storeRenderedBody,\n circuitBreaker: { ...CIRCUIT_BREAKER_DEFAULTS, ...(c.circuitBreaker ?? {}) },\n }\n}\n","/**\n * Mongo collection helpers + indexes for every mailer-owned collection.\n *\n * The single source of truth for `mailer_*` schemas lives in\n * `plans/02-data-model.md`. The TS interfaces here track that doc.\n *\n * const collections = getCollections(db)\n * await ensureIndexes(db)\n * await collections.events.insertOne({ ... })\n */\n\nimport type { Db, Collection, ObjectId } from 'mongodb'\n\nimport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../../shared/enums.js'\nimport type { FlowStep, SegmentDefinition } from '../../shared/types.js'\n\n// ---------------------------------------------------------------------------\n// Document interfaces (per collection)\n// ---------------------------------------------------------------------------\n\nexport interface SubscriptionDoc {\n _id?: ObjectId\n externalId: string\n status: SubscriptionStatus\n subscribedAt: Date | null\n unsubscribedAt: Date | null\n unsubscribeReason: string | null\n doiTokenHash: string | null\n doiRequestedAt: Date | null\n doiConfirmedAt: Date | null\n doiIp: string | null\n doiUserAgent: string | null\n source: string\n emailAtSubscribe: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface LeadDoc {\n _id?: ObjectId\n email: string\n source: string\n capturedFields: Record<string, unknown>\n status: 'lead' | 'promoted' | 'rejected'\n promotedToExternalId: string | null\n promotedAt: Date | null\n consentedAt: Date | null\n consentIp: string | null\n unsubscribedAt: Date | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface EventDoc {\n _id?: ObjectId\n externalId: string\n name: string\n properties: Record<string, unknown>\n dedupeKey: string\n occurredAt: Date\n createdAt: Date\n}\n\nexport interface FlowTrigger {\n type: 'event' | 'segment_enter' | 'cron'\n eventName?: string\n segmentDefinition?: SegmentDefinition\n cronExpression?: string\n once: boolean\n}\n\nexport interface FlowDraft {\n steps: FlowStep[]\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface FlowDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n trigger: FlowTrigger\n enabled: boolean\n steps: FlowStep[]\n version: number\n draft: FlowDraft | null\n goal: FlowGoal\n audience: string\n expectedVolumePerWeek: number | null\n stats: {\n activeRuns: number\n completedRuns: number\n sendsTotal: number\n sendsLast7Days: number\n }\n lastTriggerScanAt: Date | null\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface FlowVersionDoc {\n _id?: ObjectId\n flowId: ObjectId\n version: number\n steps: FlowStep[]\n trigger: FlowTrigger\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface FlowRunHistoryEntry {\n stepIndex: number\n action:\n | 'entered'\n | 'wait_started'\n | 'wait_completed'\n | 'condition_evaluated'\n | 'branch_taken'\n | 'sent'\n | 'send_skipped'\n | 'send_deferred'\n | 'tagged'\n | 'event_fired'\n | 'webhook_called'\n | 'exited'\n | 'failed'\n at: Date\n details?: Record<string, unknown>\n}\n\nexport interface FlowRunDoc {\n _id?: ObjectId\n externalId: string\n flowId: ObjectId\n flowSlug: string\n flowVersion: number\n emailAtEntry: string\n /**\n * Snapshot of the event that triggered this run. Properties surface in\n * templates as `{{event.*}}` and in `varsAdapter.resolve` via\n * `info.eventProperties` — this is how account/topic-scoped flows know\n * which account or topic the run is about. Null for non-event entries.\n */\n triggerEvent?: { name: string; properties: Record<string, unknown>; occurredAt: Date } | null\n /**\n * Dedupe key of the triggering event. Unique per flow (partial index) so the\n * trigger scan's overlap window can re-read an event without creating a\n * second run. Null for non-event entries (manual/API).\n */\n triggerDedupeKey?: string | null\n enteredAt: Date\n status: FlowRunStatus\n currentStepIndex: number\n currentBranchPath: Array<number | 'true' | 'false'>\n nextActionAt: Date\n attemptsForCurrentStep: number\n history: FlowRunHistoryEntry[]\n exitedAt: Date | null\n exitReason: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateDraft {\n subject: string\n preheader: string\n /** MJML source (when template is authored as MJML). Empty string if Maily-authored. */\n mjml: string\n /** Maily editor JSON (when template is authored via the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n notes: string\n lastModifiedBy: string\n lastModifiedAt: Date\n}\n\nexport interface TemplateDoc {\n _id?: ObjectId\n slug: string\n name: string\n description: string\n kind: TemplateKind\n fromName: string\n fromEmail: string\n replyTo: string | null\n providerOverride: string | null\n subject: string\n preheader: string\n body: {\n /** MJML source (set when published from MJML). */\n mjml: string\n /** Maily editor JSON (set when published from the WYSIWYG editor). null otherwise. */\n editorJson: Record<string, unknown> | null\n html: string\n plainText: string\n compiledAt: Date | null\n }\n variablesSchema: Record<\n string,\n {\n type: 'string' | 'number' | 'boolean' | 'date' | 'url'\n required: boolean\n description?: string\n defaultValue?: unknown\n }\n >\n draft: TemplateDraft | null\n tags: string[]\n trackOpens: boolean\n trackClicks: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n lastSentAt: Date | null\n }\n publishedAt: Date | null\n publishedBy: string | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface TemplateVersionDoc {\n _id?: ObjectId\n templateId: ObjectId\n version: number\n mjml: string\n html: string\n plainText: string\n subject: string\n preheader: string\n publishedAt: Date\n publishedBy: string\n}\n\nexport interface SendDoc {\n _id?: ObjectId\n dedupeKey: string\n externalId: string\n emailAtSend: string\n templateId: ObjectId\n templateSlug: string\n flowRunId: ObjectId | null\n broadcastId: ObjectId | null\n manualSendBy: string | null\n kind: TemplateKind\n provider: string\n providerMessageId: string | null\n fromName: string\n fromEmail: string\n subject: string\n bodyHash: string\n status: SendStatus\n errorMessage: string | null\n bounceType: 'hard' | 'soft' | null\n bounceReason: string | null\n /** Pre-send map: every rewritten link's linkId → original URL. Lookup target on click. */\n links: Array<{ linkId: string; url: string }>\n /** Render-time vars from the flow step or one-off send. Re-applied at dispatch. */\n vars: Record<string, unknown>\n openedAt: Date | null\n openCount: number\n firstClickAt: Date | null\n clickCount: number\n /** History of actual clicks (a linkId may appear multiple times). */\n clickedLinks: Array<{ url: string; linkId: string; clickedAt: Date }>\n unsubscribedAt: Date | null\n complainedAt: Date | null\n queuedAt: Date\n /** Last time the row was mutated; used by the stranded-send sweep. */\n updatedAt: Date\n sentAt: Date | null\n deliveredAt: Date | null\n}\n\nexport interface SuppressionDoc {\n _id?: ObjectId\n email: string | null\n emailHash: string\n scope: SuppressionScope\n reason: SuppressionReason\n source: string\n notes: string | null\n addedAt: Date\n expiresAt: Date | null\n}\n\nexport interface BroadcastDoc {\n _id?: ObjectId\n slug: string\n name: string\n templateSlug: string\n segmentDefinition: SegmentDefinition\n status: BroadcastStatus\n scheduledAt: Date | null\n startedAt: Date | null\n completedAt: Date | null\n confirmationRequired: boolean\n confirmedCount: number | null\n confirmedAt: Date | null\n confirmedBy: string | null\n recipientCount: number | null\n /** When true, dispatch fires each recipient at their local-timezone equivalent of `scheduledAt`. */\n respectRecipientTimezone?: boolean\n stats: {\n sent: number\n delivered: number\n opened: number\n clicked: number\n bounced: number\n complained: number\n unsubscribed: number\n }\n createdAt: Date\n createdBy: string\n updatedAt: Date\n}\n\nexport interface OutboxDoc {\n _id?: ObjectId\n payload: {\n type: 'event' | 'upsert_subscription' | 'unsubscribe'\n data: Record<string, unknown>\n dedupeKey: string\n }\n status: 'pending' | 'processed' | 'failed' | 'duplicate'\n attempts: number\n lastAttemptAt: Date | null\n lastError: string | null\n enqueuedAt: Date\n processedAt: Date | null\n}\n\nexport interface AuditLogDoc {\n _id?: ObjectId\n actor: string\n action: string\n resource: { collection: string; id?: ObjectId | string; slug?: string }\n before: Record<string, unknown> | null\n after: Record<string, unknown> | null\n diffSummary: string | null\n ip: string | null\n userAgent: string | null\n requestId: string | null\n occurredAt: Date\n}\n\nexport interface WebhookEventDoc {\n _id?: ObjectId\n provider: string\n providerEventId: string\n eventType: string\n normalizedType: 'delivered' | 'open' | 'click' | 'bounce' | 'complaint' | 'unsubscribe' | 'spam_report'\n providerMessageId: string\n email: string\n occurredAt: Date\n receivedAt: Date\n processed: boolean\n raw: unknown\n}\n\n/**\n * Health bucket. One doc per (senderDomain, kind) pair plus a single aggregate\n * doc with _id='agg' that rolls up everything.\n *\n * _id: 'agg' // cross-domain, cross-kind roll-up\n * _id: 'd:<senderDomain>|k:<kind>' // per-bucket\n *\n * The aggregate is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n */\nexport interface HealthDoc {\n _id: string\n /** null on the aggregate doc, set on bucket docs. */\n senderDomain: string | null\n /** null on the aggregate doc, set on bucket docs. */\n kind: TemplateKind | null\n windowStartedAt: Date\n windowDurationMs: number\n counters: {\n sent: number\n delivered: number\n bounced: number\n hardBounced: number\n softBounced: number\n complained: number\n failedToSend: number\n }\n rates: {\n bounceRate: number\n hardBounceRate: number\n complaintRate: number\n failureRate: number\n }\n status: HealthStatus\n trippedAt: Date | null\n trippedReason: string | null\n manuallyResumedAt: Date | null\n updatedAt: Date\n}\n\nexport const HEALTH_AGG_ID = 'agg'\n\nexport function healthBucketId(senderDomain: string | null, kind: TemplateKind): string {\n return `d:${senderDomain ?? '_unknown'}|k:${kind}`\n}\n\nexport type PostmasterReputation = 'HIGH' | 'MEDIUM' | 'LOW' | 'BAD' | 'REPUTATION_CATEGORY_UNSPECIFIED'\n\n/**\n * One day's traffic stats for a domain from Google Postmaster Tools.\n * Stored per (domain, date) so we can chart trends.\n */\nexport interface PostmasterSnapshotDoc {\n _id?: ObjectId\n domain: string\n /** Reporting date in YYYY-MM-DD per Postmaster's stat day. */\n date: string\n domainReputation: PostmasterReputation | null\n ipReputations: Array<{ reputation: PostmasterReputation; ipCount: number }> | null\n userReportedSpamRatio: number | null\n spfSuccessRatio: number | null\n dkimSuccessRatio: number | null\n dmarcSuccessRatio: number | null\n outboundEncryptionRatio: number | null\n inboundEncryptionRatio: number | null\n deliveryErrors: Array<{ errorType: string; errorClass: string; errorRatio: number }> | null\n spammyFeedbackLoops: Array<{ id: string; spamRatio: number }> | null\n fetchedAt: Date\n}\n\nexport interface MailTesterFeedback {\n category: string\n severity: 'info' | 'warning' | 'error'\n message: string\n}\n\n/**\n * Cached Mail-Tester deliverability score for a given (template content)\n * fingerprint. Operators don't burn a credit re-running on identical\n * content within cacheHours.\n */\nexport interface MailTesterScoreDoc {\n _id?: ObjectId\n templateSlug: string\n /** Hash of bodyHash + subject + fromEmail — the cache key. */\n contentKey: string\n checkId: string\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n fetchedAt: Date\n expiresAt: Date\n}\n\nexport type DmarcPolicy = 'none' | 'quarantine' | 'reject'\nexport type DmarcAuthResult = 'pass' | 'fail' | 'softfail' | 'neutral' | 'temperror' | 'permerror' | 'none' | 'unknown'\n\n/**\n * One DMARC RUA aggregate report. Receivers (Google, Yahoo, Microsoft, etc.)\n * email one per day per sending domain. We store one DmarcReportDoc per\n * incoming report, plus one DmarcFailureDoc per non-aligned record row.\n */\nexport interface DmarcReportDoc {\n _id?: ObjectId\n reportId: string\n /** Reporting org, e.g. 'google.com', 'enterprise.protection.outlook.com'. */\n orgName: string\n /** Reporter contact email from <report_metadata>. */\n email: string\n /** The domain we publish DMARC for, from <policy_published><domain>. */\n domain: string\n policyP: DmarcPolicy\n /** % of mail subject to the policy (1-100). */\n policyPct: number\n /** Activity window the report covers. */\n rangeStart: Date\n rangeEnd: Date\n /** Sum of <count> across all records. */\n totalMessages: number\n /** Messages that passed DMARC (DKIM aligned OR SPF aligned). */\n passCount: number\n failCount: number\n receivedAt: Date\n}\n\n/**\n * One alignment-failing source × day. Composite key `(sourceIp, domain, day)`\n * lets us roll up \"this IP sent N misaligned messages over the past week.\"\n * Failures from multiple reports for the same key get counted once per\n * report (we de-dupe on reportId × sourceIp).\n */\nexport interface DmarcFailureDoc {\n _id?: ObjectId\n reportId: string\n domain: string\n sourceIp: string\n count: number\n headerFrom: string\n dkimResult: DmarcAuthResult\n spfResult: DmarcAuthResult\n dispositionApplied: 'none' | 'quarantine' | 'reject' | string\n /** YYYY-MM-DD bucket derived from the reporting window's mid-point. */\n day: string\n receivedAt: Date\n}\n\n/**\n * Operator-set DMARC source tag. Created/updated/deleted from the admin UI\n * so operators can mark \"this IP is our SendGrid\", \"this is Hubspot\", etc.\n * Merged with `MailerConfig.dmarc.knownSources` at read time — the config\n * version is read-only baseline, the collection is mutable runtime state.\n */\nexport interface DmarcSourceTagDoc {\n _id?: ObjectId\n ip: string\n label: string\n ignored: boolean\n setBy: string\n setAt: Date\n}\n\nexport type SndsFilterResult = 'GREEN' | 'YELLOW' | 'RED' | 'UNKNOWN'\n\n/**\n * One row from a Microsoft SNDS data export covering a single activity\n * window for one sending IP. Stored unique per (ip, activityStart) so\n * historical windows accumulate without re-writing.\n */\nexport interface SndsSnapshotDoc {\n _id?: ObjectId\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n /** 0-1 fraction. SNDS reports as \"<0.1%\", \"0.1-0.3%\", etc; we store the upper bound. null when unknown. */\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n fetchedAt: Date\n}\n\nexport type DnsblResult = 'clean' | 'listed' | 'error'\nexport type DnsblTargetKind = 'domain' | 'ip'\n\n/**\n * Latest DNSBL check result per (target, list). Replaced in-place on each run\n * so the collection stays small. History (if needed later) lives in audit_log.\n */\nexport interface DnsblCheckDoc {\n _id?: ObjectId\n /** Domain (e.g. `mkt.example.com`) or dotted-quad IP (e.g. `203.0.113.5`). */\n target: string\n targetKind: DnsblTargetKind\n /** DNS suffix queried (e.g. `dbl.spamhaus.org`). */\n list: string\n /** Display label for the UI (e.g. `Spamhaus DBL`). */\n listLabel: string\n result: DnsblResult\n /** A records returned by the lookup, when listed. */\n returnCodes: string[]\n /** When result is 'error', the message; otherwise null. */\n errorMessage: string | null\n runAt: Date\n}\n\nexport interface ContactTagDoc {\n _id?: ObjectId\n externalId: string\n tag: string\n appliedBy: 'flow' | 'admin' | 'script' | 'import'\n appliedAt: Date\n}\n\n// ---------------------------------------------------------------------------\n// Collection factory\n// ---------------------------------------------------------------------------\n\nexport interface Collections {\n subscriptions: Collection<SubscriptionDoc>\n leads: Collection<LeadDoc>\n events: Collection<EventDoc>\n flows: Collection<FlowDoc>\n flowVersions: Collection<FlowVersionDoc>\n flowRuns: Collection<FlowRunDoc>\n templates: Collection<TemplateDoc>\n templateVersions: Collection<TemplateVersionDoc>\n sends: Collection<SendDoc>\n suppressions: Collection<SuppressionDoc>\n broadcasts: Collection<BroadcastDoc>\n outbox: Collection<OutboxDoc>\n auditLog: Collection<AuditLogDoc>\n webhookEvents: Collection<WebhookEventDoc>\n health: Collection<HealthDoc>\n contactTags: Collection<ContactTagDoc>\n dnsblChecks: Collection<DnsblCheckDoc>\n postmasterSnapshots: Collection<PostmasterSnapshotDoc>\n sndsSnapshots: Collection<SndsSnapshotDoc>\n dmarcReports: Collection<DmarcReportDoc>\n dmarcFailures: Collection<DmarcFailureDoc>\n dmarcSourceTags: Collection<DmarcSourceTagDoc>\n mailTesterScores: Collection<MailTesterScoreDoc>\n}\n\nexport function getCollections(db: Db, prefix = 'mailer_'): Collections {\n return {\n subscriptions: db.collection<SubscriptionDoc>(`${prefix}subscriptions`),\n leads: db.collection<LeadDoc>(`${prefix}leads`),\n events: db.collection<EventDoc>(`${prefix}events`),\n flows: db.collection<FlowDoc>(`${prefix}flows`),\n flowVersions: db.collection<FlowVersionDoc>(`${prefix}flow_versions`),\n flowRuns: db.collection<FlowRunDoc>(`${prefix}flow_runs`),\n templates: db.collection<TemplateDoc>(`${prefix}templates`),\n templateVersions: db.collection<TemplateVersionDoc>(`${prefix}template_versions`),\n sends: db.collection<SendDoc>(`${prefix}sends`),\n suppressions: db.collection<SuppressionDoc>(`${prefix}suppressions`),\n broadcasts: db.collection<BroadcastDoc>(`${prefix}broadcasts`),\n outbox: db.collection<OutboxDoc>(`${prefix}outbox`),\n auditLog: db.collection<AuditLogDoc>(`${prefix}audit_log`),\n webhookEvents: db.collection<WebhookEventDoc>(`${prefix}webhook_events`),\n health: db.collection<HealthDoc>(`${prefix}health`),\n contactTags: db.collection<ContactTagDoc>(`${prefix}contact_tags`),\n dnsblChecks: db.collection<DnsblCheckDoc>(`${prefix}dnsbl_checks`),\n postmasterSnapshots: db.collection<PostmasterSnapshotDoc>(`${prefix}postmaster_snapshots`),\n sndsSnapshots: db.collection<SndsSnapshotDoc>(`${prefix}snds_snapshots`),\n dmarcReports: db.collection<DmarcReportDoc>(`${prefix}dmarc_reports`),\n dmarcFailures: db.collection<DmarcFailureDoc>(`${prefix}dmarc_failures`),\n dmarcSourceTags: db.collection<DmarcSourceTagDoc>(`${prefix}dmarc_source_tags`),\n mailTesterScores: db.collection<MailTesterScoreDoc>(`${prefix}mail_tester_scores`),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Index ensurer\n// ---------------------------------------------------------------------------\n\nexport async function ensureIndexes(db: Db, prefix = 'mailer_'): Promise<void> {\n const c = getCollections(db, prefix)\n\n await Promise.all([\n c.subscriptions.createIndexes([\n { key: { externalId: 1 }, unique: true },\n { key: { status: 1, unsubscribedAt: -1 } },\n ]),\n c.leads.createIndexes([\n { key: { email: 1 }, unique: true },\n { key: { status: 1, createdAt: -1 } },\n ]),\n c.events.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, occurredAt: -1 } },\n { key: { name: 1, occurredAt: -1 } },\n { key: { name: 1, createdAt: 1 } },\n { key: { externalId: 1, name: 1 } },\n ]),\n c.flows.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { enabled: 1, 'trigger.type': 1, 'trigger.eventName': 1 } },\n ]),\n c.flowVersions.createIndexes([{ key: { flowId: 1, version: 1 }, unique: true }]),\n c.flowRuns.createIndexes([\n { key: { status: 1, nextActionAt: 1 } },\n { key: { externalId: 1, flowId: 1 } },\n { key: { flowId: 1, status: 1 } },\n {\n key: { flowId: 1, triggerDedupeKey: 1 },\n unique: true,\n partialFilterExpression: { triggerDedupeKey: { $type: 'string' } },\n },\n ]),\n c.templates.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { tags: 1 } },\n { key: { kind: 1 } },\n ]),\n c.templateVersions.createIndexes([{ key: { templateId: 1, version: 1 }, unique: true }]),\n c.sends.createIndexes([\n { key: { dedupeKey: 1 }, unique: true },\n { key: { externalId: 1, sentAt: -1 } },\n { key: { templateId: 1, sentAt: -1 } },\n { key: { flowRunId: 1 }, sparse: true },\n { key: { broadcastId: 1 }, sparse: true },\n { key: { providerMessageId: 1 }, sparse: true },\n { key: { status: 1, queuedAt: 1 } },\n { key: { status: 1, updatedAt: 1 } },\n ]),\n c.suppressions.createIndexes([\n { key: { email: 1, scope: 1 }, unique: true, partialFilterExpression: { email: { $type: 'string' } } },\n { key: { emailHash: 1 } },\n { key: { addedAt: -1 } },\n ]),\n c.broadcasts.createIndexes([\n { key: { slug: 1 }, unique: true },\n { key: { status: 1, scheduledAt: 1 } },\n ]),\n c.outbox.createIndexes([\n { key: { status: 1, enqueuedAt: 1 } },\n { key: { 'payload.dedupeKey': 1 }, unique: true },\n ]),\n c.auditLog.createIndexes([\n { key: { occurredAt: -1 } },\n { key: { 'resource.collection': 1, 'resource.id': 1, occurredAt: -1 } },\n { key: { actor: 1, occurredAt: -1 } },\n ]),\n c.webhookEvents.createIndexes([\n { key: { provider: 1, providerEventId: 1 }, unique: true },\n { key: { providerMessageId: 1 } },\n { key: { processed: 1, receivedAt: 1 } },\n ]),\n c.contactTags.createIndexes([\n { key: { externalId: 1, tag: 1 }, unique: true },\n { key: { tag: 1 } },\n ]),\n c.health.createIndexes([\n { key: { senderDomain: 1, kind: 1 } },\n { key: { status: 1 } },\n // setup-status reads the most-recently-touched health doc as a heartbeat.\n { key: { updatedAt: -1 } },\n ]),\n c.dnsblChecks.createIndexes([\n { key: { target: 1, list: 1 }, unique: true },\n // Supports the admin /dnsbl GET sort: result asc, then target asc, list asc.\n { key: { result: 1, target: 1, list: 1 } },\n // TTL — stale rows for targets the operator removed disappear after\n // 60 days without manual cleanup. The puller refreshes runAt on\n // every active target so existing targets stay indefinitely.\n { key: { runAt: 1 }, expireAfterSeconds: 60 * 24 * 60 * 60 },\n ]),\n c.postmasterSnapshots.createIndexes([\n { key: { domain: 1, date: 1 }, unique: true },\n { key: { domain: 1, fetchedAt: -1 } },\n { key: { domainReputation: 1 } },\n ]),\n c.sndsSnapshots.createIndexes([\n { key: { ip: 1, activityStart: 1 }, unique: true },\n { key: { ip: 1, fetchedAt: -1 } },\n { key: { filterResult: 1 } },\n ]),\n c.dmarcReports.createIndexes([\n { key: { reportId: 1, orgName: 1 }, unique: true },\n { key: { domain: 1, rangeEnd: -1 } },\n // Cross-domain \"most recent reports\" queries scan a lot without this.\n { key: { rangeEnd: -1 } },\n { key: { receivedAt: -1 } },\n ]),\n c.dmarcFailures.createIndexes([\n { key: { reportId: 1, sourceIp: 1 }, unique: true },\n { key: { domain: 1, day: -1 } },\n { key: { sourceIp: 1, day: -1 } },\n { key: { receivedAt: 1 } }, // for retention pruning\n ]),\n c.dmarcSourceTags.createIndexes([\n { key: { ip: 1 }, unique: true },\n ]),\n c.mailTesterScores.createIndexes([\n { key: { contentKey: 1 }, unique: true },\n { key: { templateSlug: 1, fetchedAt: -1 } },\n // TTL — Mongo auto-deletes expired scores so we never serve stale data.\n { key: { expiresAt: 1 }, expireAfterSeconds: 0 },\n ]),\n ])\n\n // One-shot migrations — run after indexes are in place so any DELETE\n // plan can use them. Idempotent at MongoDB level (returns 0 when\n // nothing is there).\n await c.health.deleteOne({ _id: 'singleton' as any }).catch(() => {})\n}\n","/**\n * Event registry + dedupe-key policy. INVARIANT 1: every `mailer_events` row\n * has a unique dedupeKey. Callers either pass one or `mailer.registerEvent`\n * declares a policy and we derive it.\n */\n\nimport crypto from 'node:crypto'\n\nexport type DedupePolicy = 'once-per-contact' | 'once-per-day' | 'every-time'\n\nexport interface EventRegistration {\n name: string\n dedupePolicy: DedupePolicy\n}\n\nexport class EventRegistry {\n private readonly policies = new Map<string, DedupePolicy>()\n\n register(reg: EventRegistration): void {\n this.policies.set(reg.name, reg.dedupePolicy)\n }\n\n has(name: string): boolean {\n return this.policies.has(name)\n }\n\n policy(name: string): DedupePolicy | undefined {\n return this.policies.get(name)\n }\n\n list(): EventRegistration[] {\n return Array.from(this.policies, ([name, dedupePolicy]) => ({ name, dedupePolicy }))\n }\n\n /**\n * Derive a dedupeKey for an event call. Returns null when no policy is\n * registered AND no key was passed — caller should throw.\n */\n deriveKey(\n name: string,\n externalId: string,\n passedKey: string | undefined,\n now: Date,\n ): string | null {\n if (passedKey) return passedKey\n const policy = this.policies.get(name)\n if (!policy) return null\n\n switch (policy) {\n case 'once-per-contact':\n return `${externalId}:${name}`\n case 'once-per-day':\n return `${externalId}:${name}:${isoDay(now)}`\n case 'every-time':\n return `${externalId}:${name}:${randomId()}`\n }\n }\n}\n\nfunction isoDay(d: Date): string {\n return d.toISOString().slice(0, 10)\n}\n\nfunction randomId(): string {\n return crypto.randomBytes(8).toString('hex')\n}\n","/**\n * HMAC-signed tokens for unsubscribe + preference-center URLs.\n *\n * Format: base64url(payload) '.' base64url(hmac)\n * payload = JSON.stringify({ e: email, s: scope, x: expiresAtMs })\n * hmac = HMAC-SHA256(secret, payload)\n *\n * Tokens expire because long-lived signed URLs are a liability.\n */\n\nimport crypto from 'node:crypto'\nimport type { SuppressionScope } from '../shared/enums.js'\n\nexport interface UnsubscribeTokenPayload {\n email: string\n scope: SuppressionScope\n expiresAt: Date\n}\n\nexport function signUnsubscribeToken(\n payload: UnsubscribeTokenPayload,\n secret: string,\n): string {\n const body = JSON.stringify({\n e: payload.email.toLowerCase(),\n s: payload.scope,\n x: payload.expiresAt.getTime(),\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyUnsubscribeToken(\n token: string,\n secret: string,\n now: Date = new Date(),\n): UnsubscribeTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { e?: string; s?: string; x?: number }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.e || !body.s || typeof body.x !== 'number') return null\n if (body.x < now.getTime()) return null\n if (body.s !== 'all' && body.s !== 'marketing' && body.s !== 'transactional') return null\n\n return {\n email: body.e,\n scope: body.s,\n expiresAt: new Date(body.x),\n }\n}\n\nfunction b64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction b64urlDecode(s: string): Buffer {\n const padded = s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4)\n return Buffer.from(padded, 'base64')\n}\n\n/**\n * sha256 hex digest, used for storing email hashes (GDPR forget) and dedup helpers.\n */\nexport function sha256Hex(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex')\n}\n\n// ---------------------------------------------------------------------------\n// Double opt-in tokens\n// ---------------------------------------------------------------------------\n\nexport interface DoiTokenPayload {\n externalId: string\n expiresAt: Date\n}\n\n/**\n * Sign a DOI confirmation token. Same shape as the unsubscribe token, but\n * scoped to \"this externalId confirmed their subscription.\"\n */\nexport function signDoiToken(payload: DoiTokenPayload, secret: string): string {\n const body = JSON.stringify({\n i: payload.externalId,\n x: payload.expiresAt.getTime(),\n k: 'doi',\n })\n const bodyB64 = b64url(Buffer.from(body, 'utf8'))\n const hmac = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n return `${bodyB64}.${b64url(hmac)}`\n}\n\nexport function verifyDoiToken(token: string, secret: string, now: Date = new Date()): DoiTokenPayload | null {\n const parts = token.split('.')\n if (parts.length !== 2) return null\n const [bodyB64, sigB64] = parts as [string, string]\n\n const expected = crypto.createHmac('sha256', secret).update(bodyB64).digest()\n let actual: Buffer\n try {\n actual = b64urlDecode(sigB64)\n } catch {\n return null\n }\n if (expected.length !== actual.length) return null\n if (!crypto.timingSafeEqual(expected, actual)) return null\n\n let body: { i?: string; x?: number; k?: string }\n try {\n body = JSON.parse(b64urlDecode(bodyB64).toString('utf8'))\n } catch {\n return null\n }\n if (!body.i || typeof body.x !== 'number' || body.k !== 'doi') return null\n if (body.x < now.getTime()) return null\n\n return { externalId: body.i, expiresAt: new Date(body.x) }\n}\n","/**\n * BullMQ driver. Four named queues backed by Redis. Job-level `attempts`,\n * `backoff`, `delay`, and `jobId` pass through to BullMQ's native semantics.\n * Send rate limit is enforced via BullMQ's `limiter` option (Redis Lua script).\n */\n\nimport type { Queue, Worker } from 'bullmq'\nimport IORedis, { type RedisOptions as IORedisOptions } from 'ioredis'\n\nimport type { RedisOptions } from '../config.js'\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface BullQueues {\n tick: Queue\n advance: Queue\n send: Queue\n webhook: Queue\n}\n\ninterface BullModule {\n Queue: typeof Queue\n Worker: typeof Worker\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\nexport class BullDriver implements QueueDriver {\n readonly queues: Queues\n private redis: IORedis\n private bullQueues: BullQueues\n private workers: { tick: Worker; advance: Worker; send: Worker; webhook: Worker } | null = null\n private bull: BullModule\n\n static async create(redisConfig: RedisOptions | IORedis, prefix?: string): Promise<BullDriver> {\n let bull: BullModule\n try {\n bull = (await import('bullmq')) as unknown as BullModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'bull' requires the 'bullmq' peer dependency. Run `npm install bullmq ioredis`.\",\n )\n }\n if (prefix?.includes(':')) {\n throw new Error(\n `mailery: queue prefix \"${prefix}\" must not contain ':' — BullMQ uses it as the Redis key separator.`,\n )\n }\n const redis = isRedisLike(redisConfig) ? (redisConfig as IORedis) : connect(redisConfig as RedisOptions)\n return new BullDriver(bull, redis, prefix)\n }\n\n private prefix?: string\n\n private constructor(bull: BullModule, redis: IORedis, prefix?: string) {\n this.bull = bull\n this.redis = redis\n this.prefix = prefix\n // Bounded retention: completed/failed jobs must not accumulate in Redis\n // forever. Completed jobs also need to leave promptly so jobId-based\n // idempotent re-adds aren't dropped against a stale completed job.\n const opts = {\n connection: redis,\n prefix,\n defaultJobOptions: {\n removeOnComplete: { age: 24 * 3600, count: 1000 },\n removeOnFail: { age: 7 * 24 * 3600 },\n },\n }\n this.bullQueues = {\n tick: new bull.Queue(QUEUE_NAMES.tick, opts),\n advance: new bull.Queue(QUEUE_NAMES.advance, opts),\n send: new bull.Queue(QUEUE_NAMES.send, opts),\n webhook: new bull.Queue(QUEUE_NAMES.webhook, opts),\n }\n this.queues = {\n tick: adaptBullQueue(this.bullQueues.tick),\n advance: adaptBullQueue(this.bullQueues.advance),\n send: adaptBullQueue(this.bullQueues.send),\n webhook: adaptBullQueue(this.bullQueues.webhook),\n }\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n await (this.bullQueues.tick as any).upsertJobScheduler(\n 'mailer-tick-repeat',\n { every: intervalSeconds * 1000 },\n {\n name: 'tick',\n data: {},\n opts: { removeOnComplete: { count: 20 }, removeOnFail: { count: 50 } },\n },\n )\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n if (this.workers) return\n // Workers must share the queues' prefix or they'd poll different keys.\n const base = { connection: this.redis, prefix: this.prefix }\n const { Worker } = this.bull\n\n const tick = new Worker(\n QUEUE_NAMES.tick,\n async (job: any) => opts.handlers.tick(job.data),\n { ...base, concurrency: 1 },\n )\n const advance = new Worker(\n QUEUE_NAMES.advance,\n async (job: any) => opts.handlers.advance(job.data),\n { ...base, concurrency: 10 },\n )\n const send = new Worker(\n QUEUE_NAMES.send,\n async (job: any) => opts.handlers.send(job.data),\n {\n ...base,\n concurrency: opts.concurrency.send,\n limiter: opts.sendRateLimit\n ? { max: opts.sendRateLimit.max, duration: opts.sendRateLimit.durationMs }\n : undefined,\n },\n )\n const webhook = new Worker(\n QUEUE_NAMES.webhook,\n async (job: any) => opts.handlers.webhook(job.data),\n { ...base, concurrency: 4 },\n )\n\n this.workers = { tick, advance, send, webhook }\n }\n\n async stopWorkers(): Promise<void> {\n if (!this.workers) return\n await Promise.all([\n this.workers.tick.close(),\n this.workers.advance.close(),\n this.workers.send.close(),\n this.workers.webhook.close(),\n ])\n this.workers = null\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n await Promise.all([\n this.bullQueues.tick.close(),\n this.bullQueues.advance.close(),\n this.bullQueues.send.close(),\n this.bullQueues.webhook.close(),\n ])\n }\n}\n\nfunction adaptBullQueue(q: Queue): QueueAPI {\n return {\n add: (name, data, opts) => q.add(name, data as any, opts as any),\n getWaitingCount: () => q.getWaitingCount(),\n getInFlightCount: async () => {\n const [active, waiting] = await Promise.all([q.getActiveCount(), q.getWaitingCount()])\n return active + waiting\n },\n getDelayedCount: () => q.getDelayedCount(),\n close: () => q.close(),\n }\n}\n\nfunction isRedisLike(x: unknown): boolean {\n return !!x && typeof x === 'object' && typeof (x as any).get === 'function' && typeof (x as any).set === 'function'\n}\n\nfunction connect(opts: RedisOptions): IORedis {\n const config: IORedisOptions = {\n maxRetriesPerRequest: null, // BullMQ requirement\n enableReadyCheck: false,\n }\n if (opts.url) return new IORedis(opts.url, config)\n return new IORedis({\n ...config,\n host: opts.host ?? '127.0.0.1',\n port: opts.port ?? 6379,\n password: opts.password,\n db: opts.db,\n username: opts.username,\n tls: opts.tls ? {} : undefined,\n })\n}\n\n// Re-exports needed by the broader queue surface\nexport type { AddOptions }\n","/**\n * Agenda driver. Backed by the same MongoDB instance the rest of mailery uses,\n * so no Redis is required. Uses `agenda` + `@agendajs/mongo-backend`.\n *\n * Single-process only: send rate limit is enforced via an in-memory Bottleneck\n * wrapped around the send handler. Multi-process Agenda deployments would\n * fan-out beyond the rate cap — out of scope.\n *\n * Retry/backoff: applied per-definition via Agenda's built-in\n * `backoffStrategies.exponential`. Per-call `attempts` from add() is ignored;\n * the driver uses the shared config-level `sendRetryAttempts`.\n *\n * Idempotency: per-call `jobId` is stored as `data.__jobId`. Before scheduling\n * we look for a pending (not-yet-run, not-finished) job with the same key.\n */\n\nimport type { Db } from 'mongodb'\nimport type { Agenda, Job } from 'agenda'\nimport type Bottleneck from 'bottleneck'\n\nimport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\ninterface AgendaModule {\n Agenda: typeof Agenda\n backoffStrategies: { exponential: (opts: { delay: number; maxRetries: number; factor?: number }) => any }\n}\n\ninterface MongoBackendModule {\n MongoBackend: new (cfg: { mongo: Db; collection?: string; ensureIndex?: boolean }) => any\n}\n\ninterface BottleneckCtor {\n new (opts: { minTime?: number; maxConcurrent?: number }): Bottleneck\n}\n\nconst QUEUE_NAMES = {\n tick: 'mailer-tick',\n advance: 'mailer-advance',\n send: 'mailer-send',\n webhook: 'mailer-webhook',\n} as const\n\nexport interface AgendaDriverOptions {\n db: Db\n processEverySeconds?: number\n lockLifetimeSeconds?: number\n collectionName?: string\n}\n\nexport class AgendaDriver implements QueueDriver {\n readonly queues: Queues\n private agenda: Agenda\n private agendaMod: AgendaModule\n private sendLimiter: Bottleneck | null = null\n private started = false\n\n static async create(opts: AgendaDriverOptions): Promise<AgendaDriver> {\n let agendaMod: AgendaModule\n let backendMod: MongoBackendModule\n try {\n agendaMod = (await import('agenda')) as unknown as AgendaModule\n backendMod = (await import('@agendajs/mongo-backend')) as unknown as MongoBackendModule\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' requires the 'agenda' and '@agendajs/mongo-backend' peer dependencies. Run `npm install agenda @agendajs/mongo-backend bottleneck`.\",\n )\n }\n\n const collectionName = opts.collectionName ?? '_mailerJobs'\n const backend = new backendMod.MongoBackend({\n mongo: opts.db,\n collection: collectionName,\n })\n\n const agenda = new agendaMod.Agenda({\n backend,\n processEvery: `${opts.processEverySeconds ?? 5} seconds`,\n defaultLockLifetime: (opts.lockLifetimeSeconds ?? 10 * 60) * 1000,\n maxConcurrency: 50,\n defaultConcurrency: 5,\n } as any)\n\n return new AgendaDriver(agenda, agendaMod, opts.db, collectionName)\n }\n\n private db: Db\n private collName: string\n\n private constructor(agenda: Agenda, agendaMod: AgendaModule, db: Db, collectionName: string) {\n this.agenda = agenda\n this.agendaMod = agendaMod\n this.db = db\n this.collName = collectionName\n this.queues = {\n tick: this.makeQueueAPI(QUEUE_NAMES.tick),\n advance: this.makeQueueAPI(QUEUE_NAMES.advance),\n send: this.makeQueueAPI(QUEUE_NAMES.send),\n webhook: this.makeQueueAPI(QUEUE_NAMES.webhook),\n }\n }\n\n private makeQueueAPI(name: string): QueueAPI {\n return {\n add: async (_jobName: string, data: unknown, opts?: AddOptions) => {\n const payload: Record<string, unknown> = { ...(data as object) }\n if (opts?.jobId) {\n payload.__jobId = opts.jobId\n if (await this.findPending(name, opts.jobId)) return\n }\n const job = this.agenda.create(name, payload as any)\n if (opts?.delay) job.schedule(new Date(Date.now() + opts.delay))\n await job.save()\n },\n getWaitingCount: async () => {\n return this.jobsCollection().countDocuments({\n name,\n $or: [{ lockedAt: null }, { lockedAt: { $exists: false } }],\n nextRunAt: { $lte: new Date() },\n })\n },\n close: async () => {},\n }\n }\n\n /** Direct access to the Mongo collection Agenda persists jobs into. */\n private jobsCollection() {\n return this.db.collection(this.collName)\n }\n\n private async findPending(name: string, jobId: string): Promise<unknown> {\n return this.jobsCollection().findOne({\n name,\n 'data.__jobId': jobId,\n $or: [{ lastFinishedAt: null }, { lastFinishedAt: { $exists: false } }],\n })\n }\n\n async scheduleRepeatingTick(intervalSeconds: number): Promise<void> {\n // Persist the repeating job only — do NOT start Agenda here. Starting with\n // a placeholder tick handler would let a process that never calls\n // startWorkers (API-only process in a web/worker split) lock and complete\n // tick jobs as no-ops, silently swallowing real ticks. Agenda starts in\n // startWorkers, after the real handlers are defined.\n await this.agenda.every(`${intervalSeconds} seconds`, QUEUE_NAMES.tick)\n }\n\n async startWorkers(opts: WorkerStartOptions): Promise<void> {\n const exp = this.agendaMod.backoffStrategies.exponential\n\n if (opts.sendRateLimit) {\n try {\n const Bottleneck = (await import('bottleneck')).default as unknown as BottleneckCtor\n this.sendLimiter = new Bottleneck({\n minTime: Math.ceil(opts.sendRateLimit.durationMs / opts.sendRateLimit.max),\n maxConcurrent: opts.concurrency.send,\n })\n } catch {\n throw new Error(\n \"mailery: queue driver 'agenda' with sendRateLimit requires the 'bottleneck' peer dependency. Run `npm install bottleneck`.\",\n )\n }\n }\n\n const retryBackoff = exp({ delay: 60_000, maxRetries: Math.max(0, opts.retryAttempts - 1), factor: 2 })\n\n this.agenda.define(QUEUE_NAMES.tick, async (job: Job) => {\n await opts.handlers.tick(job.attrs.data)\n }, { concurrency: 1 })\n\n this.agenda.define(QUEUE_NAMES.advance, async (job: Job) => {\n await opts.handlers.advance(job.attrs.data as any)\n }, { concurrency: 10, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.send, async (job: Job) => {\n const data = job.attrs.data as any\n if (this.sendLimiter) {\n await this.sendLimiter.schedule(() => opts.handlers.send(data))\n } else {\n await opts.handlers.send(data)\n }\n }, { concurrency: opts.concurrency.send, backoff: retryBackoff })\n\n this.agenda.define(QUEUE_NAMES.webhook, async (job: Job) => {\n await opts.handlers.webhook(job.attrs.data as any)\n }, { concurrency: 4, backoff: retryBackoff })\n\n if (!this.started) {\n await this.agenda.start()\n this.started = true\n }\n }\n\n async stopWorkers(): Promise<void> {\n if (!this.started) return\n await this.agenda.stop()\n this.started = false\n if (this.sendLimiter) {\n await this.sendLimiter.stop({ dropWaitingJobs: true }).catch(() => {})\n this.sendLimiter = null\n }\n }\n\n async close(): Promise<void> {\n await this.stopWorkers()\n }\n}\n","/**\n * No-op queue driver. Used by tests and by hosts that drive the runner\n * synchronously (no background workers, no Redis, no Agenda). `add()` is a\n * no-op; the caller is expected to invoke runner functions directly.\n */\n\nimport type {\n QueueAPI,\n QueueDriver,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nfunction noopQueueAPI(): QueueAPI {\n return {\n add: async () => undefined,\n getWaitingCount: async () => 0,\n close: async () => undefined,\n }\n}\n\nexport class NoopDriver implements QueueDriver {\n readonly queues: Queues = {\n tick: noopQueueAPI(),\n advance: noopQueueAPI(),\n send: noopQueueAPI(),\n webhook: noopQueueAPI(),\n }\n\n async scheduleRepeatingTick(_intervalSeconds: number): Promise<void> {\n /* noop */\n }\n\n async startWorkers(_opts: WorkerStartOptions): Promise<void> {\n /* noop */\n }\n\n async stopWorkers(): Promise<void> {\n /* noop */\n }\n\n async close(): Promise<void> {\n /* noop */\n }\n}\n","/**\n * Queue subsystem entry point. Exports the driver interface, the three\n * built-in drivers (Bull, Agenda, Noop), and a factory that resolves a\n * `QueueDriverConfig` to a concrete driver.\n */\n\nimport type { Db } from 'mongodb'\n\nimport { BullDriver } from './bull.js'\nimport { AgendaDriver } from './agenda.js'\nimport { NoopDriver } from './noop.js'\nimport type { QueueDriver, QueueDriverConfig } from './types.js'\n\nexport { BullDriver } from './bull.js'\nexport { AgendaDriver } from './agenda.js'\nexport { NoopDriver } from './noop.js'\nexport type {\n AddOptions,\n QueueAPI,\n QueueDriver,\n QueueDriverConfig,\n QueueHandlers,\n Queues,\n WorkerStartOptions,\n} from './types.js'\n\nexport async function createQueueDriver(\n config: QueueDriverConfig,\n fallbackDb: Db,\n): Promise<QueueDriver> {\n switch (config.driver) {\n case 'bull':\n return BullDriver.create(config.redis, config.prefix)\n case 'agenda':\n return AgendaDriver.create({\n db: config.db ?? fallbackDb,\n processEverySeconds: config.processEverySeconds,\n lockLifetimeSeconds: config.lockLifetimeSeconds,\n collectionName: config.collectionName,\n })\n case 'noop':\n return new NoopDriver()\n default: {\n const _exhaustive: never = config\n void _exhaustive\n throw new Error(`mailery: unknown queue driver`)\n }\n }\n}\n","/**\n * Event-trigger scan. Finds new event firings since each flow's\n * lastTriggerScanAt watermark, creates flow_runs for matching contacts,\n * enqueues immediate-advance jobs.\n */\n\nimport type { RunnerContext } from './index.js'\nimport type { FlowDoc, EventDoc } from '../models/index.js'\n\nconst BATCH_SIZE = 1000\n\n/**\n * Re-scan window. The watermark advances on `createdAt` (insert time), but a\n * concurrent `fire()` can commit a row with a createdAt slightly before the\n * scan's read. Re-reading this much history every pass closes that race; the\n * unique (flowId, triggerDedupeKey) index makes re-reads harmless.\n */\nconst SCAN_OVERLAP_MS = 30_000\n\nexport async function processNewlyFiredEventTriggers(ctx: RunnerContext): Promise<void> {\n const flows = await ctx.collections.flows.find({ enabled: true, 'trigger.type': 'event' }).toArray()\n for (const flow of flows) {\n await processFlowTriggers(flow, ctx)\n }\n}\n\nasync function processFlowTriggers(flow: FlowDoc, ctx: RunnerContext): Promise<void> {\n const eventName = flow.trigger.eventName\n if (!eventName) return\n // Watermark on createdAt, not occurredAt: occurredAt can lag insert time\n // (outbox-drained events carry the host-transaction timestamp), so an\n // occurredAt watermark permanently skips any event that lands \"in the past.\"\n // createdAt only ever moves forward with inserts.\n const since = flow.lastTriggerScanAt ?? flow.createdAt\n const scanFrom = new Date(since.getTime() - SCAN_OVERLAP_MS)\n\n const events = await ctx.collections.events\n .find({ name: eventName, createdAt: { $gt: scanFrom } })\n .sort({ createdAt: 1 })\n .limit(BATCH_SIZE)\n .toArray()\n\n if (events.length === 0) return\n\n for (const event of events) {\n await tryEnterFlow(flow, event, ctx)\n }\n\n const newestCreatedAt = events[events.length - 1]!.createdAt\n if (newestCreatedAt.getTime() > since.getTime()) {\n await ctx.collections.flows.updateOne(\n { _id: flow._id },\n { $set: { lastTriggerScanAt: newestCreatedAt, updatedAt: new Date() } },\n )\n }\n}\n\nasync function tryEnterFlow(flow: FlowDoc, event: EventDoc, ctx: RunnerContext): Promise<void> {\n if (flow.trigger.once) {\n const existing = await ctx.collections.flowRuns.findOne(\n { externalId: event.externalId, flowId: flow._id },\n { projection: { _id: 1 } },\n )\n if (existing) return\n }\n\n // Flow entry requires an active subscription — flows are marketing-scope.\n // Transactional mail for not-subscribed contacts goes through sendOneOff.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: event.externalId })\n if (!sub || sub.status !== 'subscribed') return\n\n let result\n try {\n result = await ctx.collections.flowRuns.insertOne({\n externalId: event.externalId,\n flowId: flow._id!,\n flowSlug: flow.slug,\n flowVersion: flow.version,\n emailAtEntry: sub.emailAtSubscribe,\n triggerEvent: { name: event.name, properties: event.properties ?? {}, occurredAt: event.occurredAt },\n triggerDedupeKey: event.dedupeKey,\n enteredAt: new Date(),\n status: 'active',\n currentStepIndex: 0,\n currentBranchPath: [],\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n history: [{ stepIndex: -1, action: 'entered', at: new Date(), details: { eventDedupeKey: event.dedupeKey } }],\n exitedAt: null,\n exitReason: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n } catch (err: any) {\n // Event already entered this flow (overlap-window re-read) — no-op.\n if (err?.code !== 11000) throw err\n return\n }\n\n await ctx.queues.advance.add('advance', { flowRunId: String(result.insertedId) })\n}\n","/**\n * Sender-domain validator.\n *\n * Hosts may declare a `senderDomains` registry mapping a domain to which kind\n * of email is allowed to send from it. Used to isolate marketing reputation\n * from transactional reputation:\n *\n * senderDomains: {\n * 'news.example.com': { kind: 'marketing' },\n * 'mail.example.com': { kind: 'transactional' },\n * 'tools.example.com': { kind: 'both' }, // OK for either kind\n * }\n *\n * The check runs at template publish time. If a template's `fromEmail` domain\n * isn't declared, or is declared for the wrong kind, publish fails with a\n * descriptive 400. Hosts who don't set `senderDomains` get no enforcement —\n * back-compat default.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\n\nexport interface SenderDomainConfig {\n /** Which template `kind` may use this domain as a From address. */\n kind: 'marketing' | 'transactional' | 'both'\n}\n\nexport type SenderDomainRegistry = Record<string, SenderDomainConfig>\n\nexport type SenderDomainValidation =\n | { ok: true }\n | { ok: false; code: 'invalid_email' | 'unregistered_domain' | 'wrong_kind'; reason: string }\n\nexport function validateSenderDomain(\n fromEmail: string,\n templateKind: TemplateKind,\n registry: SenderDomainRegistry | undefined,\n): SenderDomainValidation {\n if (!registry || Object.keys(registry).length === 0) return { ok: true }\n\n const domain = extractDomain(fromEmail)\n if (!domain) {\n return {\n ok: false,\n code: 'invalid_email',\n reason: `invalid fromEmail \"${fromEmail}\" — expected \"name@domain\"`,\n }\n }\n\n const entry = registry[domain]\n if (!entry) {\n const known = Object.keys(registry).join(', ')\n return {\n ok: false,\n code: 'unregistered_domain',\n reason: `sender domain \"${domain}\" is not declared in senderDomains (allowed: ${known})`,\n }\n }\n\n if (entry.kind === 'both') return { ok: true }\n if (entry.kind !== templateKind) {\n return {\n ok: false,\n code: 'wrong_kind',\n reason: `sender domain \"${domain}\" is configured for ${entry.kind} email, but this template's kind is ${templateKind}`,\n }\n }\n\n return { ok: true }\n}\n\nexport function extractDomain(email: string): string | null {\n if (typeof email !== 'string') return null\n const at = email.lastIndexOf('@')\n if (at <= 0 || at === email.length - 1) return null\n return email.slice(at + 1).toLowerCase().trim()\n}\n","/**\n * Circuit breaker. Tracks rolling counters in mailer_health per\n * (senderDomain, kind) bucket plus a single aggregate roll-up. Computes rates\n * on each tick and trips individual buckets when thresholds are exceeded.\n *\n * status: 'healthy' — normal\n * 'degraded' — non-blocking warnings (e.g. high failed-to-send rate)\n * 'tripped' — marketing sends held; transactional bypasses (INVARIANT 6)\n *\n * The aggregate doc is informational only — it never trips. Trips live on\n * buckets so one subdomain tanking doesn't hold mail for the others.\n *\n * Recovery is manual (admin UI: POST /api/health/resume[?domain&kind]).\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { HealthDoc } from '../models/index.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\ntype CounterKey =\n | 'sent'\n | 'delivered'\n | 'bounced'\n | 'hardBounced'\n | 'softBounced'\n | 'complained'\n | 'failedToSend'\n\nexport interface HealthDims {\n /** Caller passes the raw `fromEmail`; we extract the domain here. */\n fromEmail: string | null\n kind: TemplateKind\n}\n\nconst ZERO_COUNTERS = {\n sent: 0,\n delivered: 0,\n bounced: 0,\n hardBounced: 0,\n softBounced: 0,\n complained: 0,\n failedToSend: 0,\n}\n\nconst ZERO_RATES = {\n bounceRate: 0,\n hardBounceRate: 0,\n complaintRate: 0,\n failureRate: 0,\n}\n\n/**\n * Bump a counter on the relevant bucket doc plus the aggregate doc. Called\n * from the send / webhook paths. Idempotent at the document level (upsert).\n *\n * `dims` is null when we can't attribute the event (e.g. webhook event with\n * no matching send) — in that case only the aggregate is updated.\n */\nexport async function recordHealthCounter(\n ctx: RunnerContext,\n counter: CounterKey,\n dims: HealthDims | null,\n by = 1,\n): Promise<void> {\n const windowMs = ctx.config.circuitBreaker.windowMinutes * 60 * 1000\n const writes: Array<Promise<unknown>> = []\n\n writes.push(upsertCounter(ctx, HEALTH_AGG_ID, null, null, counter, by, windowMs))\n\n if (dims) {\n // Skip the bucket write when we can't extract a real domain from\n // fromEmail rather than funneling unrelated invalid-sender sends into a\n // shared `_unknown` bucket — that bucket can collect bounces from many\n // unrelated sources and falsely trip them all at once.\n const domain = dims.fromEmail ? extractDomain(dims.fromEmail) : null\n if (domain) {\n const id = healthBucketId(domain, dims.kind)\n writes.push(upsertCounter(ctx, id, domain, dims.kind, counter, by, windowMs))\n }\n }\n\n await Promise.all(writes)\n}\n\nasync function upsertCounter(\n ctx: RunnerContext,\n _id: string,\n senderDomain: string | null,\n kind: TemplateKind | null,\n counter: CounterKey,\n by: number,\n windowMs: number,\n): Promise<void> {\n await ctx.collections.health.updateOne(\n { _id },\n {\n $inc: { [`counters.${counter}`]: by },\n $setOnInsert: {\n _id,\n senderDomain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n rates: { ...ZERO_RATES },\n } as Partial<HealthDoc>,\n $set: { updatedAt: new Date() },\n },\n { upsert: true },\n )\n}\n\n/**\n * Recompute rates from the rolling window for every bucket and trip individual\n * buckets when thresholds are exceeded. The aggregate doc is updated but never\n * tripped. Called from the tick.\n */\nexport async function evaluateHealth(ctx: RunnerContext): Promise<void> {\n const cb = ctx.config.circuitBreaker\n const windowMs = cb.windowMinutes * 60 * 1000\n\n const docs = await ctx.collections.health.find({}).toArray()\n if (docs.length === 0) return\n\n // Ensure the aggregate doc exists so the worker-heartbeat check has\n // something to look at as soon as any bucket exists.\n const hasAgg = docs.some((d) => d._id === HEALTH_AGG_ID)\n if (!hasAgg) {\n await upsertCounter(ctx, HEALTH_AGG_ID, null, null, 'sent', 0, windowMs)\n }\n\n for (const doc of docs) {\n const isAgg = doc._id === HEALTH_AGG_ID\n const windowAge = Date.now() - new Date(doc.windowStartedAt).getTime()\n\n if (windowAge > windowMs && doc.status !== 'tripped') {\n // Window roll: zero out counters AND reset status to healthy. A bucket\n // that was 'degraded' on the prior window but receives no samples in\n // the new window should not stay degraded — degraded is a function of\n // the current window's failureRate, not a sticky state.\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n {\n $set: {\n windowStartedAt: new Date(),\n windowDurationMs: windowMs,\n counters: { ...ZERO_COUNTERS },\n rates: { ...ZERO_RATES },\n status: 'healthy',\n updatedAt: new Date(),\n },\n },\n )\n continue\n }\n\n const c = doc.counters\n const total = c.sent || 1\n const rates = {\n bounceRate: c.bounced / total,\n hardBounceRate: c.hardBounced / total,\n complaintRate: c.complained / total,\n failureRate: c.failedToSend / total,\n }\n\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { rates, updatedAt: new Date() } },\n )\n\n // Aggregate never trips, only reports.\n if (isAgg) continue\n\n if (c.sent < cb.minSendsBeforeEval) continue\n if (doc.status === 'tripped') continue\n\n let trippedReason: string | null = null\n if (rates.hardBounceRate * 100 >= cb.hardBounceRatePctTrip) {\n trippedReason = `hard bounce rate ${(rates.hardBounceRate * 100).toFixed(2)}% >= ${cb.hardBounceRatePctTrip}%`\n } else if (rates.complaintRate * 100 >= cb.complaintRatePctTrip) {\n trippedReason = `complaint rate ${(rates.complaintRate * 100).toFixed(2)}% >= ${cb.complaintRatePctTrip}%`\n } else if (rates.bounceRate * 100 >= cb.combinedBounceRatePctTrip) {\n trippedReason = `combined bounce rate ${(rates.bounceRate * 100).toFixed(2)}% >= ${cb.combinedBounceRatePctTrip}%`\n }\n\n if (trippedReason) {\n // Gate the trip write on the current non-tripped status so two\n // concurrent ticks can't both transition the same bucket. The\n // matchedCount check below tells us whether *this* tick was the one\n // that flipped it — only then do we fire the alert + audit log.\n const result = await ctx.collections.health.updateOne(\n { _id: doc._id, status: { $in: ['healthy', 'degraded'] } },\n { $set: { status: 'tripped', trippedAt: new Date(), trippedReason, updatedAt: new Date() } },\n )\n if (result.modifiedCount > 0) {\n // Audit log so the admin UI's \"Recent trips\" panel has rows to render.\n if (ctx.audit) {\n try {\n await ctx.audit({\n actor: 'system:circuit-breaker',\n action: 'health.trip',\n resource: {\n collection: 'mailer_health',\n id: String(doc._id),\n slug: `${doc.senderDomain ?? '_unknown'}|${doc.kind}`,\n },\n diffSummary: trippedReason,\n })\n } catch {\n /* swallow — audit failure must not block runner */\n }\n }\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({\n reason: `[${doc.senderDomain ?? '_unknown'} / ${doc.kind}] ${trippedReason}`,\n rates,\n })\n } catch {\n /* swallow — alert hook failures don't propagate */\n }\n }\n }\n continue\n }\n\n if (rates.failureRate * 100 >= cb.failedToSendRatePctDegrade) {\n if (doc.status !== 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'degraded', updatedAt: new Date() } },\n )\n }\n } else if (doc.status === 'degraded') {\n await ctx.collections.health.updateOne(\n { _id: doc._id },\n { $set: { status: 'healthy', updatedAt: new Date() } },\n )\n }\n }\n}\n\n/**\n * Look up the bucket status that gates a marketing send. Returns the\n * bucket doc when found, otherwise null (which the caller treats as healthy\n * — sends from a never-seen-before bucket flow through).\n */\nexport async function getBucketStatus(\n ctx: RunnerContext,\n fromEmail: string | null,\n kind: TemplateKind,\n): Promise<HealthDoc | null> {\n const domain = fromEmail ? extractDomain(fromEmail) : null\n const id = healthBucketId(domain, kind)\n return ctx.collections.health.findOne({ _id: id })\n}\n\n/**\n * Derive an effective overall status across all buckets. The aggregate doc\n * itself never trips, so callers that want a single \"is anything wrong\"\n * answer use this. Returns null when no buckets exist yet (no tick has run).\n */\nexport function effectiveOverallStatus(docs: HealthDoc[]): HealthDoc['status'] | null {\n // Only canonical bucket docs (id prefix 'd:') participate. The aggregate\n // never trips and a legacy 'singleton' doc, if it survives the migration,\n // is ignored.\n const buckets = docs.filter((d) => typeof d._id === 'string' && d._id.startsWith('d:'))\n if (buckets.length === 0) {\n return docs.length === 0 ? null : 'healthy'\n }\n if (buckets.some((d) => d.status === 'tripped')) return 'tripped'\n if (buckets.some((d) => d.status === 'degraded')) return 'degraded'\n return 'healthy'\n}\n","/**\n * Apply a normalized provider event to the corresponding Send + cascading\n * suppression / subscription updates. Called from the webhook worker.\n */\n\nimport type { NormalizedEvent } from '../../shared/types.js'\nimport type { SendDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter, type HealthDims } from './health.js'\n\nfunction dimsFromSend(send: SendDoc | null | undefined): HealthDims | null {\n if (!send) return null\n return { fromEmail: send.fromEmail, kind: send.kind }\n}\n\n/**\n * Apply unprocessed rows from mailer_webhook_events. Called by the webhook\n * worker (no age filter) and by the tick as a fallback (`olderThanMs` set) for\n * events whose enqueue failed at ingest — those would otherwise sit unprocessed\n * until the next webhook happened to arrive. The tick's age filter keeps it out\n * of the webhook worker's way in the normal path.\n */\nexport async function processWebhookBacklog(\n ctx: RunnerContext,\n opts: { olderThanMs?: number } = {},\n): Promise<void> {\n const filter: Record<string, unknown> = { processed: false }\n if (opts.olderThanMs) {\n filter.receivedAt = { $lt: new Date(Date.now() - opts.olderThanMs) }\n }\n const batch = await ctx.collections.webhookEvents.find(filter).limit(500).toArray()\n\n for (const evt of batch) {\n // At-most-once: claim the event BEFORE applying. Concurrent workers scan\n // the same unprocessed batch; without the claim each would apply the same\n // event, double-counting bounces/complaints into the circuit-breaker\n // health counters. Losing an event to a crash mid-apply is the cheaper\n // failure mode.\n const claimed = await ctx.collections.webhookEvents.findOneAndUpdate(\n { _id: evt._id, processed: false },\n { $set: { processed: true } },\n )\n if (!claimed) continue\n\n try {\n // The stored `raw` wraps the normalized event we captured at ingest;\n // pull details back out so applyWebhookEvent has the bounce reason etc.\n const normalized = (evt.raw as any)?.normalized\n const details = normalized?.details ?? {}\n await applyWebhookEvent(\n {\n type: evt.normalizedType,\n providerEventId: evt.providerEventId,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n details,\n },\n ctx,\n )\n } catch (err) {\n console.error('mailery: webhook apply failed', { id: String(evt._id), err })\n }\n }\n}\n\nexport async function applyWebhookEvent(event: NormalizedEvent, ctx: RunnerContext): Promise<void> {\n const send = await ctx.collections.sends.findOne(\n event.providerMessageId\n ? { $or: [{ providerMessageId: event.providerMessageId }, { emailAtSend: event.email }] }\n : { emailAtSend: event.email },\n { sort: { queuedAt: -1 } },\n )\n\n switch (event.type) {\n case 'delivered':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'delivered', deliveredAt: event.occurredAt } },\n )\n }\n await recordHealthCounter(ctx, 'delivered', dimsFromSend(send))\n break\n\n case 'open':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n openedAt: send.openedAt ?? event.occurredAt,\n status: send.status === 'sent' ? 'delivered' : send.status,\n },\n $inc: { openCount: 1 },\n },\n )\n }\n break\n\n case 'click':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: { firstClickAt: send.firstClickAt ?? event.occurredAt },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: event.details.clickedUrl ?? '',\n linkId: '',\n clickedAt: event.occurredAt,\n },\n },\n },\n )\n }\n break\n\n case 'bounce': {\n const bounceType = event.details.bounceType ?? 'hard'\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'bounced',\n bounceType,\n bounceReason: event.details.bounceReason ?? null,\n },\n },\n )\n }\n if (bounceType === 'hard') {\n await suppressOnce(ctx, event.email, 'hard_bounce', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n }\n {\n const dims = dimsFromSend(send)\n await recordHealthCounter(ctx, 'bounced', dims)\n await recordHealthCounter(ctx, bounceType === 'hard' ? 'hardBounced' : 'softBounced', dims)\n }\n break\n }\n\n case 'complaint':\n case 'spam_report':\n if (send) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { complainedAt: event.occurredAt, status: 'complained' } },\n )\n }\n await suppressOnce(ctx, event.email, 'complaint', 'all')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n { $set: { status: 'complained', updatedAt: new Date() } },\n )\n await recordHealthCounter(ctx, 'complained', dimsFromSend(send))\n break\n\n case 'unsubscribe':\n if (send) {\n await ctx.collections.sends.updateOne({ _id: send._id }, { $set: { unsubscribedAt: event.occurredAt } })\n }\n await suppressOnce(ctx, event.email, 'unsubscribed', 'marketing')\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: event.email },\n {\n $set: {\n status: 'unsubscribed',\n unsubscribedAt: event.occurredAt,\n unsubscribeReason: 'user_request',\n updatedAt: new Date(),\n },\n },\n )\n break\n }\n}\n\nasync function suppressOnce(\n ctx: RunnerContext,\n email: string,\n reason: 'hard_bounce' | 'complaint' | 'unsubscribed',\n scope: 'all' | 'marketing' | 'transactional',\n): Promise<void> {\n const normalized = email.toLowerCase()\n await ctx.collections.suppressions.updateOne(\n { email: normalized, scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope,\n reason,\n source: 'provider_webhook',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n}\n","/**\n * Predicate evaluator. Resolves all Predicate variants from `shared/types.ts`\n * against a Contact (host-side fields/tags) + mailer state (events, sends,\n * subscription).\n *\n * Network calls hit Mongo. Cache the Contact at the call site if you evaluate\n * many predicates in a row.\n */\n\nimport type { Contact, Predicate } from '../../shared/types.js'\nimport type { Collections, FlowRunDoc, SendDoc } from '../models/index.js'\n\nexport interface PredicateContext {\n contact: Contact\n run: FlowRunDoc\n collections: Collections\n now?: Date\n}\n\nconst BOT_UA_RE = /Mimecast|SafeLinks|proofpoint|HeadlessChrome|Googlebot|bingbot/i\n\nexport async function evaluatePredicate(\n predicate: Predicate,\n ctx: PredicateContext,\n): Promise<boolean> {\n const p = predicate as any\n\n if ('hasTag' in p) return ctx.contact.tags.includes(p.hasTag)\n if ('notHasTag' in p) return !ctx.contact.tags.includes(p.notHasTag)\n\n if ('fieldEquals' in p) {\n return ctx.contact.fields[p.fieldEquals.field] === p.fieldEquals.value\n }\n if ('fieldExists' in p) {\n return ctx.contact.fields[p.fieldExists] !== undefined\n }\n\n // Read from the run's own trigger event, NOT the contact — two concurrent\n // runs for the same person can legitimately disagree here.\n if ('triggerPropertyEquals' in p) {\n return (\n (ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyEquals.key] ===\n p.triggerPropertyEquals.value\n )\n }\n if ('triggerPropertyTruthy' in p) {\n return Boolean((ctx.run.triggerEvent?.properties ?? {})[p.triggerPropertyTruthy])\n }\n\n if ('subscriptionStatus' in p) {\n const sub = await ctx.collections.subscriptions.findOne({ externalId: ctx.contact.externalId })\n return sub?.status === p.subscriptionStatus\n }\n\n if ('hasFiredEvent' in p) {\n return hasEvent(ctx, p.hasFiredEvent, { sinceFlowStart: p.sinceFlowStart, withinDays: p.withinDays })\n }\n if ('notHasFiredEvent' in p) {\n return !(await hasEvent(ctx, p.notHasFiredEvent, { withinDays: p.withinDays }))\n }\n\n if ('hasOpened' in p) return await openOrClickCount(ctx, 'opened', p.hasOpened, false) > 0\n if ('hasClicked' in p) return await openOrClickCount(ctx, 'clicked', p.hasClicked, false) > 0\n if ('hasOpenedExcludingBots' in p) return await openOrClickCount(ctx, 'opened', p.hasOpenedExcludingBots, true) > 0\n if ('hasClickedExcludingBots' in p) return await openOrClickCount(ctx, 'clicked', p.hasClickedExcludingBots, true) > 0\n if ('openedAtLeastN' in p) return await openOrClickCount(ctx, 'opened', p.openedAtLeastN, true) >= p.openedAtLeastN.count\n if ('clickedAtLeastN' in p) return await openOrClickCount(ctx, 'clicked', p.clickedAtLeastN, true) >= p.clickedAtLeastN.count\n\n if ('all' in p) {\n for (const sub of p.all) {\n if (!(await evaluatePredicate(sub, ctx))) return false\n }\n return true\n }\n if ('any' in p) {\n for (const sub of p.any) {\n if (await evaluatePredicate(sub, ctx)) return true\n }\n return false\n }\n if ('not' in p) {\n return !(await evaluatePredicate(p.not, ctx))\n }\n\n return false\n}\n\nasync function hasEvent(\n ctx: PredicateContext,\n name: string,\n opts: { sinceFlowStart?: boolean; withinDays?: number },\n): Promise<boolean> {\n const filter: any = { externalId: ctx.contact.externalId, name }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter.occurredAt = { $gt: lower }\n const found = await ctx.collections.events.findOne(filter, { projection: { _id: 1 } })\n return !!found\n}\n\nasync function openOrClickCount(\n ctx: PredicateContext,\n kind: 'opened' | 'clicked',\n opts: { templateSlug?: string; sinceFlowStart?: boolean; withinDays?: number },\n excludeBots: boolean,\n): Promise<number> {\n const filter: any = { externalId: ctx.contact.externalId }\n if (opts.templateSlug) filter.templateSlug = opts.templateSlug\n if (kind === 'opened') filter.openedAt = { $ne: null }\n if (kind === 'clicked') filter.firstClickAt = { $ne: null }\n const lower = effectiveLowerBound(ctx, opts)\n if (lower) filter[kind === 'opened' ? 'openedAt' : 'firstClickAt'] = { $gt: lower }\n\n if (!excludeBots) {\n return await ctx.collections.sends.countDocuments(filter)\n }\n\n // Bot filter is best-effort: we only know UA for clicks (open pixel hits don't reliably carry one)\n const docs = await ctx.collections.sends.find(filter).limit(1000).toArray()\n let n = 0\n for (const s of docs) {\n if (kind === 'opened') {\n n++\n continue\n }\n const hasHumanClick = (s as SendDoc).clickedLinks?.some((c: any) => !c.userAgent || !BOT_UA_RE.test(c.userAgent))\n if (hasHumanClick) n++\n }\n return n\n}\n\nfunction effectiveLowerBound(ctx: PredicateContext, opts: { sinceFlowStart?: boolean; withinDays?: number }): Date | null {\n const now = ctx.now ?? new Date()\n if (opts.sinceFlowStart) return ctx.run.enteredAt\n if (opts.withinDays && opts.withinDays > 0) {\n return new Date(now.getTime() - opts.withinDays * 24 * 60 * 60 * 1000)\n }\n return null\n}\n","/**\n * Delivery-window math. Pure — no I/O, no Date.now(); callers pass `now`.\n *\n * Given the moment a send step becomes runnable, `computeDeliveryTime`\n * returns the earliest instant the email is allowed to go out. It only ever\n * moves forward: a send already inside its window returns `now` unchanged.\n *\n * Timezone handling uses the Intl API (no dependency). DST transitions are\n * resolved with a two-pass offset fix; the worst case during a transition is\n * being off by the shifted hour, which is fine for email delivery.\n */\n\nimport type { DeliveryWindow } from '../../shared/types.js'\n\n/**\n * Ticks fire with jitter, so a send arriving shortly AFTER its timeOfDay slot\n * still goes out rather than waiting a full day.\n */\nconst TIME_OF_DAY_GRACE_MS = 60 * 60_000\n\nexport function computeDeliveryTime(\n now: Date,\n window: DeliveryWindow,\n contactTimezone?: string,\n): Date {\n const tz = pickTimezone(window, contactTimezone)\n let candidate = now\n\n if (window.timeOfDay) {\n const [hh, mm] = window.timeOfDay.split(':').map(Number) as [number, number]\n const local = localParts(candidate, tz)\n const todaySlot = utcFromLocal(local.y, local.mo, local.d, hh, mm, tz)\n if (candidate.getTime() < todaySlot.getTime()) {\n candidate = todaySlot\n } else if (candidate.getTime() - todaySlot.getTime() > TIME_OF_DAY_GRACE_MS) {\n const next = addLocalDays(local, 1)\n candidate = utcFromLocal(next.y, next.mo, next.d, hh, mm, tz)\n }\n // else: within grace of today's slot — send now.\n }\n\n if (window.weekdaysOnly) {\n for (let guard = 0; guard < 3; guard++) {\n const local = localParts(candidate, tz)\n if (local.weekday !== 'Sat' && local.weekday !== 'Sun') break\n const shift = local.weekday === 'Sat' ? 2 : 1\n const moved = addLocalDays(local, shift)\n // Preserve the local clock time (timeOfDay slot, or the wall-clock\n // moment the step became runnable).\n candidate = utcFromLocal(moved.y, moved.mo, moved.d, local.hh, local.mi, tz)\n }\n }\n\n return candidate\n}\n\nfunction pickTimezone(window: DeliveryWindow, contactTimezone?: string): string {\n const candidates = [\n window.useContactTimezone ? contactTimezone : undefined,\n window.timezone,\n 'UTC',\n ]\n for (const tz of candidates) {\n if (tz && isValidTimezone(tz)) return tz\n }\n return 'UTC'\n}\n\nconst validatedZones = new Map<string, boolean>()\n\nfunction isValidTimezone(tz: string): boolean {\n const cached = validatedZones.get(tz)\n if (cached !== undefined) return cached\n let ok = true\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: tz })\n } catch {\n ok = false\n }\n validatedZones.set(tz, ok)\n return ok\n}\n\ninterface LocalParts {\n y: number\n mo: number\n d: number\n hh: number\n mi: number\n ss: number\n weekday: string // 'Mon'…'Sun'\n}\n\nconst partFormatters = new Map<string, Intl.DateTimeFormat>()\n\nfunction formatterFor(tz: string): Intl.DateTimeFormat {\n let f = partFormatters.get(tz)\n if (!f) {\n f = new Intl.DateTimeFormat('en-US', {\n timeZone: tz,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n weekday: 'short',\n hour12: false,\n })\n partFormatters.set(tz, f)\n }\n return f\n}\n\nfunction localParts(date: Date, tz: string): LocalParts {\n const parts: Record<string, string> = {}\n for (const p of formatterFor(tz).formatToParts(date)) parts[p.type] = p.value\n return {\n y: Number(parts.year),\n mo: Number(parts.month),\n d: Number(parts.day),\n hh: Number(parts.hour) % 24, // Intl emits '24' for midnight in some locales\n mi: Number(parts.minute),\n ss: Number(parts.second),\n weekday: parts.weekday!,\n }\n}\n\n/** UTC instant for a wall-clock time in `tz`. Two passes to converge across DST. */\nfunction utcFromLocal(y: number, mo: number, d: number, hh: number, mi: number, tz: string): Date {\n let ts = Date.UTC(y, mo - 1, d, hh, mi, 0)\n for (let i = 0; i < 2; i++) {\n const p = localParts(new Date(ts), tz)\n const asUtc = Date.UTC(p.y, p.mo - 1, p.d, p.hh, p.mi, p.ss)\n const offset = asUtc - ts\n ts = Date.UTC(y, mo - 1, d, hh, mi, 0) - offset\n }\n return new Date(ts)\n}\n\n/** Add days to a local calendar date (normalizes month/year rollover). */\nfunction addLocalDays(p: LocalParts, days: number): { y: number; mo: number; d: number } {\n const dt = new Date(Date.UTC(p.y, p.mo - 1, p.d + days))\n return { y: dt.getUTCFullYear(), mo: dt.getUTCMonth() + 1, d: dt.getUTCDate() }\n}\n","/**\n * Template render pipeline.\n *\n * authorMjml + handlebarsContext\n * ↓ Handlebars render → MJML with substituted vars\n * ↓ mjml-core compile → HTML\n * ↓ html-to-text derive → plain text alternative\n * ↓ applyTracking(sendId) → tracked HTML with rewritten links + open pixel\n *\n * Subject and preheader run through Handlebars too. Plain text is auto-derived\n * unless the template explicitly overrides it.\n */\n\nimport crypto from 'node:crypto'\nimport Handlebars from 'handlebars'\nimport { convert as htmlToText } from 'html-to-text'\nimport mjml2html from 'mjml'\n\nimport type { Contact } from '../../shared/types.js'\nimport type { TemplateDoc } from '../models/index.js'\n\n// ---------------------------------------------------------------------------\n// Compile (publish-time)\n// ---------------------------------------------------------------------------\n\nexport interface CompileResult {\n html: string\n plainText: string\n errors: Array<{ line?: number; message: string; tagName?: string; formattedMessage?: string }>\n}\n\n/** Compile MJML → HTML, then derive plain text. Called at template publish time. */\nexport async function compileTemplate(mjml: string): Promise<CompileResult> {\n const out = await mjml2html(mjml, { validationLevel: 'soft', minify: false })\n const plainText = derivePlaintext(out.html)\n return { html: out.html, plainText, errors: out.errors ?? [] }\n}\n\n/**\n * Compile Maily editor JSON (Tiptap-shape) → HTML via `@maily-to/render`, then\n * derive plain text. Called at template publish time when the template was\n * authored via the WYSIWYG editor.\n */\nexport async function compileMailyTemplate(content: unknown): Promise<CompileResult> {\n const { render } = await import('@maily-to/render')\n const html = await render(content as any)\n const plainText = derivePlaintext(html)\n return { html, plainText, errors: [] }\n}\n\n/** Auto-derive plain text from compiled HTML. */\nexport function derivePlaintext(html: string): string {\n return htmlToText(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'img', format: 'skip' },\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n ],\n }).trim()\n}\n\n// ---------------------------------------------------------------------------\n// Render (send-time)\n// ---------------------------------------------------------------------------\n\nexport interface RenderContext {\n /**\n * Host-resolved variables (varsAdapter) live at the context root, so a\n * schema key `user` renders as `{{user.name}}`. Reserved keys below always\n * win over resolved keys.\n */\n [resolvedVar: string]: unknown\n contact: Contact\n vars: Record<string, unknown>\n /** Properties of the event that triggered the flow run ({{event.*}}). Empty outside flow sends. */\n event?: Record<string, unknown>\n /** URL the recipient hits to one-click unsubscribe. */\n unsubscribeUrl: string\n /** URL to view this email in a browser (when implemented). */\n viewInBrowserUrl?: string\n /** URL for the preference center (when implemented). */\n preferenceCenterUrl?: string\n /** Configured sender postal address (CAN-SPAM). */\n senderAddress?: string\n}\n\nexport interface RenderedTemplate {\n subject: string\n preheader: string\n html: string\n plainText: string\n fromName: string\n fromEmail: string\n replyTo: string | null\n}\n\nexport interface RenderOptions {\n /** Extra Handlebars helpers contributed by the host. */\n helpers?: Record<string, Handlebars.HelperDelegate>\n}\n\n/**\n * Render a published template against a contact + vars context. Returns the\n * substituted subject/preheader/html/plainText. Tracking is NOT applied here —\n * that step needs the send id and runs separately via `applyTracking`.\n */\nexport async function renderTemplate(\n template: TemplateDoc,\n ctx: RenderContext,\n opts: RenderOptions = {},\n): Promise<RenderedTemplate> {\n const hb = makeHandlebars(opts.helpers)\n\n const subject = hb.compile(template.subject)(ctx)\n const preheader = hb.compile(template.preheader)(ctx)\n\n // Prefer the compiled HTML if present; fall back to compiling MJML on the fly.\n let html: string\n if (template.body.html) {\n html = hb.compile(template.body.html)(ctx)\n } else {\n const compiled = await compileTemplate(template.body.mjml)\n html = hb.compile(compiled.html)(ctx)\n }\n\n const plainText = template.body.plainText\n ? hb.compile(template.body.plainText)(ctx)\n : derivePlaintext(html)\n\n return {\n subject,\n preheader,\n html,\n plainText,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n replyTo: template.replyTo,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tracking application\n// ---------------------------------------------------------------------------\n\nexport interface TrackingOptions {\n sendId: string\n publicUrl: string\n trackOpens: boolean\n trackClicks: boolean\n /** URL that must NOT be rewritten (e.g. the resolved unsubscribe URL). */\n preserveUrls?: string[]\n}\n\nexport interface TrackingResult {\n html: string\n /** linkId → original URL map; persist on `mailer_sends.links` for click resolution. */\n links: Array<{ linkId: string; url: string }>\n}\n\n/**\n * Rewrite `<a href>` in `html` to /m/click/<sendId>/<linkId>?... and append an\n * open pixel. Returns the modified HTML plus the link map to persist on the\n * send document.\n */\nexport function applyTracking(html: string, opts: TrackingOptions): TrackingResult {\n const preserve = new Set((opts.preserveUrls ?? []).map((u) => u.trim()))\n const links: Array<{ linkId: string; url: string }> = []\n const seen = new Map<string, string>() // url → linkId\n\n let out = html\n\n if (opts.trackClicks) {\n out = out.replace(/<a\\b([^>]*?)\\bhref=([\"'])([^\"']+)\\2([^>]*)>/gi, (full, pre, _q, rawUrl, post) => {\n // Handlebars `{{ }}` escapes substituted URLs (& → &, = → =). That is\n // correct in HTML source, but the stored/redirect URL must be the decoded one.\n const url = decodeHtmlEntities(rawUrl)\n if (shouldSkipClickRewrite(url, preserve, full)) return full\n let linkId = seen.get(url)\n if (!linkId) {\n linkId = shortHash(`${opts.sendId}:${url}:${links.length}`)\n seen.set(url, linkId)\n links.push({ linkId, url })\n }\n const newHref = `${opts.publicUrl}/m/click/${opts.sendId}/${linkId}`\n return `<a${pre}href=\"${newHref}\"${post}>`\n })\n }\n\n if (opts.trackOpens) {\n const pixel = `<img src=\"${opts.publicUrl}/m/open/${opts.sendId}.png\" width=\"1\" height=\"1\" alt=\"\" style=\"display:block;border:0\" />`\n if (/<\\/body>/i.test(out)) {\n out = out.replace(/<\\/body>/i, `${pixel}</body>`)\n } else {\n out = out + pixel\n }\n }\n\n return { html: out, links }\n}\n\nfunction shouldSkipClickRewrite(url: string, preserve: Set<string>, fullTag: string): boolean {\n if (!url) return true\n if (url.startsWith('mailto:')) return true\n if (url.startsWith('tel:')) return true\n if (url.startsWith('#')) return true\n if (url.startsWith('{{') || url.startsWith('{')) return true // unrendered handlebars\n if (preserve.has(url.trim())) return true\n if (/data-mailer-notrack=[\"']true[\"']/.test(fullTag)) return true\n return false\n}\n\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n}\n\n/**\n * Decode the HTML entities Handlebars' escapeExpression emits (plus numeric\n * forms), so a captured href round-trips to the URL the browser would request.\n * `&` is decoded last-wins via a single pass so `&lt;` stays `<`.\n */\nfunction decodeHtmlEntities(input: string): string {\n return input.replace(/&(#x[0-9a-f]+|#\\d+|[a-z][a-z0-9]*);/gi, (match, body: string) => {\n if (body[0] === '#') {\n const code =\n body[1] === 'x' || body[1] === 'X'\n ? parseInt(body.slice(2), 16)\n : parseInt(body.slice(1), 10)\n if (!Number.isFinite(code) || code < 0 || code > 0x10ffff) return match\n try {\n return String.fromCodePoint(code)\n } catch {\n return match\n }\n }\n const named = NAMED_ENTITIES[body.toLowerCase()]\n return named ?? match\n })\n}\n\nfunction shortHash(input: string): string {\n return crypto.createHash('sha256').update(input).digest('hex').slice(0, 12)\n}\n\n// ---------------------------------------------------------------------------\n// Handlebars instance + helpers\n// ---------------------------------------------------------------------------\n\nfunction makeHandlebars(extra?: Record<string, Handlebars.HelperDelegate>): typeof Handlebars {\n const hb = Handlebars.create()\n\n hb.registerHelper('eq', (a: unknown, b: unknown) => a === b)\n hb.registerHelper('ne', (a: unknown, b: unknown) => a !== b)\n hb.registerHelper('gt', (a: any, b: any) => a > b)\n hb.registerHelper('lt', (a: any, b: any) => a < b)\n hb.registerHelper('gte', (a: any, b: any) => a >= b)\n hb.registerHelper('lte', (a: any, b: any) => a <= b)\n hb.registerHelper('and', (...args: any[]) => args.slice(0, -1).every(Boolean))\n hb.registerHelper('or', (...args: any[]) => args.slice(0, -1).some(Boolean))\n hb.registerHelper('not', (a: unknown) => !a)\n\n hb.registerHelper('formatDate', (value: unknown, fmt?: string) => {\n if (!value) return ''\n const d = value instanceof Date ? value : new Date(String(value))\n if (Number.isNaN(d.getTime())) return ''\n if (fmt === 'long') return d.toLocaleDateString('en-US', { dateStyle: 'long' })\n if (fmt === 'short') return d.toLocaleDateString('en-US', { dateStyle: 'short' })\n return d.toISOString().slice(0, 10)\n })\n\n hb.registerHelper('formatNumber', (n: unknown) => {\n const v = Number(n)\n return Number.isFinite(v) ? v.toLocaleString('en-US') : ''\n })\n\n hb.registerHelper('formatCurrency', (cents: unknown, currency: string = 'usd') => {\n const v = Number(cents)\n if (!Number.isFinite(v)) return ''\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(v / 100)\n })\n\n hb.registerHelper('pluralize', (n: unknown, one: string, many: string) =>\n Number(n) === 1 ? one : many,\n )\n\n if (extra) {\n for (const [name, fn] of Object.entries(extra)) {\n hb.registerHelper(name, fn)\n }\n }\n\n return hb\n}\n\nexport { makeHandlebars }\n","/**\n * Send pipeline. `handleSend` is called by the runner state machine; it creates\n * the Send document and enqueues a mailer:send job. `dispatchSend` is the\n * worker — re-checks suppression + circuit breaker, applies tracking, calls\n * the provider, updates the Send row.\n */\n\nimport crypto from 'node:crypto'\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport {\n applyTracking,\n renderTemplate,\n type RenderContext,\n} from '../templates/render.js'\nimport { signUnsubscribeToken } from '../tokens.js'\nimport { resolveVars } from '../adapters/vars.js'\nimport { isSuppressed } from './suppression.js'\nimport { advanceStep, failFlowRun } from './step.js'\nimport { getBucketStatus, recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function handleSend(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'send' }>,\n contact: Contact,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: step.templateSlug })\n if (!template) {\n await failFlowRun(run, `template not found: ${step.templateSlug}`, ctx)\n return\n }\n\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}`\n\n // Idempotency: has this exact step already produced a send?\n const existing = await ctx.collections.sends.findOne({ dedupeKey })\n if (existing) {\n await advanceStep(run, ctx, {\n action: 'sent',\n details: { dedupeKey, alreadySent: true, sendId: String(existing._id) },\n })\n return\n }\n\n const providerName = pickProviderName(step.providerOverride, template, ctx)\n\n // Render now (with fresh contact + vars). Tracking application happens in\n // dispatchSend once we have the persisted sendId.\n const renderCtx = buildRenderContext(contact, run, step.vars ?? {}, ctx)\n let rendered\n try {\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await ctx.collections.sends.insertOne(\n newSendDoc({\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: template.subject,\n bodyHash: '',\n status: 'failed',\n errorMessage: `render error: ${err?.message ?? err}`,\n }),\n )\n await advanceStep(run, ctx, {\n action: 'send_skipped',\n details: { reason: 'render_error', message: String(err?.message ?? err) },\n })\n return\n }\n\n const sendId = new ObjectId()\n await ctx.collections.sends.insertOne(\n newSendDoc({\n _id: sendId,\n dedupeKey,\n run,\n contact,\n template,\n flow,\n providerName,\n renderedSubject: rendered.subject,\n bodyHash: sha256(rendered.html),\n status: 'queued',\n renderedFrom: rendered.fromName ? { name: rendered.fromName, email: rendered.fromEmail } : undefined,\n vars: step.vars ?? {},\n }),\n )\n\n await ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: ctx.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n await advanceStep(run, ctx, { action: 'sent', details: { dedupeKey, sendId: String(sendId) } })\n}\n\n// ---------------------------------------------------------------------------\n// Send worker entry point\n// ---------------------------------------------------------------------------\n\nexport async function dispatchSend(sendId: ObjectId, ctx: RunnerContext): Promise<void> {\n // Atomic claim: flip queued/failed → sending so exactly one worker proceeds.\n // The stranded-send sweep and the queue's stalled-job retry can both fire a\n // job for the same send; a read-then-act status check lets both through and\n // the recipient gets the email twice. Every downstream path writes a\n // terminal status (or resets to 'queued' for the breaker retry); a crash\n // leaves 'sending', which the stranded-send sweep resets after 5 minutes.\n const send = await ctx.collections.sends.findOneAndUpdate(\n { _id: sendId, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'sending', updatedAt: new Date() } },\n )\n if (!send) return // already claimed / dispatched / cancelled\n\n const template = await ctx.collections.templates.findOne({ _id: send.templateId })\n if (!template) {\n await markFailed(send._id!, 'template_missing', ctx)\n return\n }\n\n // 1. Suppression check (INVARIANT 3: always re-checked at send time).\n const supp = await isSuppressed(ctx.collections, send.emailAtSend, send.kind)\n if (supp.suppressed) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'suppressed', errorMessage: `suppressed: ${supp.reason}` } },\n )\n return\n }\n\n // 2. Circuit-breaker check (only blocks marketing). The breaker is scoped\n // per (senderDomain, kind) bucket — one bad subdomain doesn't hold mail for\n // the others.\n if (send.kind === 'marketing') {\n const bucket = await getBucketStatus(ctx, send.fromEmail, send.kind)\n if (bucket?.status === 'tripped') {\n // Release the claim so the delayed retry can re-claim it.\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n await ctx.queues.send.add('send', { sendId: String(send._id) }, { delay: 60_000 })\n return\n }\n }\n\n // 3. Pull the contact + re-render (use the contact that exists now, not at flow entry).\n const contact = await ctx.adapter.getById(send.externalId)\n if (!contact) {\n await markFailed(send._id!, 'contact_missing', ctx)\n return\n }\n\n const run = send.flowRunId ? await ctx.collections.flowRuns.findOne({ _id: send.flowRunId }) : null\n\n // Aborted-run guard: closes the race where a send is enqueued between the\n // abort's send-cancellation sweep and dispatch. Only host aborts block here —\n // completed/naturally-exited runs may still have legitimately queued mail.\n if (run && run.status === 'exited' && run.exitReason?.startsWith('aborted_by_host')) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${run.exitReason}`, updatedAt: new Date() } },\n )\n return\n }\n\n // Resolve host vars + render. A throw here (host DB hiccup, bad template)\n // marks the send failed and rethrows so the queue retries with backoff —\n // never dispatch a half-rendered email.\n let renderCtx: RenderContext\n let rendered: Awaited<ReturnType<typeof renderTemplate>>\n try {\n const resolved = await resolveVars(ctx.varsAdapter, contact, {\n reason: 'send',\n templateSlug: template.slug,\n flowSlug: run?.flowSlug,\n eventName: run?.triggerEvent?.name,\n eventProperties: run?.triggerEvent?.properties,\n })\n renderCtx = buildRenderContext(contact, run, send.vars ?? {}, ctx, resolved)\n rendered = await renderTemplate(template, renderCtx, { helpers: ctx.handlebarsHelpers })\n } catch (err: any) {\n await markFailed(send._id!, `render error: ${String(err?.message ?? err)}`, ctx)\n throw err // let the queue retry per the attempts policy\n }\n\n // 4. Apply tracking using the now-known send id.\n const tracking = applyTracking(rendered.html, {\n sendId: String(send._id),\n publicUrl: ctx.config.publicUrl,\n trackOpens: template.trackOpens ?? ctx.config.trackOpens,\n trackClicks: template.trackClicks ?? ctx.config.trackClicks,\n preserveUrls: [renderCtx.unsubscribeUrl],\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n links: tracking.links,\n bodyHash: sha256(tracking.html),\n status: 'sending',\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: rendered.subject,\n updatedAt: new Date(),\n },\n },\n )\n\n // 5. Provider dispatch.\n const provider = ctx.providers[send.provider] ?? ctx.providers[ctx.config.defaultProvider]\n if (!provider) {\n await markFailed(send._id!, `provider_unknown: ${send.provider}`, ctx)\n return\n }\n\n // List-Unsubscribe belongs on bulk mail only. The unsubscribe token is\n // scoped 'marketing', so advertising one-click unsub on a password reset\n // both misrepresents the header and offers an opt-out that wouldn't stop\n // the transactional mail the recipient is looking at.\n const headers: Record<string, string> =\n send.kind === 'marketing'\n ? {\n 'List-Unsubscribe': `<${renderCtx.unsubscribeUrl}>`,\n 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',\n }\n : {}\n\n try {\n const result = await provider.send({\n to: send.emailAtSend,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n replyTo: rendered.replyTo ?? undefined,\n subject: rendered.subject,\n html: tracking.html,\n text: rendered.plainText,\n headers,\n messageMeta: { sendId: String(send._id) },\n })\n\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n {\n $set: {\n status: 'sent',\n sentAt: new Date(),\n providerMessageId: result.providerId,\n },\n },\n )\n // Use send.fromEmail (same field getBucketStatus reads) so the breaker\n // gate and the counter record into the same bucket even if a\n // hypothetical render-time fromDefaults swap ever lands.\n await recordHealthCounter(ctx, 'sent', { fromEmail: send.fromEmail, kind: send.kind })\n } catch (err: any) {\n await ctx.collections.sends.updateOne(\n { _id: send._id },\n { $set: { status: 'failed', errorMessage: String(err?.message ?? err) } },\n )\n await recordHealthCounter(ctx, 'failedToSend', { fromEmail: send.fromEmail, kind: send.kind })\n if (ctx.config.onSendFailure) {\n try {\n await ctx.config.onSendFailure({ send, error: err })\n } catch {\n /* swallow */\n }\n }\n throw err // let BullMQ retry per the attempts policy\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction pickProviderName(stepOverride: string | undefined, tpl: TemplateDoc, ctx: RunnerContext): string {\n if (stepOverride) return stepOverride\n if (tpl.providerOverride) return tpl.providerOverride\n if (tpl.kind === 'transactional' && ctx.config.defaultTransactionalProvider) {\n return ctx.config.defaultTransactionalProvider\n }\n return ctx.config.defaultProvider\n}\n\nfunction buildRenderContext(\n contact: Contact,\n run: FlowRunDoc | null,\n vars: Record<string, unknown>,\n ctx: RunnerContext,\n resolved: Record<string, unknown> = {},\n): RenderContext {\n const scope = 'marketing'\n const expiresAt = new Date(Date.now() + ctx.config.unsubscribeTokenLifetimeDays * 24 * 60 * 60 * 1000)\n const token = signUnsubscribeToken(\n { email: contact.email, scope, expiresAt },\n ctx.config.unsubscribeSecret,\n )\n const unsubscribeUrl = `${ctx.config.publicUrl}/m/unsub/${token}`\n\n return {\n ...resolved,\n contact,\n vars,\n event: run?.triggerEvent?.properties ?? {},\n unsubscribeUrl,\n senderAddress: ctx.config.senderAddress,\n }\n}\n\ninterface NewSendInput {\n _id?: ObjectId\n dedupeKey: string\n run: FlowRunDoc\n contact: Contact\n template: TemplateDoc\n flow: FlowDoc\n providerName: string\n renderedSubject: string\n bodyHash: string\n status: SendDoc['status']\n errorMessage?: string\n renderedFrom?: { name: string; email: string }\n vars?: Record<string, unknown>\n}\n\nfunction newSendDoc(input: NewSendInput): SendDoc {\n const now = new Date()\n return {\n _id: input._id,\n dedupeKey: input.dedupeKey,\n externalId: input.run.externalId,\n emailAtSend: input.contact.email,\n templateId: input.template._id!,\n templateSlug: input.template.slug,\n flowRunId: input.run._id!,\n broadcastId: null,\n manualSendBy: null,\n kind: input.template.kind,\n provider: input.providerName,\n providerMessageId: null,\n fromName: input.renderedFrom?.name ?? input.template.fromName,\n fromEmail: input.renderedFrom?.email ?? input.template.fromEmail,\n subject: input.renderedSubject,\n bodyHash: input.bodyHash,\n status: input.status,\n errorMessage: input.errorMessage ?? null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: input.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: now,\n updatedAt: now,\n sentAt: null,\n deliveredAt: null,\n }\n}\n\nasync function markFailed(sendId: ObjectId, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.sends.updateOne(\n { _id: sendId },\n { $set: { status: 'failed', errorMessage: reason } },\n )\n}\n\nfunction sha256(s: string): string {\n return crypto.createHash('sha256').update(s).digest('hex')\n}\n","/**\n * Suppression checks. INVARIANT 3: re-checked at send time, never trusted\n * from enqueue time. INVARIANT 9: hashed-suppression records (GDPR forget)\n * block sends without retaining the plaintext email.\n */\n\nimport type { Collections } from '../models/index.js'\nimport type { SuppressionScope, TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\n\nexport interface SuppressionResult {\n suppressed: boolean\n scope?: string\n reason?: string\n}\n\nconst SCOPES_BY_KIND: Record<TemplateKind, SuppressionScope[]> = {\n marketing: ['all', 'marketing'],\n transactional: ['all', 'transactional'],\n}\n\nexport async function isSuppressed(\n collections: Collections,\n email: string,\n kind: TemplateKind,\n): Promise<SuppressionResult> {\n const normalized = email.toLowerCase()\n const allowed = SCOPES_BY_KIND[kind]\n\n const byEmail = await collections.suppressions.findOne({\n email: normalized,\n scope: { $in: allowed },\n $or: [{ expiresAt: null }, { expiresAt: { $gt: new Date() } }],\n })\n if (byEmail) return { suppressed: true, scope: byEmail.scope, reason: byEmail.reason }\n\n const hashed = await collections.suppressions.findOne({\n emailHash: sha256Hex(normalized),\n scope: { $in: allowed },\n })\n if (hashed) return { suppressed: true, scope: hashed.scope, reason: hashed.reason }\n\n return { suppressed: false }\n}\n","/**\n * Flow_run state machine. One step transition per `processOneRunStep` call.\n * Idempotent — optimistic concurrency on `currentStepIndex` means two workers\n * racing on the same run advance exactly once.\n */\n\nimport type { ObjectId } from 'mongodb'\n\nimport type { FlowStep } from '../../shared/types.js'\nimport type { FlowRunDoc, FlowDoc } from '../models/index.js'\nimport { evaluatePredicate } from './predicate.js'\nimport type { RunnerContext } from './index.js'\nimport { computeDeliveryTime } from './delivery-window.js'\nimport { handleSend } from './send.js'\n\n/**\n * Tolerance on the not-yet-due check below. A delayed job may fire a few\n * milliseconds early, and clocks between app servers drift; without slack\n * those runs would bounce to the sweep and stall for a whole tick.\n */\nconst DUE_SKEW_MS = 1_000\n\nexport async function processOneRunStep(runId: ObjectId, ctx: RunnerContext): Promise<void> {\n const run = await ctx.collections.flowRuns.findOne({ _id: runId })\n if (!run || run.status !== 'active') return\n\n // Don't touch a run that is parked in the future. The schedule used to be\n // enforced only by the callers — the sweep's `nextActionAt <= now` filter and\n // the advance job's delay — which is a time-of-check/time-of-use race: the\n // sweep selects a run that is due, the run's own advance job parks it on a\n // wait in the meantime, and the sweep then processes the step AFTER the wait,\n // skipping it entirely. That is reachable on every tick, because a freshly\n // triggered run is inserted with `nextActionAt = now` and `runTick` runs the\n // trigger scan and the sweep back to back — so a flow whose first step is a\n // wait could lose it. The invariant belongs with the state, not the caller.\n if (run.nextActionAt && run.nextActionAt.getTime() > Date.now() + DUE_SKEW_MS) return\n\n const flow = await ctx.collections.flows.findOne({ _id: run.flowId })\n if (!flow) {\n await failFlowRun(run, 'flow_missing', ctx)\n return\n }\n\n const steps = await loadStepsForRun(run, flow, ctx)\n const step = locateStep(steps, run.currentStepIndex, run.currentBranchPath)\n if (!step) {\n await completeFlowRun(run, 'completed', ctx)\n return\n }\n\n const contact = await ctx.adapter.getById(run.externalId)\n if (!contact) {\n await exitFlowRun(run, 'contact_missing', ctx)\n return\n }\n\n // Subscription gate: flows are marketing-scope. Any non-subscribed status\n // exits the run before the next step, regardless of template kind — there is\n // deliberately no transactional bypass here. Transactional mail that must\n // reach not-subscribed contacts (receipts, password resets) goes through\n // sendOneOff, not a flow. Entry is gated the same way in triggers.ts.\n const sub = await ctx.collections.subscriptions.findOne({ externalId: run.externalId })\n if (sub && sub.status !== 'subscribed') {\n await exitFlowRun(run, sub.status, ctx)\n return\n }\n\n switch (step.type) {\n case 'wait':\n return handleWait(run, step, ctx)\n case 'condition':\n return handleCondition(run, step, contact, ctx)\n case 'branch':\n return handleBranch(run, step, contact, ctx)\n case 'send': {\n // Delivery window: push the send to the next allowed slot (weekday /\n // time-of-day, optionally in the contact's timezone) before rendering.\n if (step.delivery) {\n const deliverAt = computeDeliveryTime(new Date(), step.delivery, contact.timezone)\n if (deliverAt.getTime() > Date.now() + 30_000) {\n return deferSendForWindow(run, deliverAt, ctx)\n }\n }\n return handleSend(run, step, contact, flow, ctx)\n }\n case 'tag':\n return handleTag(run, step, ctx)\n case 'fire_event':\n return handleFireEvent(run, step, ctx)\n case 'webhook':\n return handleWebhookStep(run, step, ctx)\n case 'exit':\n return exitFlowRun(run, step.reason ?? 'exit_step', ctx)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Step handlers\n// ---------------------------------------------------------------------------\n\nasync function handleWait(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'wait' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const ms = unitToMs(step.value, step.unit)\n const nextAt = new Date(Date.now() + ms)\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: nextAt, attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: 1 },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'wait_started',\n at: new Date(),\n details: { until: nextAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return // another worker advanced; their job will fire.\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: ms, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex + 1}` },\n )\n}\n\nasync function handleCondition(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'condition' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections })\n\n if (result) {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: true } })\n return\n }\n if (step.ifFalse === 'continue') {\n await advanceStep(run, ctx, { action: 'condition_evaluated', details: { result: false, skipped: 1 } }, { stepInc: 2 })\n return\n }\n await exitFlowRun(run, 'condition_false', ctx)\n}\n\nasync function handleBranch(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'branch' }>,\n contact: Awaited<ReturnType<typeof ctx.adapter.getById>>,\n ctx: RunnerContext,\n): Promise<void> {\n if (!contact) return\n const result = await evaluatePredicate(step.test, { contact, run, collections: ctx.collections })\n const newPath = [...run.currentBranchPath, run.currentStepIndex, result ? 'true' : 'false', 0] as Array<number | 'true' | 'false'>\n\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: {\n currentBranchPath: newPath,\n currentStepIndex: 0,\n nextActionAt: new Date(),\n attemptsForCurrentStep: 0,\n updatedAt: new Date(),\n },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'branch_taken',\n at: new Date(),\n details: { result },\n },\n },\n },\n { returnDocument: 'after' },\n )\n\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nasync function handleTag(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'tag' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const adds = step.addTags ?? []\n const removes = step.removeTags ?? []\n\n if (ctx.adapter.addTags && adds.length > 0) {\n await ctx.adapter.addTags(run.externalId, adds)\n } else if (adds.length > 0) {\n await ctx.collections.contactTags.bulkWrite(\n adds.map((tag) => ({\n updateOne: {\n filter: { externalId: run.externalId, tag },\n update: { $setOnInsert: { externalId: run.externalId, tag, appliedBy: 'flow', appliedAt: new Date() } },\n upsert: true,\n },\n })),\n )\n }\n\n if (ctx.adapter.removeTags && removes.length > 0) {\n await ctx.adapter.removeTags(run.externalId, removes)\n } else if (removes.length > 0) {\n await ctx.collections.contactTags.deleteMany({ externalId: run.externalId, tag: { $in: removes } })\n }\n\n await advanceStep(run, ctx, { action: 'tagged', details: { addTags: adds, removeTags: removes } })\n}\n\nasync function handleFireEvent(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'fire_event' }>,\n ctx: RunnerContext,\n): Promise<void> {\n const dedupeKey = `flowrun:${run._id}:step${run.currentStepIndex}:${step.eventName}`\n try {\n await ctx.collections.events.insertOne({\n externalId: run.externalId,\n name: step.eventName,\n // Inherit the triggering event's properties so a handoff carries the\n // context that identifies what the run is ABOUT (which account, order,\n // subscription, ...). A step's `properties` are static — authored once in\n // the flow definition — so without this a fired event can only ever say\n // \"this contact\", losing the scope the originating event supplied, and\n // the receiving flow has nothing to resolve variables against. Explicit\n // step.properties win on conflict.\n properties: { ...(run.triggerEvent?.properties ?? {}), ...(step.properties ?? {}) },\n dedupeKey,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n await advanceStep(run, ctx, { action: 'event_fired', details: { name: step.eventName } })\n}\n\nasync function handleWebhookStep(\n run: FlowRunDoc,\n step: Extract<FlowStep, { type: 'webhook' }>,\n ctx: RunnerContext,\n): Promise<void> {\n try {\n const res = await fetch(step.url, {\n method: step.method ?? 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(step.payload ?? { externalId: run.externalId, flowRunId: String(run._id) }),\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) throw new Error(`webhook step returned ${res.status}`)\n await advanceStep(run, ctx, { action: 'webhook_called', details: { url: step.url, status: res.status } })\n } catch (err: any) {\n const attempts = (run.attemptsForCurrentStep ?? 0) + 1\n if (attempts >= ctx.config.webhookRetryAttempts) {\n if (step.failureMode === 'fail_run') {\n await failFlowRun(run, `webhook failed: ${err?.message}`, ctx)\n } else {\n // Soft fail — log and advance.\n await advanceStep(run, ctx, {\n action: 'webhook_called',\n details: { url: step.url, error: err?.message, exhausted: true },\n })\n }\n } else {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n { $inc: { attemptsForCurrentStep: 1 }, $set: { nextActionAt: new Date(Date.now() + 60_000) } },\n )\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n { delay: 60_000, jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:retry-${attempts}` },\n )\n }\n }\n}\n\n/**\n * Park the run on the SAME step until the delivery window opens, then let the\n * normal advance job re-enter processOneRunStep — at which point the window\n * check passes and handleSend runs. Idempotent via the jobId (one defer job\n * per step per slot) and the nextActionAt guard.\n */\nasync function deferSendForWindow(run: FlowRunDoc, deliverAt: Date, ctx: RunnerContext): Promise<void> {\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n // Only write once per deferral — if nextActionAt already points at (or\n // past) the slot, another worker/tick got here first.\n { _id: run._id, currentStepIndex: run.currentStepIndex, nextActionAt: { $lt: deliverAt } },\n {\n $set: { nextActionAt: deliverAt, updatedAt: new Date() },\n $push: {\n history: {\n stepIndex: run.currentStepIndex,\n action: 'send_deferred' as const,\n at: new Date(),\n details: { until: deliverAt },\n },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n\n await ctx.queues.advance.add(\n 'advance',\n { flowRunId: String(run._id) },\n {\n delay: Math.max(0, deliverAt.getTime() - Date.now()),\n jobId: `advance:${run._id}:${branchKey(run)}:${run.currentStepIndex}:window:${deliverAt.getTime()}`,\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Common helpers\n// ---------------------------------------------------------------------------\n\nexport interface AdvanceOptions {\n stepInc?: number\n}\n\nexport interface AdvanceLog {\n action: FlowRunDoc['history'][number]['action']\n details?: Record<string, unknown>\n}\n\nexport async function advanceStep(\n run: FlowRunDoc,\n ctx: RunnerContext,\n log: AdvanceLog,\n opts: AdvanceOptions = {},\n): Promise<void> {\n const stepInc = opts.stepInc ?? 1\n const updated = await ctx.collections.flowRuns.findOneAndUpdate(\n { _id: run._id, currentStepIndex: run.currentStepIndex },\n {\n $set: { nextActionAt: new Date(), attemptsForCurrentStep: 0, updatedAt: new Date() },\n $inc: { currentStepIndex: stepInc },\n $push: {\n history: { stepIndex: run.currentStepIndex, action: log.action, at: new Date(), details: log.details },\n },\n },\n { returnDocument: 'after' },\n )\n if (!updated) return\n await ctx.queues.advance.add('advance', { flowRunId: String(run._id) })\n}\n\nexport async function exitFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'exited', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'exited', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function completeFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'completed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n },\n )\n}\n\nexport async function failFlowRun(run: FlowRunDoc, reason: string, ctx: RunnerContext): Promise<void> {\n await ctx.collections.flowRuns.updateOne(\n { _id: run._id, status: 'active' },\n {\n $set: { status: 'failed', exitedAt: new Date(), exitReason: reason, updatedAt: new Date() },\n $push: { history: { stepIndex: run.currentStepIndex, action: 'failed', at: new Date(), details: { reason } } },\n },\n )\n}\n\nexport async function loadStepsForRun(\n run: FlowRunDoc,\n flow: FlowDoc,\n ctx: RunnerContext,\n): Promise<FlowStep[]> {\n if (run.flowVersion === flow.version) return flow.steps\n const snapshot = await ctx.collections.flowVersions.findOne({ flowId: run.flowId, version: run.flowVersion })\n return snapshot?.steps ?? flow.steps\n}\n\n/**\n * Walk a branch path through nested branch steps to find the active step.\n * Branch path layout: [parentStepIndex, 'true'|'false', childStepIndex, ...repeat]\n */\nexport function locateStep(\n steps: FlowStep[],\n currentStepIndex: number,\n branchPath: ReadonlyArray<number | 'true' | 'false'>,\n): FlowStep | null {\n let arr: FlowStep[] = steps\n\n for (let i = 0; i < branchPath.length; i += 3) {\n const parentIndex = branchPath[i] as number\n const branchKey = branchPath[i + 1] as 'true' | 'false'\n const parent = arr[parentIndex]\n if (!parent || parent.type !== 'branch') return null\n arr = branchKey === 'true' ? parent.ifTrueSteps : parent.ifFalseSteps\n }\n\n return arr[currentStepIndex] ?? null\n}\n\n/**\n * Branch-path discriminator for advance jobIds. `currentStepIndex` resets to 0\n * on branch entry, so (runId, stepIndex) alone is not unique across a run's\n * lifetime — the same numeric index recurs inside each branch arm.\n */\nfunction branchKey(run: FlowRunDoc): string {\n return run.currentBranchPath.join('_')\n}\n\nfunction unitToMs(value: number, unit: 'minutes' | 'hours' | 'days' | 'weeks'): number {\n const m = 60_000\n switch (unit) {\n case 'minutes':\n return value * m\n case 'hours':\n return value * 60 * m\n case 'days':\n return value * 24 * 60 * m\n case 'weeks':\n return value * 7 * 24 * 60 * m\n }\n}\n","/**\n * Recovery sweep: finds active flow_runs whose `nextActionAt` has passed but\n * weren't woken by their delayed `mailer:advance` job (worker restart, BullMQ\n * data loss). Processes each one inline.\n */\n\nimport { processOneRunStep } from './step.js'\nimport type { RunnerContext } from './index.js'\n\nconst SWEEP_LIMIT = 500\n\nexport async function sweepStrandedFlowRuns(ctx: RunnerContext): Promise<void> {\n const runs = await ctx.collections.flowRuns\n .find({ status: 'active', nextActionAt: { $lte: new Date() } })\n .sort({ nextActionAt: 1 })\n .limit(SWEEP_LIMIT)\n .toArray()\n\n for (const run of runs) {\n try {\n await processOneRunStep(run._id!, ctx)\n } catch (err) {\n console.error('mailery: sweep advance failed', { runId: String(run._id), err })\n }\n }\n}\n","/**\n * Broadcast dispatch. Picks up scheduled broadcasts whose `scheduledAt` has\n * passed, streams the segment via the adapter cursor + mailer-side post-filter,\n * and bulk-enqueues Send docs + jobs. Per-provider rate limiting + bounded\n * enqueue (pause when waitingCount > broadcastEnqueueMaxWaiting).\n */\n\nimport { ObjectId } from 'mongodb'\n\nimport type { Contact, SegmentDefinition, SegmentFilter, AdapterFilter } from '../../shared/types.js'\nimport type { BroadcastDoc, SendDoc, TemplateDoc } from '../models/index.js'\nimport { isSuppressed } from './suppression.js'\nimport { sha256Hex } from '../tokens.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Broadcasts stuck in 'sending' with updatedAt older than this are assumed\n * dead (worker crashed mid-dispatch). dispatchBroadcast heartbeats updatedAt\n * on every page, so a stale timestamp means no live dispatcher.\n */\nconst STALLED_BROADCAST_THRESHOLD_MS = 10 * 60 * 1000\n\n/**\n * Process scheduled broadcasts whose `scheduledAt` has passed. Called from the\n * tick. Marks each broadcast `sending` before dispatch so concurrent ticks\n * don't double-dispatch.\n */\nexport async function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n const now = new Date()\n const due = await ctx.collections.broadcasts\n .find({ status: 'scheduled', scheduledAt: { $lte: now } })\n .toArray()\n\n for (const b of due) {\n // Optimistic claim — only one worker takes this broadcast.\n const claimed = await ctx.collections.broadcasts.findOneAndUpdate(\n { _id: b._id, status: 'scheduled' },\n { $set: { status: 'sending', startedAt: now, updatedAt: now } },\n { returnDocument: 'after' },\n )\n if (!claimed) continue\n await startBroadcastDispatch(claimed, ctx)\n }\n}\n\n/**\n * Hand the (potentially hours-long) recipient enqueue off the tick. With a\n * real queue driver, dispatch runs as an advance job so a large broadcast\n * can't starve trigger scans and sweeps — the tick worker has concurrency 1.\n * The noop driver has no workers (hosts drive the runner synchronously), so\n * dispatch stays inline there.\n */\nasync function startBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n if (ctx.config.queue.driver === 'noop') {\n await runBroadcastDispatch(broadcast, ctx)\n return\n }\n await ctx.queues.advance.add(\n 'advance',\n { broadcastId: String(broadcast._id) },\n {\n attempts: 3,\n backoff: { type: 'exponential', delay: 60_000 },\n jobId: `broadcast-dispatch:${broadcast._id}`,\n },\n )\n}\n\n/** Advance-worker entry point for `{ broadcastId }` jobs. */\nexport async function dispatchBroadcastById(broadcastId: ObjectId, ctx: RunnerContext): Promise<void> {\n const broadcast = await ctx.collections.broadcasts.findOne({ _id: broadcastId, status: 'sending' })\n if (!broadcast) return\n await runBroadcastDispatch(broadcast, ctx)\n}\n\n/**\n * Rescue broadcasts whose dispatcher died. Re-dispatch is idempotent: the\n * per-recipient dedupeKey unique index skips send rows already inserted, so\n * a resumed broadcast picks up where the dead worker left off.\n */\nexport async function resumeStalledBroadcasts(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STALLED_BROADCAST_THRESHOLD_MS)\n const stalled = await ctx.collections.broadcasts\n .find({ status: 'sending', updatedAt: { $lt: cutoff } })\n .toArray()\n\n for (const b of stalled) {\n // Touch before re-dispatch so subsequent ticks don't stack rescues.\n await ctx.collections.broadcasts.updateOne(\n { _id: b._id },\n { $set: { updatedAt: new Date() } },\n )\n await startBroadcastDispatch(b, ctx)\n }\n}\n\nasync function runBroadcastDispatch(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n try {\n await dispatchBroadcast(broadcast, ctx)\n } catch (err) {\n console.error('mailery: broadcast dispatch failed', { id: String(broadcast._id), err })\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n }\n}\n\nasync function dispatchBroadcast(broadcast: BroadcastDoc, ctx: RunnerContext): Promise<void> {\n const template = await ctx.collections.templates.findOne({ slug: broadcast.templateSlug })\n if (!template) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { status: 'failed', updatedAt: new Date() } },\n )\n return\n }\n\n const hostFilter = toAdapterFilter(broadcast.segmentDefinition)\n const postFilters = broadcast.segmentDefinition.filters.filter((f) => isMailerSide(f))\n\n let cursor: string | undefined = undefined\n let total = 0\n const batchSize = ctx.config.broadcastEnqueueBatchSize\n const maxWaiting = ctx.config.broadcastEnqueueMaxWaiting\n const respectTimezone = broadcast.respectRecipientTimezone === true\n const scheduledMs = broadcast.scheduledAt?.getTime() ?? Date.now()\n\n for (;;) {\n // Progress heartbeat — resumeStalledBroadcasts treats a stale updatedAt\n // as a dead dispatcher, so touch it every page (and during backpressure).\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n\n const page = await ctx.adapter.query(hostFilter, { limit: batchSize, cursor })\n if (page.contacts.length === 0) break\n\n // Stage B: mailer-side post-filter.\n const eligible = await applyPostFilters(page.contacts, postFilters, ctx)\n\n if (eligible.length > 0) {\n // Backpressure: wait until the send queue's waiting set drains below cap.\n while ((await ctx.queues.send.getWaitingCount()) > maxWaiting) {\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n { $set: { updatedAt: new Date() } },\n )\n await sleep(2000)\n }\n\n const sendDocs = await Promise.all(\n eligible.map(async (contact) => buildSendDoc(broadcast, template, contact, ctx, scheduledMs, respectTimezone)),\n )\n\n // Filter out suppressed (mailer-side suppression check is the same one\n // dispatchSend would do; we short-circuit here to avoid enqueuing).\n const inserted: Array<{ sendId: ObjectId; delayMs: number }> = []\n for (const { doc, delayMs } of sendDocs) {\n if (!doc) continue\n try {\n await ctx.collections.sends.insertOne(doc)\n inserted.push({ sendId: doc._id!, delayMs })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // dup dedupeKey — already dispatched somewhere\n }\n }\n\n // Bulk enqueue.\n if (inserted.length > 0) {\n await Promise.all(\n inserted.map(({ sendId, delayMs }) =>\n ctx.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n ...(delayMs > 0 ? { delay: delayMs } : {}),\n },\n ),\n ),\n )\n }\n\n total += inserted.length\n }\n\n if (!page.nextCursor) break\n cursor = page.nextCursor\n }\n\n await ctx.collections.broadcasts.updateOne(\n { _id: broadcast._id },\n {\n $set: {\n status: 'sent',\n completedAt: new Date(),\n recipientCount: total,\n updatedAt: new Date(),\n },\n },\n )\n}\n\n// ---------------------------------------------------------------------------\n// Segment translation\n// ---------------------------------------------------------------------------\n\nfunction toAdapterFilter(seg: SegmentDefinition): AdapterFilter {\n const out: AdapterFilter = {}\n for (const f of seg.filters) {\n switch (f.kind) {\n case 'hasTag':\n out.hasTag = f.tag\n break\n case 'fieldEquals':\n out.fieldEquals = { field: f.field, value: f.value }\n break\n case 'fieldIn':\n out.fieldIn = { field: f.field, values: f.values }\n break\n case 'fieldExists':\n out.fieldExists = f.field\n break\n // notHasTag isn't a single-condition adapter filter, defer to post-filter\n // subscriptionStatus / firedEvent / opened are all mailer-side\n }\n }\n return out\n}\n\nfunction isMailerSide(f: SegmentFilter): boolean {\n return (\n f.kind === 'subscriptionStatus' ||\n f.kind === 'firedEvent' ||\n f.kind === 'notFiredEvent' ||\n f.kind === 'subscribedAfter' ||\n f.kind === 'subscribedBefore' ||\n f.kind === 'opened' ||\n f.kind === 'notOpened' ||\n f.kind === 'notHasTag' ||\n f.kind === 'any' ||\n f.kind === 'not'\n )\n}\n\nasync function applyPostFilters(contacts: Contact[], filters: SegmentFilter[], ctx: RunnerContext): Promise<Contact[]> {\n if (filters.length === 0) return contacts\n const externalIds = contacts.map((c) => c.externalId)\n\n // Cache common lookups in one Mongo round-trip per filter.\n const cache: Record<string, Set<string>> = {}\n for (const f of filters) {\n if (f.kind === 'subscriptionStatus') {\n const docs = await ctx.collections.subscriptions\n .find({ externalId: { $in: externalIds }, status: f.equals })\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`sub:${f.equals}`] = new Set(docs.map((d) => d.externalId))\n }\n if (f.kind === 'firedEvent' || f.kind === 'notFiredEvent') {\n const query: any = { externalId: { $in: externalIds }, name: f.eventName }\n if (f.withinDays) {\n query.occurredAt = { $gt: new Date(Date.now() - f.withinDays * 86_400_000) }\n }\n const docs = await ctx.collections.events\n .find(query)\n .project<{ externalId: string }>({ externalId: 1 })\n .toArray()\n cache[`evt:${f.eventName}`] = new Set(docs.map((d) => d.externalId))\n }\n }\n\n return contacts.filter((c) => filters.every((f) => filterMatches(c, f, cache)))\n}\n\nfunction filterMatches(c: Contact, f: SegmentFilter, cache: Record<string, Set<string>>): boolean {\n switch (f.kind) {\n case 'subscriptionStatus':\n return cache[`sub:${f.equals}`]?.has(c.externalId) ?? false\n case 'firedEvent':\n return cache[`evt:${f.eventName}`]?.has(c.externalId) ?? false\n case 'notFiredEvent':\n return !cache[`evt:${f.eventName}`]?.has(c.externalId)\n case 'notHasTag':\n return !c.tags.includes(f.tag)\n case 'opened':\n case 'notOpened':\n // V1: not implemented in batch — would need a per-contact send lookup.\n // Treat as pass for now; suppress at dispatch time.\n return true\n case 'subscribedAfter':\n case 'subscribedBefore':\n return true // V2\n case 'any':\n return f.filters.some((sub) => filterMatches(c, sub, cache))\n case 'not':\n return !filterMatches(c, f.filter, cache)\n default:\n return true\n }\n}\n\n// ---------------------------------------------------------------------------\n// Send doc construction\n// ---------------------------------------------------------------------------\n\ninterface BuildResult {\n doc: SendDoc | null\n delayMs: number\n}\n\nasync function buildSendDoc(\n broadcast: BroadcastDoc,\n template: TemplateDoc,\n contact: Contact,\n ctx: RunnerContext,\n scheduledMs: number,\n respectTimezone: boolean,\n): Promise<BuildResult> {\n // Final suppression check before we insert.\n const supp = await isSuppressed(ctx.collections, contact.email, template.kind)\n if (supp.suppressed) return { doc: null, delayMs: 0 }\n\n const sendId = new ObjectId()\n const dedupeKey = `broadcast:${broadcast._id}:${contact.externalId}`\n\n // Per-recipient TZ delay calculation. Anchored to scheduledAt (not enqueue\n // time) so tick lag and backpressure pauses don't drift later batches.\n let delayMs = Math.max(0, scheduledMs - Date.now())\n if (respectTimezone && contact.timezone) {\n const offsetMs = perRecipientOffsetMs(scheduledMs, contact.timezone)\n delayMs = Math.max(0, scheduledMs + offsetMs - Date.now())\n }\n\n const doc: SendDoc = {\n _id: sendId,\n dedupeKey,\n externalId: contact.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: broadcast._id!,\n manualSendBy: null,\n kind: template.kind,\n provider: template.providerOverride ?? ctx.config.defaultProvider,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n }\n void sha256Hex\n return { doc, delayMs }\n}\n\n/**\n * Offset to add to `scheduledMs` so the email arrives at the same WALL-CLOCK\n * time in the recipient's timezone.\n *\n * Example: broadcast `scheduledAt` is 10am UTC, contact is in PST (UTC-8).\n * Their 10am is 6pm UTC → offset +8h.\n *\n * Recipients EAST of the schedule's timezone would need a negative offset —\n * their 10am already passed when dispatch starts. Sending \"now\" would land at\n * the wrong local time, so instead the offset is normalized into [0, 24h):\n * they get the NEXT occurrence of the wall-clock slot, i.e. same time\n * tomorrow. (Berlin, UTC+2: raw offset −2h → +22h.)\n */\nfunction perRecipientOffsetMs(scheduledMs: number, timezone: string): number {\n const DAY_MS = 24 * 60 * 60 * 1000\n try {\n // Get the offset between the scheduled UTC instant interpreted as a wall\n // clock and the same wall clock in the recipient's tz.\n const scheduled = new Date(scheduledMs)\n const utc = scheduled.toLocaleString('en-US', { timeZone: 'UTC', hour12: false })\n const local = scheduled.toLocaleString('en-US', { timeZone: timezone, hour12: false })\n\n // Parse both as Date objects in the runner's local tz and take the diff.\n const parse = (s: string) => {\n const m = s.match(/(\\d+)\\/(\\d+)\\/(\\d+),\\s*(\\d+):(\\d+):(\\d+)/)\n if (!m) return 0\n return Date.UTC(+m[3]!, +m[1]! - 1, +m[2]!, +m[4]!, +m[5]!, +m[6]!)\n }\n const utcMs = parse(utc)\n const localMs = parse(local)\n const offsetMs = utcMs - localMs\n\n return ((offsetMs % DAY_MS) + DAY_MS) % DAY_MS\n } catch {\n return 0\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * Soft → hard bounce promotion. Configurable threshold + window:\n *\n * softBouncePromotionThreshold soft bounces for the same email within\n * softBouncePromotionWindowDays → insert a hard suppression + mark\n * the subscription bounced.\n *\n * Runs on each tick. Idempotent: if a hard suppression already exists for\n * that email, we skip.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport { sha256Hex } from '../tokens.js'\nimport { recordHealthCounter } from './health.js'\nimport type { RunnerContext } from './index.js'\n\nexport async function promoteSoftBounces(ctx: RunnerContext): Promise<void> {\n const threshold = ctx.config.softBouncePromotionThreshold\n const windowDays = ctx.config.softBouncePromotionWindowDays\n if (threshold <= 0 || windowDays <= 0) return\n\n const cutoff = new Date(Date.now() - windowDays * 86_400_000)\n\n // Aggregate: count soft bounces per emailAtSend since cutoff, hitting the\n // threshold. Bounded limit to keep the tick fast.\n const offenders = await ctx.collections.sends\n .aggregate<{ _id: string; count: number; lastFromEmail: string | null; lastKind: TemplateKind | null }>([\n { $match: { status: 'bounced', bounceType: 'soft', queuedAt: { $gt: cutoff } } },\n { $sort: { queuedAt: 1 } },\n {\n $group: {\n _id: '$emailAtSend',\n count: { $sum: 1 },\n lastFromEmail: { $last: '$fromEmail' },\n lastKind: { $last: '$kind' },\n },\n },\n { $match: { count: { $gte: threshold } } },\n { $limit: 200 },\n ])\n .toArray()\n\n for (const o of offenders) {\n const email = String(o._id ?? '').toLowerCase()\n if (!email) continue\n\n // Skip if already hard-suppressed.\n const existing = await ctx.collections.suppressions.findOne({\n email,\n scope: 'all',\n })\n if (existing) continue\n\n await ctx.collections.suppressions.updateOne(\n { email, scope: 'all' },\n {\n $setOnInsert: {\n email,\n emailHash: sha256Hex(email),\n scope: 'all',\n reason: 'hard_bounce',\n source: 'soft_promotion',\n notes: `${o.count} soft bounces in last ${windowDays} days`,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await ctx.collections.subscriptions.updateOne(\n { emailAtSubscribe: email },\n { $set: { status: 'bounced', updatedAt: new Date() } },\n )\n\n await recordHealthCounter(\n ctx,\n 'hardBounced',\n o.lastKind ? { fromEmail: o.lastFromEmail, kind: o.lastKind } : null,\n )\n }\n}\n","/**\n * DNSBL monitor. Once a day (or on demand) we DNS-query each configured\n * sender domain against domain block lists (DBLs) and each configured\n * dedicated IP against IP block lists. Results are stored as one doc per\n * (target, list) — the latest result replaces the prior one.\n *\n * No external API. Pure DNS, so it works in any environment that can\n * resolve public hostnames.\n */\n\nimport dns from 'node:dns/promises'\nimport net from 'node:net'\nimport psl from 'psl'\n\nimport type {\n DnsblConfig,\n DnsblListSpec,\n} from '../config.js'\nimport {\n DEFAULT_DOMAIN_DNSBL_LISTS,\n DEFAULT_IP_DNSBL_LISTS,\n} from '../config.js'\nimport type { DnsblCheckDoc, DnsblResult, DnsblTargetKind } from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Lists that expect a registrable domain (eTLD+1) rather than the full\n * FQDN. Querying `mail.foo.example.com.multi.surbl.org` returns NXDOMAIN\n * even when `example.com` is listed.\n */\nconst REGISTRABLE_ONLY_LISTS = new Set(['multi.surbl.org', 'multi.uribl.com'])\n\n/** DNS-query concurrency for parallel lookups. Keep modest to avoid resolver throttling. */\nconst DNS_CONCURRENCY = 8\n\nexport interface Resolver {\n resolve4(hostname: string): Promise<string[]>\n}\n\nconst defaultResolver: Resolver = {\n resolve4: (hostname) => dns.resolve4(hostname),\n}\n\nexport interface RunDnsblOptions {\n /** Override the DNS resolver (used in tests). */\n resolver?: Resolver\n /** When true, ignore the throttle and run all checks immediately. */\n force?: boolean\n}\n\nexport interface RunDnsblResult {\n ran: boolean\n reason?: string\n totalChecks?: number\n listedCount?: number\n}\n\n/**\n * Run DNSBL checks for every (target × list) pair. Idempotent — the latest\n * result for each pair is upserted.\n */\nexport async function runDnsblChecks(\n ctx: RunnerContext,\n opts: RunDnsblOptions = {},\n): Promise<RunDnsblResult> {\n const cfg = ctx.config.dnsbl ?? {}\n const intervalHours = cfg.intervalHours ?? 24\n\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const targets = collectTargets(ctx, cfg)\n if (targets.domains.length === 0 && targets.ips.length === 0) {\n return { ran: false, reason: 'no_targets' }\n }\n\n const resolver = opts.resolver ?? defaultResolver\n const domainLists = cfg.domainLists ?? DEFAULT_DOMAIN_DNSBL_LISTS\n const ipLists = cfg.ipLists ?? DEFAULT_IP_DNSBL_LISTS\n\n const pairs: Array<{\n target: string\n targetKind: DnsblTargetKind\n list: DnsblListSpec\n }> = []\n for (const d of targets.domains) {\n for (const l of domainLists) pairs.push({ target: d, targetKind: 'domain', list: l })\n }\n for (const ip of targets.ips) {\n for (const l of ipLists) pairs.push({ target: ip, targetKind: 'ip', list: l })\n }\n\n // Per-pair throttle: skip pairs whose existing row is fresher than the\n // interval. Force ignores the throttle. This replaces the previous\n // single-most-recent-check gate that blocked the whole suite based on\n // one stale row.\n const throttleCutoff = opts.force ? null : Date.now() - intervalHours * 60 * 60 * 1000\n let duePairs = pairs\n if (throttleCutoff != null) {\n const existing = await ctx.collections.dnsblChecks\n .find(\n {\n $or: pairs.map((p) => ({ target: p.target, list: p.list.host })),\n },\n { projection: { target: 1, list: 1, runAt: 1 } },\n )\n .toArray()\n const fresh = new Set<string>()\n for (const e of existing) {\n if (new Date(e.runAt).getTime() > throttleCutoff) {\n fresh.add(`${e.target}|${e.list}`)\n }\n }\n duePairs = pairs.filter((p) => !fresh.has(`${p.target}|${p.list.host}`))\n if (duePairs.length === 0) {\n return { ran: false, reason: 'not_due', totalChecks: 0, listedCount: 0 }\n }\n }\n\n let listedCount = 0\n\n // Bounded parallelism — DNS lookups are I/O-bound, but blasting all 25+\n // queries at once invites resolver throttling.\n async function processPair(p: typeof pairs[number]) {\n const queryName = buildQueryName(p.target, p.targetKind, p.list.host)\n const lookup = queryName\n ? await queryDnsbl(resolver, queryName)\n : { result: 'error' as DnsblResult, returnCodes: [], errorMessage: 'unsupported target format' }\n // Transient DNS failure: preserve the prior verdict so a momentary\n // resolver hiccup doesn't flip a clean target to 'error' in setup-status.\n if (lookup.transient) return\n if (lookup.result === 'listed') listedCount++\n await ctx.collections.dnsblChecks.updateOne(\n { target: p.target, list: p.list.host },\n {\n $set: {\n target: p.target,\n targetKind: p.targetKind,\n list: p.list.host,\n listLabel: p.list.label,\n result: lookup.result,\n returnCodes: lookup.returnCodes,\n errorMessage: lookup.errorMessage,\n runAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n\n let idx = 0\n await Promise.all(\n Array.from({ length: Math.min(DNS_CONCURRENCY, duePairs.length) }, async () => {\n while (idx < duePairs.length) {\n const my = idx++\n await processPair(duePairs[my]!)\n }\n }),\n )\n\n return { ran: true, totalChecks: duePairs.length, listedCount }\n}\n\n/**\n * Targets we'll check: every sender domain we know about + any explicitly\n * configured dedicated IPs. Domains come from `senderDomains` registry plus\n * the From defaults so an operator who only set fromDefaults still gets\n * coverage.\n */\nfunction collectTargets(ctx: RunnerContext, cfg: DnsblConfig): { domains: string[]; ips: string[] } {\n const domains = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) domains.add(d.toLowerCase())\n }\n const fromDomain = ctx.config.fromDefaults?.email\n ? extractDomain(ctx.config.fromDefaults.email)\n : null\n if (fromDomain) domains.add(fromDomain)\n const txnDomain = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (txnDomain) domains.add(txnDomain)\n\n // Both IPv4 and IPv6 are valid query targets — let the lookup layer handle\n // formatting per RFC 5782. Invalid strings are dropped here so they don't\n // produce a row with errorMessage='unsupported target format' on every run.\n return {\n domains: Array.from(domains),\n ips: (cfg.dedicatedIps ?? []).filter((ip) => net.isIP(ip) !== 0),\n }\n}\n\n/**\n * Compute the DNS name to query for a (target, list) pair, honoring the\n * per-list peculiarities:\n * - IPv4: reverse octets and prepend.\n * - IPv6: reverse nibble-by-nibble per RFC 5782.\n * - Domain on a registrable-only list (SURBL/URIBL): collapse to eTLD+1.\n *\n * Returns null when the target shape isn't supported by the list (e.g.,\n * IPv4-only list given an IPv6 target).\n */\nfunction buildQueryName(target: string, kind: DnsblTargetKind, listHost: string): string | null {\n if (kind === 'ip') {\n const v = net.isIP(target)\n if (v === 4) return `${reverseIPv4(target)}.${listHost}`\n if (v === 6) return `${reverseIPv6Nibbles(target)}.${listHost}`\n return null\n }\n // Domain — collapse to registrable label for lists that demand it.\n const domain = REGISTRABLE_ONLY_LISTS.has(listHost) ? registrableDomain(target) : target\n return `${domain}.${listHost}`\n}\n\ninterface QueryResult {\n /** When true, the underlying DNS query failed transiently (SERVFAIL etc).\n * Caller should leave the existing row in place rather than overwrite it. */\n transient?: boolean\n result: DnsblResult\n returnCodes: string[]\n errorMessage: string | null\n}\n\n// Transient DNS errors we don't want to treat as a \"list error\" — these\n// indicate a resolver problem or rate-limit at the block-list side and\n// should be retried next tick rather than producing a setup-status warn.\nconst TRANSIENT_DNS_CODES = new Set(['ESERVFAIL', 'EREFUSED', 'ETIMEOUT', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'])\n\nasync function queryDnsbl(resolver: Resolver, query: string): Promise<QueryResult> {\n try {\n const records = await resolver.resolve4(query)\n return interpretRecords(records)\n } catch (err: any) {\n const code = err?.code\n // NXDOMAIN / no records → not listed.\n if (code === 'ENOTFOUND' || code === 'ENODATA') {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Transient: signal the runner to skip the upsert. Spamhaus and friends\n // SERVFAIL when rate-limiting public resolvers; storing those as 'error'\n // produces setup-status warn churn without operator-actionable signal.\n if (code && TRANSIENT_DNS_CODES.has(code)) {\n return {\n transient: true,\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n return {\n result: 'error',\n returnCodes: [],\n errorMessage: String(err?.message ?? err),\n }\n }\n}\n\nexport function interpretRecords(records: string[]): QueryResult {\n if (!records || records.length === 0) {\n return { result: 'clean', returnCodes: [], errorMessage: null }\n }\n // Per Spamhaus convention, 127.255.255.x is reserved for query-error /\n // public-resolver / blocked-by-list signals. Treat those as errors so they\n // don't false-positive a \"listed\" verdict.\n const errorish = records.filter((r) => r.startsWith('127.255.255.'))\n if (errorish.length === records.length) {\n return {\n result: 'error',\n returnCodes: records,\n errorMessage: `list returned reserved code(s): ${records.join(', ')}`,\n }\n }\n const listed = records.filter((r) => r.startsWith('127.') && !r.startsWith('127.255.255.'))\n if (listed.length > 0) {\n return { result: 'listed', returnCodes: records, errorMessage: null }\n }\n return { result: 'clean', returnCodes: records, errorMessage: null }\n}\n\nexport function reverseIPv4(ip: string): string {\n return ip.split('.').reverse().join('.')\n}\n\n/**\n * RFC 5782 §2.4 nibble-reversed form for IPv6. Each hex digit becomes its\n * own label in reverse order. Example:\n * 2001:db8::1\n * → 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2\n *\n * Handles IPv4-mapped form (`::ffff:1.2.3.4`) by converting the embedded\n * dot-octet portion into two hex groups before nibble-expanding.\n */\nexport function reverseIPv6Nibbles(ip: string): string {\n // First convert any embedded IPv4 (\"::ffff:1.2.3.4\" → \"::ffff:0102:0304\").\n const v4Match = /:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/.exec(ip)\n let normalized = ip\n if (v4Match) {\n const octets = v4Match[1]!.split('.').map((o) => Number(o))\n if (octets.length === 4 && octets.every((o) => o >= 0 && o <= 255)) {\n const hi = ((octets[0]! << 8) | octets[1]!).toString(16).padStart(4, '0')\n const lo = ((octets[2]! << 8) | octets[3]!).toString(16).padStart(4, '0')\n normalized = ip.slice(0, v4Match.index) + ':' + hi + ':' + lo\n }\n }\n\n // Expand `::` shorthand and zero-pad each group to 4 chars.\n const sides = normalized.split('::')\n let groups: string[]\n if (sides.length === 1) {\n groups = sides[0]!.split(':')\n } else {\n const left = sides[0]!.split(':').filter(Boolean)\n const right = sides[1]!.split(':').filter(Boolean)\n const missing = 8 - left.length - right.length\n groups = [...left, ...Array(missing).fill('0'), ...right]\n }\n if (groups.length !== 8) {\n throw new Error(`unexpected IPv6 group count for ${ip}: ${groups.length}`)\n }\n const padded = groups.map((g) => g.toLowerCase().padStart(4, '0')).join('')\n return padded.split('').reverse().join('.')\n}\n\n/**\n * Public Suffix List-aware eTLD+1 extraction. Required for SURBL / URIBL\n * which need the registrable domain — `mail.example.co.uk` must collapse to\n * `example.co.uk`, not `co.uk`. Falls back to the original input when PSL\n * can't classify the domain (e.g., a private TLD).\n */\nfunction registrableDomain(domain: string): string {\n const parsed = psl.parse(domain)\n if ('domain' in parsed && parsed.domain) return parsed.domain\n return domain\n}\n","/**\n * Google Postmaster Tools API client + daily puller.\n *\n * - Exchanges the operator-provided OAuth refresh token for short-lived\n * access tokens (cached until ~5 minutes before expiry).\n * - Pulls per-domain TrafficStats for each registered sender domain.\n * - Persists one PostmasterSnapshot per (domain, day).\n * - When a snapshot reports `domainReputation: 'BAD'`, trips the\n * (domain × marketing) health bucket so the runner stops dispatching\n * marketing mail from that domain.\n *\n * Setup is one-time and external — operator creates an OAuth client in their\n * own Google Cloud project, performs the consent flow, and configures the\n * refresh token in MailerConfig.postmaster.\n */\n\nimport type { PostmasterConfig } from '../config.js'\nimport type {\n PostmasterReputation,\n PostmasterSnapshotDoc,\n} from '../models/index.js'\nimport { extractDomain } from '../templates/sender-domain.js'\nimport type { RunnerContext } from './index.js'\nimport { healthBucketId } from '../models/index.js'\n\nconst OAUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token'\nconst POSTMASTER_BASE = 'https://gmailpostmastertools.googleapis.com/v1'\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nasync function fetchWithTimeout(fetcher: Fetcher, url: string, init: RequestInit = {}, timeoutMs = FETCH_TIMEOUT_MS): Promise<Response> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), timeoutMs)\n try {\n return await fetcher(url, { ...init, signal: ctl.signal })\n } finally {\n clearTimeout(t)\n }\n}\n\nexport interface PostmasterClient {\n listDomains(): Promise<Array<{ name: string; createTime?: string }>>\n getLatestTrafficStats(domain: string): Promise<TrafficStat | null>\n}\n\ninterface OAuthResponse {\n access_token: string\n expires_in: number\n scope?: string\n token_type?: string\n}\n\nexport interface TrafficStat {\n /** Resource name, e.g. `domains/example.com/trafficStats/20240101`. */\n name: string\n domainReputation?: PostmasterReputation\n ipReputations?: Array<{ reputation: PostmasterReputation; ipCount: string | number }>\n userReportedSpamRatio?: number\n spfSuccessRatio?: number\n dkimSuccessRatio?: number\n dmarcSuccessRatio?: number\n inboundEncryptionRatio?: number\n outboundEncryptionRatio?: number\n deliveryErrors?: Array<{ errorType: string; errorClass: string; errorRatio: number }>\n spammyFeedbackLoops?: Array<{ id: string; spamRatio: number }>\n}\n\nexport function createPostmasterClient(\n cfg: Pick<PostmasterConfig, 'clientId' | 'clientSecret' | 'refreshToken'>,\n fetcher: Fetcher = globalThis.fetch,\n): PostmasterClient {\n let cached: { accessToken: string; expiresAt: number } | null = null\n\n async function getAccessToken(): Promise<string> {\n if (cached && cached.expiresAt > Date.now() + 5 * 60 * 1000) {\n return cached.accessToken\n }\n const body = new URLSearchParams({\n client_id: cfg.clientId,\n client_secret: cfg.clientSecret,\n refresh_token: cfg.refreshToken,\n grant_type: 'refresh_token',\n })\n const res = await fetchWithTimeout(fetcher, OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n })\n if (!res.ok) {\n throw new Error(`Postmaster OAuth token refresh failed: ${res.status} ${await safeText(res)}`)\n }\n const data = (await res.json()) as OAuthResponse\n cached = {\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n return cached.accessToken\n }\n\n async function authedGet<T>(path: string): Promise<T> {\n const token = await getAccessToken()\n const res = await fetchWithTimeout(fetcher, `${POSTMASTER_BASE}${path}`, {\n method: 'GET',\n headers: { authorization: `Bearer ${token}` },\n })\n if (!res.ok) {\n throw new Error(`Postmaster GET ${path} failed: ${res.status} ${await safeText(res)}`)\n }\n return (await res.json()) as T\n }\n\n return {\n async listDomains() {\n const data = await authedGet<{ domains?: Array<{ name: string; createTime?: string }> }>('/domains')\n return data.domains ?? []\n },\n\n async getLatestTrafficStats(domain: string) {\n // Postmaster traffic stats are reported with a ~2-day delay. Pull the\n // most recent available; the API returns them in reverse-chronological\n // order when no date range is specified.\n const data = await authedGet<{ trafficStats?: TrafficStat[] }>(\n `/domains/${encodeURIComponent(domain)}/trafficStats?pageSize=1`,\n )\n return data.trafficStats?.[0] ?? null\n },\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return '<no body>'\n }\n}\n\n// ---------------------------------------------------------------------------\n// Puller\n// ---------------------------------------------------------------------------\n\nexport interface RunPostmasterOptions {\n client?: PostmasterClient\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunPostmasterResult {\n ran: boolean\n reason?: string\n fetched?: number\n trippedDomains?: string[]\n}\n\nexport async function runPostmasterPull(\n ctx: RunnerContext,\n opts: RunPostmasterOptions = {},\n): Promise<RunPostmasterResult> {\n const cfg = ctx.config.postmaster\n if (!cfg) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) {\n return { ran: false, reason: 'disabled' }\n }\n\n const client =\n opts.client ?? createPostmasterClient(cfg, opts.fetcher)\n const allDomains = resolveDomains(ctx, cfg)\n if (allDomains.length === 0) {\n return { ran: false, reason: 'no_domains' }\n }\n\n // Per-domain throttle — fetch only domains whose latest snapshot is\n // older than intervalHours. Previously a single global timestamp across\n // all domains locked unfetched / partially-failed domains out of the\n // next run for a full window.\n let domains = allDomains\n if (!opts.force) {\n const cutoff = Date.now() - intervalHours * 60 * 60 * 1000\n const latest = await ctx.collections.postmasterSnapshots\n .find({ domain: { $in: allDomains } }, { projection: { domain: 1, fetchedAt: 1 } })\n .sort({ fetchedAt: -1 })\n .limit(allDomains.length * 8)\n .toArray()\n const lastByDomain = new Map<string, number>()\n for (const s of latest) {\n const ts = new Date(s.fetchedAt).getTime()\n const cur = lastByDomain.get(s.domain) ?? 0\n if (ts > cur) lastByDomain.set(s.domain, ts)\n }\n domains = allDomains.filter((d) => (lastByDomain.get(d) ?? 0) < cutoff)\n if (domains.length === 0) {\n return { ran: false, reason: 'not_due' }\n }\n }\n\n // Fetch all domains in parallel — they're independent HTTP calls and\n // serial ordering only multiplies tick latency.\n const fetches = await Promise.all(\n domains.map(async (domain) => {\n try {\n const stat = await client.getLatestTrafficStats(domain)\n return { domain, stat, error: null as Error | null }\n } catch (err: any) {\n console.error(`mailery: postmaster fetch failed for ${domain}`, err)\n return { domain, stat: null, error: err as Error }\n }\n }),\n )\n\n let fetched = 0\n const trippedDomains: string[] = []\n for (const { domain, stat } of fetches) {\n if (!stat) continue\n const snapshot = toSnapshot(domain, stat)\n if (!snapshot) continue\n fetched++\n\n await ctx.collections.postmasterSnapshots.updateOne(\n { domain: snapshot.domain, date: snapshot.date },\n { $set: snapshot },\n { upsert: true },\n )\n\n if (snapshot.domainReputation === 'BAD') {\n // Trip every kind the registry says this domain is allowed to send\n // as. If the registry doesn't know this domain at all, skip the\n // auto-trip — we have no signal that the operator wants this domain\n // gated by mailery.\n const kindsToTrip = kindsForDomain(ctx, domain)\n for (const kind of kindsToTrip) {\n const tripped = await tripBucket(ctx, domain, kind, snapshot)\n if (tripped) trippedDomains.push(`${domain}|${kind}`)\n }\n }\n }\n\n return { ran: true, fetched, trippedDomains }\n}\n\nfunction kindsForDomain(ctx: RunnerContext, domain: string): Array<'marketing' | 'transactional'> {\n const registry = ctx.config.senderDomains ?? {}\n const entry = registry[domain.toLowerCase()]\n if (!entry) return []\n if (entry.kind === 'both') return ['marketing', 'transactional']\n return [entry.kind]\n}\n\nfunction resolveDomains(ctx: RunnerContext, cfg: PostmasterConfig): string[] {\n if (cfg.domains && cfg.domains.length > 0) {\n return cfg.domains.map((d) => d.toLowerCase())\n }\n const out = new Set<string>()\n const registry = ctx.config.senderDomains\n if (registry) {\n for (const d of Object.keys(registry)) out.add(d.toLowerCase())\n }\n const f = ctx.config.fromDefaults?.email ? extractDomain(ctx.config.fromDefaults.email) : null\n if (f) out.add(f)\n const t = ctx.config.transactionalFromDefaults?.email\n ? extractDomain(ctx.config.transactionalFromDefaults.email)\n : null\n if (t) out.add(t)\n return Array.from(out)\n}\n\nfunction toSnapshot(domain: string, stat: TrafficStat): PostmasterSnapshotDoc | null {\n // `name` looks like `domains/example.com/trafficStats/20240115`. Bail out\n // when the format isn't recognized rather than overwriting today's snapshot\n // every run — the previous fallback to today's UTC date silently rewrote\n // legitimate data when the API format ever drifted.\n const m = /\\/trafficStats\\/(\\d{8})$/.exec(stat.name ?? '')\n if (!m) {\n console.error(`mailery: postmaster snapshot for ${domain} has unrecognized name \"${stat.name}\" — skipping`)\n return null\n }\n const yyyymmdd = m[1]!\n const date = `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`\n\n return {\n domain,\n date,\n domainReputation: stat.domainReputation ?? null,\n ipReputations: stat.ipReputations\n ? stat.ipReputations.map((r) => ({\n reputation: r.reputation,\n ipCount: typeof r.ipCount === 'string' ? Number(r.ipCount) : r.ipCount,\n }))\n : null,\n userReportedSpamRatio: stat.userReportedSpamRatio ?? null,\n spfSuccessRatio: stat.spfSuccessRatio ?? null,\n dkimSuccessRatio: stat.dkimSuccessRatio ?? null,\n dmarcSuccessRatio: stat.dmarcSuccessRatio ?? null,\n outboundEncryptionRatio: stat.outboundEncryptionRatio ?? null,\n inboundEncryptionRatio: stat.inboundEncryptionRatio ?? null,\n deliveryErrors: stat.deliveryErrors ?? null,\n spammyFeedbackLoops: stat.spammyFeedbackLoops ?? null,\n fetchedAt: new Date(),\n }\n}\n\n/**\n * Set a (domain × kind) bucket to `tripped` so the dispatcher holds matching\n * sends. The bucket is created on demand if it doesn't exist yet — Postmaster\n * can flag a domain before mailery has ever sent from it.\n */\nasync function tripBucket(\n ctx: RunnerContext,\n domain: string,\n kind: 'marketing' | 'transactional',\n snapshot: PostmasterSnapshotDoc,\n): Promise<boolean> {\n const id = healthBucketId(domain, kind)\n const reason = `Postmaster Tools reports ${domain} reputation = BAD on ${snapshot.date}`\n\n // Only update + alert when the bucket transitions to tripped — otherwise a\n // sustained BAD reputation would fire onCircuitBreakerTrip on every pull.\n const prior = await ctx.collections.health.findOne({ _id: id })\n if (prior?.status === 'tripped') {\n return false\n }\n\n await ctx.collections.health.updateOne(\n { _id: id },\n {\n $set: {\n status: 'tripped',\n trippedAt: new Date(),\n trippedReason: reason,\n updatedAt: new Date(),\n },\n $setOnInsert: {\n _id: id,\n senderDomain: domain,\n kind,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n if (ctx.config.onCircuitBreakerTrip) {\n try {\n await ctx.config.onCircuitBreakerTrip({ reason, rates: { userReportedSpamRatio: snapshot.userReportedSpamRatio ?? 0 } })\n } catch {\n /* swallow */\n }\n }\n return true\n}\n","/**\n * Microsoft SNDS (Smart Network Data Services) puller.\n *\n * https://sendersupport.olc.protection.outlook.com/snds/\n *\n * SNDS reports IP-level Outlook/Hotmail/Live reputation: filter verdict\n * (GREEN/YELLOW/RED), complaint rate, spam-trap hits, and sample HELO /\n * MAIL FROM strings for each activity window. Only meaningful when the\n * operator sends from a dedicated IP — shared-IP senders see nothing\n * meaningful here.\n *\n * Auth is a per-account access key (no OAuth). The data endpoint returns\n * CSV. Snapshots are stored per (ip, activityStart) so historical windows\n * accumulate.\n */\n\nimport type { SndsConfig } from '../config.js'\nimport type { SndsFilterResult, SndsSnapshotDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nconst SNDS_DATA_URL = 'https://postmaster.live.com/snds/data.aspx'\nconst FETCH_TIMEOUT_MS = 30_000\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface RunSndsOptions {\n fetcher?: Fetcher\n force?: boolean\n}\n\nexport interface RunSndsResult {\n ran: boolean\n reason?: string\n rowsParsed?: number\n rowsPersisted?: number\n}\n\nexport async function runSndsPull(\n ctx: RunnerContext,\n opts: RunSndsOptions = {},\n): Promise<RunSndsResult> {\n const cfg = ctx.config.snds\n if (!cfg?.accessKey) return { ran: false, reason: 'not_configured' }\n\n const intervalHours = cfg.intervalHours ?? 24\n if (!opts.force && intervalHours <= 0) return { ran: false, reason: 'disabled' }\n\n if (!opts.force) {\n const latest = await ctx.collections.sndsSnapshots\n .find({})\n .sort({ fetchedAt: -1 })\n .limit(1)\n .toArray()\n if (latest[0]) {\n const ageMs = Date.now() - new Date(latest[0].fetchedAt).getTime()\n if (ageMs < intervalHours * 60 * 60 * 1000) {\n return { ran: false, reason: 'not_due' }\n }\n }\n }\n\n const fetcher = opts.fetcher ?? globalThis.fetch\n const url = `${SNDS_DATA_URL}?key=${encodeURIComponent(cfg.accessKey)}`\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(url, { method: 'GET', signal: ctl.signal })\n } catch (err: any) {\n // Scrub the access key from any error message before it reaches a log.\n throw new Error(`SNDS data fetch failed: ${redactKey(String(err?.message ?? err), cfg.accessKey)}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n throw new Error(`SNDS data fetch failed: ${res.status} ${redactKey(await safeText(res), cfg.accessKey)}`)\n }\n const csv = await res.text()\n const rows = parseSndsCsv(csv)\n\n const ipFilter = cfg.ips?.length ? new Set(cfg.ips) : null\n const now = new Date()\n const ops = rows\n .filter((row) => !ipFilter || ipFilter.has(row.ip))\n .map((row) => ({\n updateOne: {\n filter: { ip: row.ip, activityStart: row.activityStart },\n update: { $set: { ...row, fetchedAt: now } },\n upsert: true,\n },\n }))\n let persisted = 0\n if (ops.length > 0) {\n const r = await ctx.collections.sndsSnapshots.bulkWrite(ops, { ordered: false })\n persisted = (r.modifiedCount ?? 0) + (r.upsertedCount ?? 0)\n }\n\n return { ran: true, rowsParsed: rows.length, rowsPersisted: persisted }\n}\n\nfunction redactKey(s: string, key: string): string {\n if (!key) return s\n return s.split(key).join('<redacted>').split(encodeURIComponent(key)).join('<redacted>')\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// CSV parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedSndsRow {\n ip: string\n activityStart: Date\n activityEnd: Date\n rcptCommands: number\n dataCommands: number\n messageRecipients: number\n filterResult: SndsFilterResult\n complaintRate: number | null\n trapMessageCount: number\n sampleHelo: string | null\n sampleMailFrom: string | null\n}\n\n/**\n * SNDS returns CSV with columns:\n * IP, ActivityStart, ActivityEnd, RCPTCommands, DATACommands,\n * MessageRecipients, FilterResult, ComplaintRate, TrapMessageCount,\n * SampleHELO, SampleMailFrom\n *\n * No header row. Fields may contain commas inside quoted strings (sample\n * HELO / MAIL FROM) — we handle simple double-quote escaping.\n */\nexport function parseSndsCsv(csv: string): ParsedSndsRow[] {\n const out: ParsedSndsRow[] = []\n for (const raw of csv.split(/\\r?\\n/)) {\n if (!raw.trim()) continue\n const fields = splitCsvRow(raw)\n if (fields.length < 7) continue // malformed row\n const parsed = parseRow(fields)\n if (parsed) out.push(parsed)\n }\n return out\n}\n\nfunction splitCsvRow(row: string): string[] {\n const out: string[] = []\n let cur = ''\n let inQuotes = false\n for (let i = 0; i < row.length; i++) {\n const ch = row[i]!\n if (inQuotes) {\n if (ch === '\"') {\n if (row[i + 1] === '\"') {\n cur += '\"'\n i++\n } else {\n inQuotes = false\n }\n } else {\n cur += ch\n }\n } else if (ch === '\"') {\n inQuotes = true\n } else if (ch === ',') {\n out.push(cur)\n cur = ''\n } else {\n cur += ch\n }\n }\n out.push(cur)\n return out.map((f) => f.trim())\n}\n\nfunction parseRow(fields: string[]): ParsedSndsRow | null {\n const [\n ip,\n activityStart,\n activityEnd,\n rcptCommands,\n dataCommands,\n messageRecipients,\n filterResult,\n complaintRate,\n trapMessageCount,\n sampleHelo,\n sampleMailFrom,\n ] = fields\n\n const start = parseSndsDate(activityStart ?? '')\n const end = parseSndsDate(activityEnd ?? '')\n if (!ip || !start || !end) return null\n\n return {\n ip,\n activityStart: start,\n activityEnd: end,\n rcptCommands: toInt(rcptCommands),\n dataCommands: toInt(dataCommands),\n messageRecipients: toInt(messageRecipients),\n filterResult: normalizeFilter(filterResult ?? ''),\n complaintRate: parseComplaintRate(complaintRate ?? ''),\n trapMessageCount: toInt(trapMessageCount),\n sampleHelo: sampleHelo ? sampleHelo : null,\n sampleMailFrom: sampleMailFrom ? sampleMailFrom : null,\n }\n}\n\nfunction toInt(s: string | undefined): number {\n if (!s) return 0\n const n = Number(s.replace(/[^\\d-]/g, ''))\n return Number.isFinite(n) ? n : 0\n}\n\nfunction normalizeFilter(s: string): SndsFilterResult {\n const u = s.toUpperCase().trim()\n if (u === 'GREEN' || u === 'YELLOW' || u === 'RED') return u\n return 'UNKNOWN'\n}\n\n/**\n * SNDS reports complaint rate in the formats: `<0.1%`, `0.1-0.3%`, `0.3-0.5%`,\n * `0.5-1%`, `1-2%`, `2-4%`, `>4%`. We persist the upper bound as a 0-1 fraction.\n */\nexport function parseComplaintRate(s: string): number | null {\n const trimmed = s.trim()\n if (!trimmed || trimmed === '-' || /n\\/?a/i.test(trimmed)) return null\n\n const cleaned = trimmed.replace(/%/g, '')\n // `<X` → X\n let m = /^<\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `>X` → X (lower bound; treat as the floor of what they're reporting)\n m = /^>\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n // `A-B` → B\n m = /^(\\d+(?:\\.\\d+)?)\\s*-\\s*(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[2]) / 100\n // Plain number\n m = /^(\\d+(?:\\.\\d+)?)$/.exec(cleaned)\n if (m) return Number(m[1]) / 100\n return null\n}\n\n/**\n * SNDS reports dates as `M/D/YYYY h:mm AM/PM` in Microsoft's Pacific time\n * (PST/PDT) — Microsoft's own docs are silent but community testing\n * consistently shows Pacific. Convert to UTC by applying the offset that\n * was in effect at that local timestamp.\n *\n * Daylight saving in the US runs second-Sunday-of-March → first-Sunday-of-\n * November. We compute the offset based on the parsed local-Pacific\n * timestamp; a fixed -8/-7 offset would be wrong around the boundaries.\n */\nexport function parseSndsDate(s: string): Date | null {\n const trimmed = s.trim()\n if (!trimmed) return null\n const m = /^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})\\s+(\\d{1,2}):(\\d{2})(?::(\\d{2}))?\\s*(AM|PM)?$/i.exec(trimmed)\n if (m) {\n const month = Number(m[1]) - 1\n const day = Number(m[2])\n const year = Number(m[3])\n let hour = Number(m[4])\n const minute = Number(m[5])\n const second = Number(m[6] ?? 0)\n const meridiem = m[7]?.toUpperCase()\n if (meridiem === 'PM' && hour < 12) hour += 12\n if (meridiem === 'AM' && hour === 12) hour = 0\n // First place the wall-clock instant in UTC, then add the Pacific\n // offset to convert back to a real UTC moment.\n const wallMs = Date.UTC(year, month, day, hour, minute, second)\n if (!Number.isFinite(wallMs)) return null\n const offsetHours = isUsPacificDst(year, month, day) ? 7 : 8\n return new Date(wallMs + offsetHours * 60 * 60 * 1000)\n }\n // Fallback: ISO-ish strings get parsed as expected by Date.\n const d = new Date(trimmed)\n if (!isNaN(d.getTime())) return d\n return null\n}\n\n/**\n * US daylight saving runs from the second Sunday of March through the\n * first Sunday of November. Pure date math against the wall-clock day —\n * close enough for SNDS export granularity (full-day activity windows).\n */\nfunction isUsPacificDst(year: number, month0: number, day: number): boolean {\n if (month0 > 2 && month0 < 10) return true\n if (month0 < 2 || month0 > 10) return false\n // March: starts on second Sunday.\n if (month0 === 2) {\n const dst = nthSundayOfMonth(year, 2, 2)\n return day >= dst\n }\n // November: ends on first Sunday.\n const dst = nthSundayOfMonth(year, 10, 1)\n return day < dst\n}\n\nfunction nthSundayOfMonth(year: number, month0: number, n: number): number {\n const first = new Date(Date.UTC(year, month0, 1))\n const dayOfWeek = first.getUTCDay()\n const firstSunday = 1 + ((7 - dayOfWeek) % 7)\n return firstSunday + (n - 1) * 7\n}\n","/**\n * DMARC RUA aggregate report ingestion.\n *\n * - extractDmarcXml(buffer, filename) — decompresses .zip / .gz / .xml\n * - parseDmarcReport(xml) — pure RFC 7489 XML → normalized doc + failures\n * - ingestDmarcAttachment(ctx, buffer, filename) — full ingest path:\n * extract → parse → upsert into mailer_dmarc_reports + _dmarc_failures\n *\n * Designed so the same `ingestDmarcAttachment` is used by:\n * - the admin file-upload endpoint\n * - the (future) SendGrid Inbound Parse webhook\n * - the (future) IMAP poller\n * - the `mailery ingest-dmarc` CLI\n */\n\n// Heavy parsers are loaded lazily inside the functions that need them so\n// the testing bundle doesn't drag adm-zip + fast-xml-parser through.\nimport type AdmZipType from 'adm-zip'\nimport type { XMLParser as XMLParserType } from 'fast-xml-parser'\n\nimport type {\n DmarcAuthResult,\n DmarcFailureDoc,\n DmarcPolicy,\n DmarcReportDoc,\n} from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Hard cap on decompressed bytes. A real RUA aggregate report is well under\n * 1 MB; anything above this is either malformed or an attempted zip bomb.\n */\nconst MAX_DECOMPRESSED_BYTES = 50 * 1024 * 1024\n\n/**\n * Reject zip entry names that would escape the extraction directory if we\n * were writing them to disk, plus null-byte injection. We only ever read\n * the buffer in memory, but defense-in-depth keeps us safe if the storage\n * model changes.\n */\nexport function assertSafeZipEntryName(rawName: string): void {\n if (typeof rawName !== 'string' || rawName.length === 0) {\n throw new Error(`zip entry has unsafe path: <empty>`)\n }\n if (rawName.includes('\\0')) {\n throw new Error(`zip entry has unsafe path: contains null byte`)\n }\n // POSIX absolute (`/etc/passwd`) or Windows-drive (`C:\\…`) paths.\n if (rawName.startsWith('/') || rawName.startsWith('\\\\') || /^[a-zA-Z]:[\\\\/]/.test(rawName)) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n const parts = rawName.split(/[/\\\\]/)\n if (parts.some((p) => p === '..')) {\n throw new Error(`zip entry has unsafe path: ${rawName}`)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Pull DMARC XML payload(s) out of an attachment. Receivers send `.zip` or\n * `.gz` (or rarely a bare `.xml`). A multi-file zip returns each entry as a\n * separate string — concatenating them with `\\n` produces invalid XML with\n * two `<feedback>` roots.\n *\n * Defends against:\n * - decompression bombs — caps inflated bytes at MAX_DECOMPRESSED_BYTES\n * - zip-slip path traversal — rejects entries with absolute or `..` paths\n * - empty / malformed archives — throws with a useful message\n */\nexport async function extractDmarcXmls(buffer: Buffer, filename: string): Promise<string[]> {\n const lower = (filename ?? '').toLowerCase()\n const zlib = await import('node:zlib')\n\n if (lower.endsWith('.gz')) {\n const xml = await new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n let bytes = 0\n const stream = zlib.createGunzip()\n stream.on('data', (chunk: Buffer) => {\n bytes += chunk.length\n if (bytes > MAX_DECOMPRESSED_BYTES) {\n stream.destroy()\n reject(new Error(`DMARC gzip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`))\n return\n }\n chunks.push(chunk)\n })\n stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))\n stream.on('error', reject)\n stream.end(buffer)\n })\n return [xml]\n }\n\n if (lower.endsWith('.zip')) {\n const { default: AdmZip } = await import('adm-zip')\n const zip = new (AdmZip as unknown as typeof AdmZipType)(buffer)\n const entries = zip.getEntries().filter((e) => !e.isDirectory)\n if (entries.length === 0) throw new Error('zip contains no files')\n\n let total = 0\n const pieces: string[] = []\n for (const entry of entries) {\n // Zip-slip defense — adm-zip has had CVE history (CVE-2018-1002204).\n assertSafeZipEntryName(entry.entryName)\n\n // Declared size is the fast-path bail — reject before decompressing\n // when a (truthful) header already exceeds the cap. Reject entries\n // with no declared size at all (DMARC receivers always populate it).\n const declaredSize = (entry.header as any)?.size\n if (typeof declaredSize !== 'number' || declaredSize <= 0) {\n throw new Error(`zip entry ${entry.entryName} has no declared size (refusing to decompress)`)\n }\n if (declaredSize > MAX_DECOMPRESSED_BYTES || total + declaredSize > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip exceeds ${MAX_DECOMPRESSED_BYTES} bytes (decompression bomb?)`)\n }\n\n // Actual decompressed payload — defends against a forged header that\n // claims a tiny size but inflates huge. We pay the inflation cost for\n // this entry, but cap on cumulative real bytes before the next entry.\n const data = entry.getData()\n total += data.length\n if (total > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC zip decompressed payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes (forged header?)`)\n }\n // Compression-ratio sanity check only kicks in on larger entries —\n // legitimate tiny XML inflates ~64x routinely. The cumulative cap\n // above already covers the real bomb scenarios for small entries.\n if (declaredSize > 10 * 1024 && data.length > declaredSize * 64 + 1024) {\n throw new Error(`DMARC zip entry ${entry.entryName} decompressed size (${data.length}) far exceeds declared (${declaredSize})`)\n }\n pieces.push(data.toString('utf8'))\n }\n return pieces\n }\n\n // Treat as raw XML — still cap by raw buffer size.\n if (buffer.length > MAX_DECOMPRESSED_BYTES) {\n throw new Error(`DMARC payload exceeds ${MAX_DECOMPRESSED_BYTES} bytes`)\n }\n return [buffer.toString('utf8')]\n}\n\n/**\n * Convenience wrapper for callers that handle a single report.\n * @deprecated prefer `extractDmarcXmls` so multi-file zips can be parsed\n * independently. Kept temporarily; remove once all callers migrate.\n */\nexport async function extractDmarcXml(buffer: Buffer, filename: string): Promise<string> {\n const xmls = await extractDmarcXmls(buffer, filename)\n return xmls.join('\\n')\n}\n\n// ---------------------------------------------------------------------------\n// XML parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedDmarcReport {\n report: Omit<DmarcReportDoc, 'receivedAt'>\n failures: Array<Omit<DmarcFailureDoc, 'receivedAt'>>\n}\n\n/**\n * Parse RFC 7489 aggregate report XML. Tolerant — receivers vary slightly in\n * casing and field order. Throws if the XML can't be parsed at all or if\n * required identifiers (report_id, domain, date_range) are missing.\n */\nexport function parseDmarcReport(xml: string): ParsedDmarcReport {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { XMLParser } = require('fast-xml-parser') as { XMLParser: typeof XMLParserType }\n const parser = new XMLParser({\n ignoreAttributes: false,\n parseAttributeValue: false,\n parseTagValue: false,\n trimValues: true,\n // RFC 7489 specifies lowercase snake_case tag names, but some\n // less-careful receivers emit CamelCase. Normalize before lookup.\n transformTagName: (t: string) => t.toLowerCase(),\n })\n const root: any = parser.parse(xml)\n const fb = root?.feedback\n if (!fb) throw new Error('DMARC XML missing <feedback> root')\n\n const meta = fb.report_metadata ?? {}\n const policy = fb.policy_published ?? {}\n\n const reportId = String(meta.report_id ?? '').trim()\n const orgName = String(meta.org_name ?? '').trim()\n const email = String(meta.email ?? '').trim()\n const domain = String(policy.domain ?? '').trim().toLowerCase()\n const policyP = (policy.p ?? 'none') as DmarcPolicy\n const rawPct = Number(policy.pct ?? 100)\n // Use isFinite so pct=0 (legit \"monitor only\" config) survives.\n const policyPct = Number.isFinite(rawPct) ? Math.max(0, Math.min(100, rawPct)) : 100\n\n if (!reportId) throw new Error('DMARC XML missing report_id')\n if (!domain) throw new Error('DMARC XML missing policy_published.domain')\n\n const range = meta.date_range ?? {}\n const begin = secondsToDate(range.begin)\n const end = secondsToDate(range.end)\n if (!begin || !end) throw new Error('DMARC XML missing date_range')\n\n const records = toArray<any>(fb.record)\n const failures: ParsedDmarcReport['failures'] = []\n let totalMessages = 0\n let passCount = 0\n let failCount = 0\n\n // Day bucket = mid-point of the report window.\n const midMs = Math.floor((begin.getTime() + end.getTime()) / 2)\n const day = new Date(midMs).toISOString().slice(0, 10)\n\n for (const rec of records) {\n const row = rec?.row ?? {}\n const count = Number(row.count ?? 0) || 0\n totalMessages += count\n\n const evald = row.policy_evaluated ?? {}\n const dkim = (evald.dkim ?? 'none') as DmarcAuthResult\n const spf = (evald.spf ?? 'none') as DmarcAuthResult\n const aligned = dkim === 'pass' || spf === 'pass'\n\n if (aligned) {\n passCount += count\n continue\n }\n failCount += count\n\n const sourceIp = String(row.source_ip ?? '').trim()\n if (!sourceIp) continue\n const headerFrom = String(rec?.identifiers?.header_from ?? '').toLowerCase()\n const dispositionApplied = String(evald.disposition ?? 'none')\n\n failures.push({\n reportId,\n domain,\n sourceIp,\n count,\n headerFrom,\n dkimResult: dkim,\n spfResult: spf,\n dispositionApplied,\n day,\n })\n }\n\n return {\n report: {\n reportId,\n orgName,\n email,\n domain,\n policyP,\n policyPct,\n rangeStart: begin,\n rangeEnd: end,\n totalMessages,\n passCount,\n failCount,\n },\n failures,\n }\n}\n\nfunction secondsToDate(v: unknown): Date | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : Number(String(v))\n if (!Number.isFinite(n) || n <= 0) return null\n return new Date(n * 1000)\n}\n\nfunction toArray<T>(v: T | T[] | undefined | null): T[] {\n if (v === undefined || v === null) return []\n return Array.isArray(v) ? v : [v]\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport interface IngestResult {\n ok: true\n reportId: string\n domain: string\n rangeStart: Date\n rangeEnd: Date\n totalMessages: number\n passCount: number\n failCount: number\n duplicate: boolean\n}\n\n/**\n * Full ingest path: extract attachment → parse each XML payload → upsert\n * into mailer_dmarc_reports + mailer_dmarc_failures. Idempotent on\n * (reportId, orgName) — re-uploading the same report is a no-op. When the\n * attachment is a multi-file zip, each entry is parsed independently and\n * the first ingest result is returned (with `additionalReports` count).\n */\nexport async function ingestDmarcAttachment(\n ctx: RunnerContext,\n buffer: Buffer,\n filename: string,\n): Promise<IngestResult & { additionalReports?: number }> {\n const xmls = await extractDmarcXmls(buffer, filename)\n if (xmls.length === 0) throw new Error('attachment contained no XML payload')\n const results: IngestResult[] = []\n let firstError: unknown = null\n for (const xml of xmls) {\n try {\n const parsed = parseDmarcReport(xml)\n results.push(await ingestParsedDmarcReport(ctx, parsed))\n } catch (err) {\n if (!firstError) firstError = err\n // Continue ingesting siblings — one malformed report in a multi-file\n // archive shouldn't reject all valid siblings.\n }\n }\n if (results.length === 0) {\n throw firstError ?? new Error('no parseable DMARC reports in attachment')\n }\n return { ...results[0]!, additionalReports: results.length - 1 }\n}\n\nexport async function ingestParsedDmarcReport(\n ctx: RunnerContext,\n parsed: ParsedDmarcReport,\n): Promise<IngestResult> {\n const now = new Date()\n const { report, failures } = parsed\n\n // Race-safe duplicate detection — let the unique index on\n // (reportId, orgName) decide. The prior findOne→insertOne split admitted\n // a window where two concurrent uploads of the same report could both\n // succeed.\n let duplicate = false\n try {\n await ctx.collections.dmarcReports.insertOne({ ...report, receivedAt: now })\n } catch (err: any) {\n if (err?.code === 11000) {\n duplicate = true\n } else {\n throw err\n }\n }\n\n if (!duplicate && failures.length > 0) {\n // Idempotent: unique index on (reportId, sourceIp) — duplicates skipped.\n // BulkWriteError mixes real + duplicate-key errors; inspect each write\n // error and rethrow if any aren't 11000.\n try {\n await ctx.collections.dmarcFailures.insertMany(\n failures.map((f) => ({ ...f, receivedAt: now })),\n { ordered: false },\n )\n } catch (err: any) {\n const writeErrors: Array<{ code?: number }> | undefined = err?.writeErrors\n if (Array.isArray(writeErrors)) {\n const nonDup = writeErrors.find((w) => w?.code !== 11000)\n if (nonDup) throw err\n } else if (err?.code !== 11000) {\n throw err\n }\n }\n }\n\n return {\n ok: true,\n reportId: report.reportId,\n domain: report.domain,\n rangeStart: report.rangeStart,\n rangeEnd: report.rangeEnd,\n totalMessages: report.totalMessages,\n passCount: report.passCount,\n failCount: report.failCount,\n duplicate,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Retention\n// ---------------------------------------------------------------------------\n\n// Throttle DMARC prune so it doesn't fire on every tick (60s default). Once\n// per hour is plenty — failure rows live for retentionDays (default 90).\nlet _lastPruneAt = 0\nconst PRUNE_INTERVAL_MS = 60 * 60 * 1000\n\nexport async function pruneDmarcFailures(ctx: RunnerContext, opts: { force?: boolean } = {}): Promise<number> {\n const cfg = ctx.config.dmarc\n const days = cfg?.retentionDays ?? 90\n if (days <= 0) return 0\n if (!opts.force && Date.now() - _lastPruneAt < PRUNE_INTERVAL_MS) return 0\n _lastPruneAt = Date.now()\n const cutoff = new Date(Date.now() - days * 86_400_000)\n const r = await ctx.collections.dmarcFailures.deleteMany({ receivedAt: { $lt: cutoff } })\n return r.deletedCount ?? 0\n}\n\n// ---------------------------------------------------------------------------\n// Source tags — merge config-defined + db-defined\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedSourceTag {\n ip: string\n label: string\n ignored: boolean\n /** 'config' = read-only (set in MailerConfig), 'db' = mutable from UI. */\n source: 'config' | 'db'\n}\n\nexport async function resolveSourceTags(ctx: RunnerContext): Promise<Map<string, ResolvedSourceTag>> {\n const out = new Map<string, ResolvedSourceTag>()\n for (const t of ctx.config.dmarc?.knownSources ?? []) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: !!t.ignored, source: 'config' })\n }\n // DB tags override config tags so the operator can re-label without redeploy.\n const dbTags = await ctx.collections.dmarcSourceTags.find({}).toArray()\n for (const t of dbTags) {\n out.set(t.ip, { ip: t.ip, label: t.label, ignored: t.ignored, source: 'db' })\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Policy progression suggestion\n// ---------------------------------------------------------------------------\n\nexport interface DomainProgression {\n domain: string\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n /** null when no suggestion (already at strictest, or insufficient data). */\n suggested: { policy: 'none' | 'quarantine' | 'reject'; pct: number; reason: string } | null\n}\n\n/**\n * Heuristic: walk through the DMARC ramp progression.\n * p=none → suggest p=quarantine pct=10 when last 30d alignment ≥99%\n * from non-ignored sources AND ≥30 reports AND ≥1k messages\n * p=quarantine pct<100 → ramp pct (10→25→50→100) when alignment stays high\n * p=quarantine pct=100 → suggest p=reject when alignment ≥99.9% for 14+ days\n * p=reject → no suggestion (already at strictest)\n *\n * Pure function so it's easy to unit-test.\n */\nexport interface ProgressionInput {\n reports: Array<{ rangeEnd: Date; passCount: number; failCount: number }>\n failures: Array<{ sourceIp: string; count: number; receivedAt: Date }>\n knownSourceIps: Set<string>\n ignoredSourceIps: Set<string>\n currentPolicy: 'none' | 'quarantine' | 'reject' | null\n currentPct: number | null\n}\n\nexport function suggestPolicyProgression(input: ProgressionInput): DomainProgression['suggested'] {\n const { reports, failures, knownSourceIps, ignoredSourceIps, currentPolicy, currentPct } = input\n\n if (currentPolicy === 'reject') return null\n\n const since30 = Date.now() - 30 * 86_400_000\n const recentReports = reports.filter((r) => r.rangeEnd.getTime() >= since30)\n const totalMsgs = recentReports.reduce((acc, r) => acc + r.passCount + r.failCount, 0)\n const totalPass = recentReports.reduce((acc, r) => acc + r.passCount, 0)\n\n if (recentReports.length < 30) return null\n if (totalMsgs < 1000) return null\n\n // Failures from untagged (and non-ignored) sources mean we don't yet know\n // who they are — never tighten policy until they're identified.\n const untaggedFailures = failures.filter(\n (f) => f.receivedAt.getTime() >= since30 && !knownSourceIps.has(f.sourceIp) && !ignoredSourceIps.has(f.sourceIp),\n )\n if (untaggedFailures.length > 0) return null\n\n const alignmentRate = totalMsgs === 0 ? 0 : totalPass / totalMsgs\n\n if (currentPolicy === null || currentPolicy === 'none') {\n if (alignmentRate >= 0.99) {\n return {\n policy: 'quarantine',\n pct: 10,\n reason: `${(alignmentRate * 100).toFixed(2)}% alignment over ${recentReports.length} reports / ${totalMsgs.toLocaleString()} messages, all known sources tagged.`,\n }\n }\n return null\n }\n\n if (currentPolicy === 'quarantine') {\n const pct = currentPct ?? 100\n if (alignmentRate < 0.995) return null\n if (pct < 25) return { policy: 'quarantine', pct: 25, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 25.` }\n if (pct < 50) return { policy: 'quarantine', pct: 50, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 50.` }\n if (pct < 100) return { policy: 'quarantine', pct: 100, reason: `Alignment held at ${(alignmentRate * 100).toFixed(2)}% — safe to ramp pct from ${pct} to 100.` }\n\n // pct=100 + alignment ≥99.9% for 14+ days → suggest reject\n if (alignmentRate >= 0.999) {\n return { policy: 'reject', pct: 100, reason: `Alignment at ${(alignmentRate * 100).toFixed(3)}% with policy=quarantine pct=100 — safe to move to p=reject.` }\n }\n }\n\n return null\n}\n","/**\n * The mailer:tick handler. Orchestrates all the periodic work that doesn't\n * fit a delayed-job model: event-trigger scanning, recovery sweep,\n * scheduled-broadcast dispatch, outbox draining, rollups.\n */\n\nimport { processNewlyFiredEventTriggers } from './triggers.js'\nimport { processWebhookBacklog } from './webhook.js'\nimport { sweepStrandedFlowRuns } from './sweep.js'\nimport { processScheduledBroadcasts as dispatchScheduled, resumeStalledBroadcasts } from './broadcasts.js'\nimport { evaluateHealth } from './health.js'\nimport { promoteSoftBounces } from './bounce-promotion.js'\nimport { runDnsblChecks } from './dnsbl.js'\nimport { runPostmasterPull } from './postmaster.js'\nimport { runSndsPull } from './snds.js'\nimport { pruneDmarcFailures } from './dmarc.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\n/**\n * Sends that entered the 'sending' state more than this long ago are assumed\n * to have been abandoned mid-dispatch (worker crash, OOM kill, ...). The tick\n * resets them to 'queued' and re-enqueues. Providers should treat the sendId\n * (passed in messageMeta) as an idempotency key to avoid duplicate delivery on\n * the rare case where the original call did reach the provider.\n */\nconst STRANDED_SEND_THRESHOLD_MS = 5 * 60 * 1000\n\n/**\n * Webhook events older than this and still unprocessed are assumed stranded\n * (the ingest-time queue add failed). The tick drains them; fresher rows are\n * left to the webhook worker to avoid racing it in the normal path.\n */\nconst STRANDED_WEBHOOK_THRESHOLD_MS = 5 * 60 * 1000\n\nexport async function runTick(ctx: RunnerContext): Promise<void> {\n // Heartbeat: ensure the aggregate health doc exists with an up-to-date\n // `updatedAt` so the setup-status check can detect \"workers are running.\"\n // Wrapped in try/catch — a Mongo blip should never abort the whole tick.\n try {\n await ctx.collections.health.updateOne(\n { _id: HEALTH_AGG_ID },\n {\n $set: { updatedAt: new Date() },\n $setOnInsert: {\n _id: HEALTH_AGG_ID,\n senderDomain: null,\n kind: null,\n windowStartedAt: new Date(),\n windowDurationMs: ctx.config.circuitBreaker.windowMinutes * 60 * 1000,\n status: 'healthy',\n trippedAt: null,\n trippedReason: null,\n manuallyResumedAt: null,\n counters: { sent: 0, delivered: 0, bounced: 0, hardBounced: 0, softBounced: 0, complained: 0, failedToSend: 0 },\n rates: { bounceRate: 0, hardBounceRate: 0, complaintRate: 0, failureRate: 0 },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n console.error('mailery: heartbeat write failed', err)\n }\n\n // Core runners: order matters (sweep before send dispatch, drain outbox\n // before triggers re-scan, etc). Keep these serial.\n await processNewlyFiredEventTriggers(ctx).catch((err) => {\n console.error('mailery: triggers scan failed', err)\n })\n await sweepStrandedFlowRuns(ctx).catch((err) => {\n console.error('mailery: sweep failed', err)\n })\n await sweepStrandedSends(ctx).catch((err) => {\n console.error('mailery: stranded-send sweep failed', err)\n })\n await drainOutbox(ctx).catch((err) => {\n console.error('mailery: outbox drain failed', err)\n })\n await processScheduledBroadcasts(ctx).catch((err) => {\n console.error('mailery: broadcast dispatch failed', err)\n })\n await resumeStalledBroadcasts(ctx).catch((err) => {\n console.error('mailery: stalled-broadcast resume failed', err)\n })\n await evaluateHealth(ctx).catch((err) => {\n console.error('mailery: health evaluation failed', err)\n })\n await promoteSoftBounces(ctx).catch((err) => {\n console.error('mailery: soft-bounce promotion failed', err)\n })\n await processWebhookBacklog(ctx, { olderThanMs: STRANDED_WEBHOOK_THRESHOLD_MS }).catch((err) => {\n console.error('mailery: stranded-webhook drain failed', err)\n })\n\n // Independent reputation pollers + housekeeping — run in parallel so tick\n // latency is max() not sum(). Each is already throttled internally and\n // catches its own errors.\n await Promise.all([\n runDnsblChecks(ctx).catch((err) => {\n console.error('mailery: dnsbl checks failed', err)\n }),\n runPostmasterPull(ctx).catch((err) => {\n console.error('mailery: postmaster pull failed', err)\n }),\n runSndsPull(ctx).catch((err) => {\n console.error('mailery: snds pull failed', err)\n }),\n pruneDmarcFailures(ctx).catch((err) => {\n console.error('mailery: dmarc prune failed', err)\n }),\n ])\n}\n\n/**\n * Find sends stuck in 'sending' past the threshold (crashed mid-dispatch) and\n * re-enqueue them. Returning to 'queued' lets `dispatchSend` pick them back up.\n */\nasync function sweepStrandedSends(ctx: RunnerContext): Promise<void> {\n const cutoff = new Date(Date.now() - STRANDED_SEND_THRESHOLD_MS)\n const cursor = ctx.collections.sends.find(\n { status: 'sending', updatedAt: { $lt: cutoff } },\n { projection: { _id: 1 } },\n ).limit(500)\n for await (const row of cursor) {\n const reset = await ctx.collections.sends.updateOne(\n { _id: row._id, status: 'sending', updatedAt: { $lt: cutoff } },\n { $set: { status: 'queued', updatedAt: new Date() } },\n )\n if (reset.modifiedCount === 0) continue\n await ctx.queues.send.add('send', { sendId: String(row._id) }, {\n attempts: ctx.config.sendRetryAttempts,\n backoff: { type: 'exponential', delay: 60_000 },\n })\n }\n}\n\n/**\n * Pull pending outbox rows committed by host transactions and promote them\n * into the real collections (events / subscriptions / suppressions).\n */\nasync function drainOutbox(ctx: RunnerContext): Promise<void> {\n const batch = await ctx.collections.outbox\n .find({ status: 'pending' })\n .sort({ enqueuedAt: 1 })\n .limit(200)\n .toArray()\n\n for (const row of batch) {\n try {\n if (row.payload.type === 'event') {\n try {\n await ctx.collections.events.insertOne({\n externalId: row.payload.data.externalId as string,\n name: row.payload.data.name as string,\n properties: (row.payload.data.properties as Record<string, unknown>) ?? {},\n dedupeKey: row.payload.dedupeKey,\n occurredAt: (row.payload.data.occurredAt as Date | undefined) ?? new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n { $set: { status: 'processed', processedAt: new Date() } },\n )\n } catch (err: any) {\n await ctx.collections.outbox.updateOne(\n { _id: row._id },\n {\n $set: { lastAttemptAt: new Date(), lastError: String(err?.message ?? err) },\n $inc: { attempts: 1 },\n },\n )\n }\n }\n}\n\n/**\n * Claim broadcasts whose `scheduledAt` has passed and hand their recipient\n * enqueue to an advance job (inline for the noop driver), so a large\n * broadcast never blocks the tick. The dispatch itself streams the segment\n * cursor and bulk-enqueues sends, pausing when the send queue's waiting\n * count exceeds the configured cap (broadcastEnqueueMaxWaiting).\n */\nasync function processScheduledBroadcasts(ctx: RunnerContext): Promise<void> {\n await dispatchScheduled(ctx)\n}\n","/**\n * Mailer — public facade. Hosts call `Mailer.init(config)` and get an object\n * exposing the public API (fire, upsertSubscription, unsubscribe, ...) plus\n * mountable Express routers.\n *\n * See plans/10-public-api.md for the surface.\n */\n\nimport type { Db, ClientSession, ObjectId } from 'mongodb'\nimport { ObjectId as ObjectIdCtor } from 'mongodb'\n\nimport type {\n ContactAdapter,\n MailProvider,\n} from '../shared/types.js'\nimport {\n abortAllFlowsInputSchema,\n abortFlowInputSchema,\n fireInputSchema,\n registerEventSchema,\n sendOneOffInputSchema,\n suppressInputSchema,\n tagInputSchema,\n unsubscribeInputSchema,\n upsertSubscriptionSchema,\n type FireInput,\n type RegisterEventInput,\n type SendOneOffInput,\n type SuppressInput,\n type TagInput,\n type UnsubscribeInput,\n type UpsertSubscriptionInput,\n} from '../shared/schemas.js'\nimport { resolveConfig, type MailerConfig, type ResolvedConfig } from './config.js'\nimport {\n ensureIndexes,\n getCollections,\n} from './models/index.js'\nimport type { Collections } from './models/index.js'\nimport { EventRegistry } from './events.js'\nimport { sha256Hex, signDoiToken } from './tokens.js'\nimport {\n createQueueDriver,\n type QueueDriver,\n type Queues,\n} from './queues/index.js'\nimport {\n dispatchBroadcastById,\n dispatchSend,\n exitFlowRun,\n processOneRunStep,\n runTick,\n type RunnerContext,\n} from './runner/index.js'\nimport { processWebhookBacklog } from './runner/webhook.js'\n\nexport class Mailer {\n readonly db: Db\n readonly collections: Collections\n readonly adapter: ContactAdapter\n readonly providers: Record<string, MailProvider>\n readonly queues: Queues\n readonly config: ResolvedConfig\n readonly events: EventRegistry\n\n private queueDriver: QueueDriver\n private workersStarted = false\n private runnerContext: RunnerContext\n\n private constructor(args: {\n config: ResolvedConfig\n db: Db\n collections: Collections\n adapter: ContactAdapter\n providers: Record<string, MailProvider>\n queueDriver: QueueDriver\n events: EventRegistry\n }) {\n this.config = args.config\n this.db = args.db\n this.collections = args.collections\n this.adapter = args.adapter\n this.providers = args.providers\n this.queueDriver = args.queueDriver\n this.queues = args.queueDriver.queues\n this.events = args.events\n\n this.runnerContext = {\n db: this.db,\n collections: this.collections,\n adapter: this.adapter,\n varsAdapter: this.config.varsAdapter,\n providers: this.providers,\n queues: this.queues,\n config: this.config,\n handlebarsHelpers: this.config.handlebarsHelpers,\n audit: (entry) => this.audit(entry),\n }\n }\n\n /**\n * Construct a Mailer from environment variables. Reads:\n *\n * MAILER_MONGODB_URI — Mongo connection string (required)\n * MAILER_MONGODB_DB — database name (optional; defaults to the URI default)\n * MAILER_REDIS_URL — Redis connection URL (required)\n * MAILER_QUEUE_PREFIX — Redis key prefix to namespace this instance (optional)\n * MAILER_PUBLIC_URL — base for tracking/unsub URLs (required)\n * MAILER_UNSUBSCRIBE_SECRET — HMAC key (required)\n * MAILER_SENDER_ADDRESS — postal address for CAN-SPAM (optional)\n * MAILER_FROM_NAME / MAILER_FROM_EMAIL\n * MAILER_DEFAULT_PROVIDER — defaults to 'sendgrid' if SENDGRID_API_KEY is set\n * MAILER_SENDGRID_API_KEY / MAILER_SENDGRID_WEBHOOK_KEY\n * MAILER_HOST_USERS_COLLECTION (default 'users')\n * MAILER_HOST_USERS_EMAIL_FIELD (default 'email')\n * MAILER_HOST_USERS_ID_FIELD (default '_id')\n * MAILER_HOST_USERS_TAGS_FIELD\n * MAILER_HOST_USERS_TAGS_WRITABLE — '1' or 'true' to enable\n *\n * For anything beyond this (custom toContact, custom providers, hooks),\n * use the programmatic init.\n */\n static async fromEnv(): Promise<Mailer> {\n const env = process.env\n const required = (k: string) => {\n const v = env[k]\n if (!v) throw new Error(`Mailer.fromEnv: missing env var ${k}`)\n return v\n }\n\n const { MongoClient } = await import('mongodb')\n const mongoClient = await MongoClient.connect(required('MAILER_MONGODB_URI'))\n const db = env.MAILER_MONGODB_DB ? mongoClient.db(env.MAILER_MONGODB_DB) : mongoClient.db()\n\n const { MongoContactAdapter } = await import('./adapters/mongo.js')\n const adapter = new MongoContactAdapter({\n db,\n collection: env.MAILER_HOST_USERS_COLLECTION ?? 'users',\n emailField: env.MAILER_HOST_USERS_EMAIL_FIELD ?? 'email',\n idField: env.MAILER_HOST_USERS_ID_FIELD ?? '_id',\n tagsField: env.MAILER_HOST_USERS_TAGS_FIELD,\n tagsWritable:\n env.MAILER_HOST_USERS_TAGS_WRITABLE === '1' || env.MAILER_HOST_USERS_TAGS_WRITABLE === 'true',\n })\n\n const providers: Record<string, MailProvider> = {}\n if (env.MAILER_SENDGRID_API_KEY) {\n const { SendGridProvider } = await import('./providers/sendgrid.js')\n providers.sendgrid = new SendGridProvider({\n apiKey: env.MAILER_SENDGRID_API_KEY,\n webhookVerificationKey: env.MAILER_SENDGRID_WEBHOOK_KEY,\n sandbox: env.NODE_ENV !== 'production',\n })\n }\n if (Object.keys(providers).length === 0) {\n throw new Error('Mailer.fromEnv: no provider configured (set MAILER_SENDGRID_API_KEY, ...)')\n }\n\n const defaultProvider = env.MAILER_DEFAULT_PROVIDER ?? Object.keys(providers)[0]!\n\n const driverEnv = env.MAILER_QUEUE_DRIVER ?? 'bull'\n const queue =\n driverEnv === 'agenda'\n ? ({ driver: 'agenda' as const })\n : driverEnv === 'noop'\n ? ({ driver: 'noop' as const })\n : ({\n driver: 'bull' as const,\n redis: { url: required('MAILER_REDIS_URL') },\n prefix: env.MAILER_QUEUE_PREFIX,\n })\n\n return Mailer.init({\n db,\n adapter,\n queue,\n providers,\n defaultProvider,\n publicUrl: required('MAILER_PUBLIC_URL'),\n unsubscribeSecret: required('MAILER_UNSUBSCRIBE_SECRET'),\n senderAddress: env.MAILER_SENDER_ADDRESS,\n fromDefaults:\n env.MAILER_FROM_NAME && env.MAILER_FROM_EMAIL\n ? { name: env.MAILER_FROM_NAME, email: env.MAILER_FROM_EMAIL }\n : undefined,\n })\n }\n\n static async init(input: MailerConfig): Promise<Mailer> {\n const config = resolveConfig(input)\n if (!config.providers[config.defaultProvider]) {\n throw new Error(`defaultProvider \"${config.defaultProvider}\" not in providers map`)\n }\n if (config.varsAdapter) {\n const { assertNoReservedVarKeys } = await import('./adapters/vars.js')\n assertNoReservedVarKeys(config.varsAdapter)\n }\n\n const collections = getCollections(config.db, config.collectionPrefix)\n await ensureIndexes(config.db, config.collectionPrefix)\n\n const queueDriver = await createQueueDriver(config.queue, config.db)\n if (!config.workerless && config.queue.driver !== 'noop') {\n await queueDriver.scheduleRepeatingTick(config.tickIntervalSeconds)\n }\n\n return new Mailer({\n config,\n db: config.db,\n collections,\n adapter: config.adapter,\n providers: config.providers,\n queueDriver,\n events: new EventRegistry(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Event registration + firing\n // -------------------------------------------------------------------------\n\n registerEvent(reg: RegisterEventInput): void {\n const parsed = registerEventSchema.parse(reg)\n this.events.register(parsed)\n }\n\n async fire(\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(\n `fire(\"${input.eventName}\") missing dedupeKey and no policy registered. ` +\n `Call mailer.registerEvent(\"${input.eventName}\", { dedupePolicy }) or pass a key explicitly.`,\n )\n }\n try {\n await this.collections.events.insertOne({\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n dedupeKey: key,\n occurredAt: new Date(),\n createdAt: new Date(),\n })\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n // Duplicate dedupeKey — no-op by design.\n }\n }\n\n async fireFromSession(\n session: ClientSession,\n eventName: string,\n externalId: string,\n properties: Record<string, unknown> = {},\n dedupeKey?: string,\n ): Promise<void> {\n const input = fireInputSchema.parse({ eventName, externalId, properties, dedupeKey })\n const key = this.events.deriveKey(input.eventName, input.externalId, input.dedupeKey, new Date())\n if (!key) {\n throw new Error(`fireFromSession(\"${input.eventName}\") missing dedupeKey and no policy registered.`)\n }\n try {\n await this.collections.outbox.insertOne(\n {\n payload: {\n type: 'event',\n data: {\n externalId: input.externalId,\n name: input.eventName,\n properties: input.properties ?? {},\n occurredAt: new Date(),\n },\n dedupeKey: key,\n },\n status: 'pending',\n attempts: 0,\n lastAttemptAt: null,\n lastError: null,\n enqueuedAt: new Date(),\n processedAt: null,\n },\n { session },\n )\n } catch (err: any) {\n if (err?.code !== 11000) throw err\n }\n }\n\n // -------------------------------------------------------------------------\n // Subscription / unsubscribe / tags / suppression\n // -------------------------------------------------------------------------\n\n async upsertSubscription(input: UpsertSubscriptionInput): Promise<void> {\n const parsed = upsertSubscriptionSchema.parse(input)\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`adapter has no contact for externalId ${parsed.externalId}`)\n\n const status = this.config.requireDoubleOptIn ? 'pending_doi' : 'subscribed'\n const now = new Date()\n\n // Generate a DOI token up front when DOI is required. We store its hash\n // (not the raw token) on the subscription doc for audit.\n let doiToken: string | null = null\n let doiTokenHash: string | null = null\n if (status === 'pending_doi') {\n const expiresAt = new Date(now.getTime() + this.config.doiTokenLifetimeDays * 86_400_000)\n doiToken = signDoiToken({ externalId: parsed.externalId, expiresAt }, this.config.unsubscribeSecret)\n doiTokenHash = sha256Hex(doiToken)\n }\n\n await this.collections.subscriptions.updateOne(\n { externalId: parsed.externalId },\n {\n $set: {\n status,\n source: parsed.source,\n emailAtSubscribe: contact.email,\n subscribedAt: status === 'subscribed' ? (parsed.consentTimestamp ?? now) : null,\n updatedAt: now,\n ...(doiTokenHash ? { doiTokenHash, doiRequestedAt: now } : {}),\n },\n $setOnInsert: {\n externalId: parsed.externalId,\n createdAt: now,\n unsubscribedAt: null,\n unsubscribeReason: null,\n doiTokenHash: null,\n doiRequestedAt: null,\n doiConfirmedAt: null,\n doiIp: parsed.consentIp ?? null,\n doiUserAgent: parsed.consentUserAgent ?? null,\n },\n },\n { upsert: true },\n )\n\n // Send the DOI confirmation email (best-effort — failures here don't\n // unwind the subscription; the host can poll pending DOI rows + re-fire).\n if (status === 'pending_doi' && doiToken) {\n const tpl = await this.collections.templates.findOne({ slug: this.config.doiTemplateSlug })\n if (!tpl) {\n console.warn(`mailery: DOI required but template \"${this.config.doiTemplateSlug}\" not found — skipping confirmation email`)\n return\n }\n const dedupeKey = `doi:${parsed.externalId}:${now.toISOString().slice(0, 10)}`\n try {\n await this.sendOneOff({\n templateSlug: tpl.slug,\n externalId: parsed.externalId,\n vars: { confirmDoiUrl: `${this.config.publicUrl}/m/confirm-doi/${doiToken}` },\n dedupeKey,\n })\n } catch (err) {\n console.error('mailery: DOI confirmation send failed', err)\n }\n }\n }\n\n async unsubscribe(email: string, opts: Omit<UnsubscribeInput, 'email'>): Promise<void> {\n const parsed = unsubscribeInputSchema.parse({ email, ...opts })\n const normalized = parsed.email\n const now = new Date()\n\n await this.collections.suppressions.updateOne(\n { email: normalized, scope: parsed.scope },\n {\n $setOnInsert: {\n email: normalized,\n emailHash: sha256Hex(normalized),\n scope: parsed.scope,\n // mailer_suppressions canonical reason — see plans/02-data-model.md.\n reason: 'unsubscribed' as const,\n source: parsed.source,\n notes: parsed.notes ?? null,\n addedAt: now,\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n\n await this.collections.subscriptions.updateOne(\n { emailAtSubscribe: normalized },\n {\n $set: {\n status: 'unsubscribed' as const,\n unsubscribedAt: now,\n unsubscribeReason: parsed.reason,\n updatedAt: now,\n },\n },\n )\n }\n\n async suppress(email: string, opts: Omit<SuppressInput, 'email'>): Promise<void> {\n const parsed = suppressInputSchema.parse({ email, ...opts })\n await this.collections.suppressions.updateOne(\n { email: parsed.email, scope: parsed.scope },\n {\n $setOnInsert: {\n email: parsed.email,\n emailHash: sha256Hex(parsed.email),\n scope: parsed.scope,\n reason: parsed.reason,\n source: parsed.source,\n notes: parsed.notes ?? null,\n addedAt: new Date(),\n expiresAt: parsed.expiresAt ?? null,\n },\n },\n { upsert: true },\n )\n }\n\n async tag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.addTags) {\n await this.adapter.addTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.updateOne(\n { externalId: parsed.externalId, tag: parsed.tag },\n {\n $setOnInsert: {\n externalId: parsed.externalId,\n tag: parsed.tag,\n appliedBy: 'admin',\n appliedAt: new Date(),\n },\n },\n { upsert: true },\n )\n }\n }\n\n async untag(externalId: string, tag: string): Promise<void> {\n const parsed = tagInputSchema.parse({ externalId, tag })\n if (this.adapter.removeTags) {\n await this.adapter.removeTags(parsed.externalId, [parsed.tag])\n } else {\n await this.collections.contactTags.deleteOne({ externalId: parsed.externalId, tag: parsed.tag })\n }\n }\n\n // -------------------------------------------------------------------------\n // Flow abort\n // -------------------------------------------------------------------------\n\n /**\n * Abort every active run of one flow for a contact, immediately. Runs parked\n * in a `wait` exit too — their delayed wake-up jobs find the run exited and\n * no-op. Also cancels any of the flow's emails still sitting in the send\n * queue for this contact (queued or awaiting retry), so an abort means no\n * further mail, not just no further steps.\n *\n * No-op (returns zero counts) when nothing is active. Safe to call from the\n * same handler that processes the business event (\"user upgraded\").\n */\n async abortFlow(\n flowSlug: string,\n externalId: string,\n opts: { reason?: string; matchTriggerProperties?: Record<string, unknown> } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortFlowInputSchema.parse({\n flowSlug,\n externalId,\n reason: opts.reason,\n matchTriggerProperties: opts.matchTriggerProperties,\n })\n const flow = await this.collections.flows.findOne(\n { slug: parsed.flowSlug },\n { projection: { _id: 1 } },\n )\n if (!flow) throw new Error(`abortFlow: unknown flow slug \"${parsed.flowSlug}\"`)\n\n // Dotted paths so the match is against individual trigger properties; a\n // nested-object equality would demand the whole properties bag match.\n const triggerMatch = Object.fromEntries(\n Object.entries(parsed.matchTriggerProperties ?? {}).map(([k, v]) => [\n `triggerEvent.properties.${k}`,\n v,\n ]),\n )\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId, flowId: flow._id!, ...triggerMatch },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort',\n resource: { collection: 'mailer_flow_runs', slug: parsed.flowSlug },\n // Record the scope: without it a one-account abort and an abort-every-\n // run-for-this-contact are indistinguishable in the audit trail.\n diffSummary: `abortFlow slug=${parsed.flowSlug} externalId=${parsed.externalId} scope=${\n parsed.matchTriggerProperties ? JSON.stringify(parsed.matchTriggerProperties) : 'all'\n } runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n /**\n * Abort every active flow run for a contact across all flows. Same semantics\n * as `abortFlow` — for \"stop everything\" events (account deleted, churned).\n */\n async abortAllFlows(\n externalId: string,\n opts: { reason?: string } = {},\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const parsed = abortAllFlowsInputSchema.parse({ externalId, reason: opts.reason })\n\n const result = await this.abortActiveRuns(\n { externalId: parsed.externalId },\n parsed.reason ? `aborted_by_host:${parsed.reason}` : 'aborted_by_host',\n )\n if (result.abortedRuns > 0 || result.cancelledSends > 0) {\n await this.audit({\n actor: 'host',\n action: 'flow.abort_all',\n resource: { collection: 'mailer_flow_runs' },\n diffSummary: `abortAllFlows externalId=${parsed.externalId} runs=${result.abortedRuns} sends=${result.cancelledSends}${parsed.reason ? ` reason=${parsed.reason}` : ''}`,\n })\n }\n return result\n }\n\n private async abortActiveRuns(\n // Open-ended extra keys carry caller-supplied dotted paths (e.g.\n // 'triggerEvent.properties.accountId') straight into the run query.\n filter: { externalId: string; flowId?: ObjectId } & Record<string, unknown>,\n exitReason: string,\n ): Promise<{ abortedRuns: number; cancelledSends: number }> {\n const runs = await this.collections.flowRuns\n .find({ ...filter, status: 'active' })\n .toArray()\n if (runs.length === 0) return { abortedRuns: 0, cancelledSends: 0 }\n\n for (const run of runs) {\n await exitFlowRun(run, exitReason, this.runnerContext)\n }\n\n // Exiting the runs stops future steps; this stops mail already produced by\n // past send steps but not yet dispatched (provider retry backoff, tripped\n // circuit breaker, stranded-send sweep). 'failed' is included because the\n // send queue re-dispatches failed sends on retry.\n const cancelled = await this.collections.sends.updateMany(\n { flowRunId: { $in: runs.map((r) => r._id!) }, status: { $in: ['queued', 'failed'] } },\n { $set: { status: 'cancelled', errorMessage: `cancelled: ${exitReason}`, updatedAt: new Date() } },\n )\n\n return { abortedRuns: runs.length, cancelledSends: cancelled.modifiedCount }\n }\n\n /**\n * GDPR right-to-erasure. Hard-deletes the contact's PII and leaves a hashed\n * suppression row to block re-import. INVARIANT 9.\n */\n async forget(externalId: string): Promise<void> {\n const sub = await this.collections.subscriptions.findOne({ externalId })\n const email = sub?.emailAtSubscribe?.toLowerCase()\n\n const collected = await Promise.all([\n this.collections.sends.find({ externalId }).map((s) => s.emailAtSend).toArray(),\n ])\n const emails = new Set<string>()\n if (email) emails.add(email)\n for (const e of collected[0]) if (e) emails.add(e.toLowerCase())\n\n await Promise.all([\n this.collections.events.deleteMany({ externalId }),\n this.collections.flowRuns.deleteMany({ externalId }),\n this.collections.sends.deleteMany({ externalId }),\n this.collections.subscriptions.deleteMany({ externalId }),\n this.collections.contactTags.deleteMany({ externalId }),\n ])\n if (email) {\n await this.collections.leads.deleteMany({ email })\n }\n\n for (const e of emails) {\n await this.collections.suppressions.updateOne(\n { emailHash: sha256Hex(e), scope: 'all' },\n {\n $setOnInsert: {\n email: null,\n emailHash: sha256Hex(e),\n scope: 'all',\n reason: 'gdpr_forget',\n source: 'gdpr_request',\n notes: null,\n addedAt: new Date(),\n expiresAt: null,\n },\n },\n { upsert: true },\n )\n }\n\n await this.audit({\n actor: 'system:gdpr',\n action: 'gdpr.forget',\n resource: { collection: 'mailer_subscriptions', id: sub?._id },\n diffSummary: `forget externalId=${externalId}`,\n })\n }\n\n /** GDPR data export. JSON-serializable. */\n async exportContactData(externalId: string): Promise<Record<string, unknown>> {\n const subscription = await this.collections.subscriptions.findOne({ externalId })\n const [events, flowRuns, sends, suppressions, tags] = await Promise.all([\n this.collections.events.find({ externalId }).toArray(),\n this.collections.flowRuns.find({ externalId }).toArray(),\n this.collections.sends.find({ externalId }).toArray(),\n subscription?.emailAtSubscribe\n ? this.collections.suppressions.find({ email: subscription.emailAtSubscribe }).toArray()\n : Promise.resolve([]),\n this.collections.contactTags.find({ externalId }).toArray(),\n ])\n return { subscription, events, flowRuns, sends, suppressions, tags }\n }\n\n // -------------------------------------------------------------------------\n // One-off transactional send (password reset etc.)\n // -------------------------------------------------------------------------\n\n async sendOneOff(input: SendOneOffInput): Promise<{ sendId: string }> {\n const parsed = sendOneOffInputSchema.parse(input)\n const template = await this.collections.templates.findOne({ slug: parsed.templateSlug })\n if (!template) throw new Error(`template not found: ${parsed.templateSlug}`)\n\n const contact = await this.adapter.getById(parsed.externalId)\n if (!contact) throw new Error(`contact not found: ${parsed.externalId}`)\n\n const dedupeKey = `oneoff:${parsed.dedupeKey}`\n const existing = await this.collections.sends.findOne({ dedupeKey })\n if (existing) return { sendId: String(existing._id) }\n\n const providerName =\n parsed.providerOverride\n ?? template.providerOverride\n ?? (template.kind === 'transactional' ? this.config.defaultTransactionalProvider : null)\n ?? this.config.defaultProvider\n\n const sendId = new ObjectIdCtor()\n try {\n await this.collections.sends.insertOne({\n _id: sendId,\n dedupeKey,\n externalId: parsed.externalId,\n emailAtSend: contact.email,\n templateId: template._id!,\n templateSlug: template.slug,\n flowRunId: null,\n broadcastId: null,\n manualSendBy: 'sendOneOff',\n kind: template.kind,\n provider: providerName,\n providerMessageId: null,\n fromName: template.fromName,\n fromEmail: template.fromEmail,\n subject: template.subject,\n bodyHash: '',\n status: 'queued',\n errorMessage: null,\n bounceType: null,\n bounceReason: null,\n links: [],\n vars: parsed.vars ?? {},\n openedAt: null,\n openCount: 0,\n firstClickAt: null,\n clickCount: 0,\n clickedLinks: [],\n unsubscribedAt: null,\n complainedAt: null,\n queuedAt: new Date(),\n updatedAt: new Date(),\n sentAt: null,\n deliveredAt: null,\n })\n } catch (err: any) {\n // Concurrent call with the same dedupeKey won the insert — return its id.\n if (err?.code !== 11000) throw err\n const winner = await this.collections.sends.findOne({ dedupeKey })\n if (winner) return { sendId: String(winner._id) }\n throw err\n }\n\n await this.queues.send.add(\n 'send',\n { sendId: String(sendId) },\n { attempts: this.config.sendRetryAttempts, backoff: { type: 'exponential', delay: 60_000 } },\n )\n\n return { sendId: String(sendId) }\n }\n\n // -------------------------------------------------------------------------\n // Audit log helper\n // -------------------------------------------------------------------------\n\n async audit(entry: {\n actor: string\n action: string\n resource: { collection: string; id?: string | ObjectId; slug?: string }\n before?: Record<string, unknown> | null\n after?: Record<string, unknown> | null\n diffSummary?: string\n ip?: string\n userAgent?: string\n requestId?: string\n }): Promise<void> {\n await this.collections.auditLog.insertOne({\n actor: entry.actor,\n action: entry.action,\n resource: entry.resource,\n before: entry.before ?? null,\n after: entry.after ?? null,\n diffSummary: entry.diffSummary ?? null,\n ip: entry.ip ?? null,\n userAgent: entry.userAgent ?? null,\n requestId: entry.requestId ?? null,\n occurredAt: new Date(),\n })\n }\n\n // -------------------------------------------------------------------------\n // Workers\n // -------------------------------------------------------------------------\n\n async startWorkers(): Promise<void> {\n if (this.workersStarted) return\n if (this.config.queue.driver === 'noop') {\n throw new Error('startWorkers requires a non-noop queue driver')\n }\n const provider = this.providers[this.config.defaultProvider]\n const sendRate = provider?.sendRatePerSecond ?? this.config.sendRatePerSecond\n\n await this.queueDriver.startWorkers({\n concurrency: { send: this.config.sendConcurrency },\n sendRateLimit: { max: sendRate, durationMs: 1_000 },\n retryAttempts: this.config.sendRetryAttempts,\n handlers: {\n tick: async () => {\n await runTick(this.runnerContext)\n },\n advance: async (data) => {\n if (data.broadcastId) {\n if (!ObjectIdCtor.isValid(data.broadcastId)) return\n await dispatchBroadcastById(new ObjectIdCtor(data.broadcastId), this.runnerContext)\n return\n }\n if (!data.flowRunId || !ObjectIdCtor.isValid(data.flowRunId)) return\n await processOneRunStep(new ObjectIdCtor(data.flowRunId), this.runnerContext)\n },\n send: async (data) => {\n if (!ObjectIdCtor.isValid(data.sendId)) return\n await dispatchSend(new ObjectIdCtor(data.sendId), this.runnerContext)\n },\n webhook: async () => {\n await this.processWebhookBacklog()\n },\n },\n })\n this.workersStarted = true\n }\n\n /** Process unprocessed webhook events in mailer_webhook_events. */\n private async processWebhookBacklog(): Promise<void> {\n await processWebhookBacklog(this.runnerContext)\n }\n\n async stop(): Promise<void> {\n await this.queueDriver.close()\n this.workersStarted = false\n }\n\n /** Used internally by the admin router and tests; not part of the public API. */\n getRunnerContext(): RunnerContext {\n return this.runnerContext\n }\n}\n","/**\n * Public exports for the `mailery` package.\n */\n\ndeclare const __PKG_VERSION__: string | undefined\n\n/**\n * Library version, stamped from package.json at build time (tsup/vitest\n * `define`). 'dev' when the source runs without a bundler define (plain tsx).\n */\nexport const VERSION = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : 'dev'\n\n// Core\nexport { Mailer } from './mailer.js'\nexport type { MailerConfig, RedisOptions, CircuitBreakerThresholds, SenderDomainConfig, SenderDomainRegistry } from './config.js'\nexport { validateSenderDomain } from './templates/sender-domain.js'\nexport type { SenderDomainValidation } from './templates/sender-domain.js'\n\n// Adapters\nexport { MongoContactAdapter } from './adapters/mongo.js'\nexport type { MongoContactAdapterOptions } from './adapters/mongo.js'\nexport { defineVars, varsJsonSchema, RESERVED_VAR_KEYS } from './adapters/vars.js'\nexport type { VarsAdapter, VarsResolveInfo } from './adapters/vars.js'\n\n// Providers\nexport { NullProvider } from './providers/null.js'\nexport { SendGridProvider } from './providers/sendgrid.js'\nexport type { SendGridProviderOptions } from './providers/sendgrid.js'\n\n// HTTP routers\nexport { createAdminRouter } from './api/admin.js'\nexport type { AdminRouterOptions } from './api/admin.js'\nexport { createPublicRouter } from './api/public.js'\nexport type { PublicRouterOptions } from './api/public.js'\n\n// Templates (host apps may want compile + render directly for previews)\nexport {\n compileTemplate,\n compileMailyTemplate,\n derivePlaintext,\n renderTemplate,\n applyTracking,\n} from './templates/render.js'\n\n// Runner internals — exported so test harnesses and advanced hosts can drive\n// the runner inline. In production let `startWorkers()` invoke these.\nexport {\n runTick,\n processOneRunStep,\n dispatchSend,\n applyWebhookEvent,\n processNewlyFiredEventTriggers,\n sweepStrandedFlowRuns,\n} from './runner/index.js'\n\n// Models (collection helpers, in case hosts need to query directly)\nexport { getCollections, ensureIndexes } from './models/index.js'\nexport type {\n Collections,\n SubscriptionDoc,\n EventDoc,\n FlowDoc,\n FlowRunDoc,\n TemplateDoc,\n SendDoc,\n SuppressionDoc,\n BroadcastDoc,\n AuditLogDoc,\n WebhookEventDoc,\n HealthDoc,\n ContactTagDoc,\n LeadDoc,\n OutboxDoc,\n FlowVersionDoc,\n TemplateVersionDoc,\n} from './models/index.js'\n\n// Token helpers (rarely needed by hosts, useful for tests)\nexport { signUnsubscribeToken, verifyUnsubscribeToken, sha256Hex } from './tokens.js'\n\n// Shared types\nexport { computeDeliveryTime } from './runner/delivery-window.js'\n\nexport type {\n Contact,\n ContactAdapter,\n AdapterFilter,\n DeliveryWindow,\n MailProvider,\n SendArgs,\n SendResult,\n NormalizedEvent,\n FlowStep,\n Predicate,\n SegmentDefinition,\n SegmentFilter,\n} from '../shared/types.js'\n\nexport type {\n SubscriptionStatus,\n SendStatus,\n TemplateKind,\n SuppressionScope,\n SuppressionReason,\n FlowRunStatus,\n BroadcastStatus,\n HealthStatus,\n FlowGoal,\n} from '../shared/enums.js'\n\n// Option lists for tooling / admin UIs — flow step kinds, predicate kinds,\n// segment filter kinds, dedupe policies.\nexport {\n FLOW_STEP_KINDS,\n defaultFlowStep,\n PREDICATE_KINDS,\n defaultPredicate,\n predicateKind,\n SEGMENT_FILTER_KINDS,\n defaultSegmentFilter,\n DEDUPE_POLICIES,\n} from '../shared/options.js'\nexport type {\n FlowStepKindOption,\n PredicateKindOption,\n PredicateKind,\n SegmentFilterKindOption,\n SegmentFilterKind,\n DedupePolicyOption,\n} from '../shared/options.js'\n","/**\n * NullProvider — in-memory provider for tests and dev. Records every send\n * without dispatching anything. Inspect `.sent` to assert what would have\n * been delivered.\n */\n\nimport type { MailProvider, NormalizedEvent, SendArgs, SendResult } from '../../shared/types.js'\n\nlet counter = 0\n\nexport class NullProvider implements MailProvider {\n readonly name = 'null'\n readonly sendRatePerSecond = 1000\n public readonly sent: SendArgs[] = []\n\n async send(args: SendArgs): Promise<SendResult> {\n this.sent.push(args)\n return {\n providerId: `null-${Date.now()}-${++counter}`,\n status: 'accepted',\n }\n }\n\n async verifyWebhook(): Promise<boolean> {\n return true\n }\n\n parseWebhookEvents(): NormalizedEvent[] {\n return []\n }\n\n reset(): void {\n this.sent.length = 0\n }\n}\n","/**\n * Content linter for email templates. Pure function — no I/O.\n *\n * const result = lintTemplate(input, { senderDomains })\n * if (result.errors.length) refuse to publish\n *\n * The publish endpoint runs this as a gate. The editor will eventually run it\n * live for inline squiggles (PR10) — same engine, same rules.\n */\n\nimport type { TemplateKind } from '../../shared/enums.js'\nimport type { SenderDomainRegistry } from './sender-domain.js'\nimport { validateSenderDomain } from './sender-domain.js'\n\nexport type LintSeverity = 'error' | 'warning' | 'info'\n\nexport interface LintIssue {\n /** Stable rule identifier, e.g. 'missing_plain_text'. */\n rule: string\n severity: LintSeverity\n message: string\n /** Optional remediation hint shown in tooltips/expanders. */\n hint?: string\n}\n\nexport interface LintResult {\n errors: LintIssue[]\n warnings: LintIssue[]\n infos: LintIssue[]\n}\n\nexport interface LintInput {\n subject: string\n preheader: string\n /** MJML source, when authored that way. Empty string when authored via Maily. */\n mjml: string\n /**\n * Maily editor JSON source, when authored that way. Optional — passing it\n * helps rules that scan for merge tags survive HTML-encoding of braces\n * in body text.\n */\n editorJson?: unknown\n /** Rendered HTML. */\n html: string\n /** Rendered plain-text alternative. */\n plainText: string\n kind: TemplateKind\n fromEmail: string\n}\n\nexport interface LintConfig {\n senderDomains?: SenderDomainRegistry\n /**\n * JSON Schema of the host's varsAdapter (see `varsJsonSchema`). When set,\n * `{{paths}}` in subject/preheader/MJML/editorJson that don't exist in the\n * schema (or the built-in keys) are flagged as `unknown_variable` warnings.\n */\n varsJsonSchema?: Record<string, unknown> | null\n}\n\nconst URL_SHORTENERS = ['bit.ly', 't.co', 'tinyurl.com', 'goo.gl', 'ow.ly']\n\nconst SPAM_PHRASES: Array<{ pattern: RegExp; phrase: string }> = [\n { pattern: /\\bFREE\\b/, phrase: 'FREE' },\n { pattern: /\\bACT NOW\\b/i, phrase: 'ACT NOW' },\n { pattern: /\\b100%\\s+guaranteed\\b/i, phrase: '100% guaranteed' },\n]\n\nconst MARKETING_UNSUBSCRIBE_TAG = /\\{\\{\\s*unsubscribeUrl\\s*\\}\\}/\n\nexport function lintTemplate(rawInput: LintInput, config: LintConfig = {}): LintResult {\n // Coerce missing/undefined fields so downstream `.length` / `.test()`\n // calls don't throw. The publish path can hand us a draft with an\n // undefined subject, and we'd rather lint it (and emit a length warning)\n // than 500.\n const input: LintInput = {\n subject: typeof rawInput.subject === 'string' ? rawInput.subject : '',\n preheader: typeof rawInput.preheader === 'string' ? rawInput.preheader : '',\n mjml: typeof rawInput.mjml === 'string' ? rawInput.mjml : '',\n editorJson: rawInput.editorJson,\n html: typeof rawInput.html === 'string' ? rawInput.html : '',\n plainText: typeof rawInput.plainText === 'string' ? rawInput.plainText : '',\n kind: rawInput.kind === 'marketing' || rawInput.kind === 'transactional' ? rawInput.kind : 'transactional',\n fromEmail: typeof rawInput.fromEmail === 'string' ? rawInput.fromEmail : '',\n }\n const issues: LintIssue[] = []\n\n // 1. Missing plain-text alternative — error\n if (!input.plainText || input.plainText.trim().length === 0) {\n issues.push({\n rule: 'missing_plain_text',\n severity: 'error',\n message: 'Plain-text alternative is empty.',\n hint: 'Email clients and spam filters use the plain-text part. Add visible text content (MJML mj-text blocks, or text content in the Maily editor) — do not strip plain-text to empty.',\n })\n }\n\n // 2. Image-only body — error\n const imageCount = countMatches(input.html, /<img\\b/gi)\n const textLen = input.plainText.trim().length\n if (imageCount >= 1 && textLen < 20) {\n issues.push({\n rule: 'image_only_body',\n severity: 'error',\n message: 'Body is mostly images with little or no text.',\n hint: 'Image-only emails are heavily filtered as spam. Add at least one paragraph of meaningful text.',\n })\n }\n\n // 3. URL shortener — error\n const shortenerLinks = findShortenerLinks(input.html)\n if (shortenerLinks.length > 0) {\n issues.push({\n rule: 'url_shortener',\n severity: 'error',\n message: `Link uses a URL shortener: ${shortenerLinks.join(', ')}.`,\n hint: 'URL shorteners are strongly correlated with spam and are routinely blocked. Use a direct link to your domain.',\n })\n }\n\n // 4. Bare URL in body — warning\n if (hasBareUrlInVisibleText(input.html)) {\n issues.push({\n rule: 'bare_url',\n severity: 'warning',\n message: 'A URL appears in the body text without being wrapped in a link.',\n hint: 'Wrap visible URLs in an anchor tag — bare URLs look like spam template residue and reduce engagement.',\n })\n }\n\n // 5. Spammy phrases — warning (check both subject and plainText)\n const spam = findSpamSignals(`${input.subject}\\n${input.plainText}`)\n if (spam.length > 0) {\n issues.push({\n rule: 'spam_phrases',\n severity: 'warning',\n message: `Content contains spam-flagged phrases: ${spam.join(', ')}.`,\n hint: 'These phrases trigger content filters. Rephrase if possible.',\n })\n }\n\n // 6. All-caps subject — warning\n if (isAllCaps(input.subject)) {\n issues.push({\n rule: 'all_caps_subject',\n severity: 'warning',\n message: 'Subject line is mostly uppercase.',\n hint: 'All-caps subjects are flagged by spam filters and reduce click-through. Use sentence case.',\n })\n }\n\n // 7. Missing unsubscribe merge tag (marketing only) — error.\n // Check the raw mjml + editorJson + compiled HTML. @maily-to/render\n // HTML-encodes the `{{ }}` braces when they're placed in body text\n // (not in href), so checking only the rendered html misses legitimate\n // unsubscribe-tag placements.\n if (input.kind === 'marketing') {\n const sources = [input.mjml ?? '', input.html ?? '', JSON.stringify(input.editorJson ?? null)]\n const hasTag = sources.some((s) => MARKETING_UNSUBSCRIBE_TAG.test(s))\n if (!hasTag) {\n issues.push({\n rule: 'missing_unsubscribe_tag',\n severity: 'error',\n message: 'Marketing template is missing the {{unsubscribeUrl}} merge tag.',\n hint: 'CAN-SPAM, GDPR, and Gmail/Yahoo bulk-sender rules all require a working unsubscribe link. Add {{unsubscribeUrl}} somewhere in the body.',\n })\n }\n }\n\n // 8. From-domain mismatch — error (mirrors the publish-time check)\n const senderCheck = validateSenderDomain(input.fromEmail, input.kind, config.senderDomains)\n if (!senderCheck.ok) {\n issues.push({\n rule: 'sender_domain_invalid',\n severity: 'error',\n message: senderCheck.reason,\n hint: 'Edit the template fromEmail to use a domain declared for this kind in senderDomains, or update the registry.',\n })\n }\n\n // 9. Empty preheader — info\n if (!input.preheader || input.preheader.trim().length === 0) {\n issues.push({\n rule: 'empty_preheader',\n severity: 'info',\n message: 'No preheader set.',\n hint: 'The preheader shows next to the subject in most inbox previews. A good preheader lifts open rate 5-10%.',\n })\n }\n\n // 10. Subject too long — warning\n if (input.subject.length > 60) {\n issues.push({\n rule: 'subject_too_long',\n severity: 'warning',\n message: `Subject is ${input.subject.length} characters; mobile clients truncate around 60.`,\n hint: 'Front-load the important words so the truncated preview still makes sense.',\n })\n }\n\n // 11a. Unknown template variables — warning (only when a vars schema is provided)\n if (config.varsJsonSchema) {\n const sources = [input.subject, input.preheader, input.mjml, JSON.stringify(input.editorJson ?? null)]\n const unknown = findUnknownVariables(sources.join('\\n'), config.varsJsonSchema)\n if (unknown.length > 0) {\n issues.push({\n rule: 'unknown_variable',\n severity: 'warning',\n message: `Template references variable(s) not in the vars schema: ${unknown.join(', ')}.`,\n hint: 'These render as empty strings. Check for typos, or add the key to your varsAdapter schema. Paths inside {{#each}}/{{#with}} blocks are relative and not checked.',\n })\n }\n }\n\n // 11. Too many links — warning\n // Match href= with or without surrounding quotes — same shape as\n // extractHrefs above.\n const linkCount = countMatches(input.html, /<a\\s[^>]*\\bhref\\s*=/gi)\n if (linkCount > 10) {\n issues.push({\n rule: 'too_many_links',\n severity: 'warning',\n message: `${linkCount} links in body; promotional content with many links is flagged by content filters.`,\n hint: 'Consolidate calls-to-action. Aim for one primary action plus a footer link or two.',\n })\n }\n\n return splitBySeverity(issues)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction splitBySeverity(issues: LintIssue[]): LintResult {\n const out: LintResult = { errors: [], warnings: [], infos: [] }\n for (const i of issues) {\n if (i.severity === 'error') out.errors.push(i)\n else if (i.severity === 'warning') out.warnings.push(i)\n else out.infos.push(i)\n }\n return out\n}\n\nfunction countMatches(s: string, re: RegExp): number {\n return (s.match(re) ?? []).length\n}\n\nfunction findShortenerLinks(html: string): string[] {\n const hrefs = extractHrefs(html)\n const hits = new Set<string>()\n for (const href of hrefs) {\n const domain = hostnameOf(href)\n if (!domain) continue\n if (URL_SHORTENERS.includes(domain)) hits.add(domain)\n }\n return Array.from(hits)\n}\n\nfunction extractHrefs(html: string): string[] {\n const out: string[] = []\n // Match href values in any of: double-quoted, single-quoted, or\n // unquoted (terminated by space, `>`, or end of tag). Maily-generated\n // HTML mostly quotes but operator-edited MJML may not.\n const re = /<a\\s[^>]*\\bhref\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html))) {\n const href = m[1] ?? m[2] ?? m[3]\n if (href) out.push(href)\n }\n return out\n}\n\nfunction hostnameOf(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase()\n } catch {\n return null\n }\n}\n\n/**\n * Heuristic: strip anchor tags (and their contents), plus `<style>`,\n * `<script>`, and `<head>` blocks before looking for a bare URL. Otherwise\n * URLs in CSS (`@import url(...)`) or scripts trigger a false positive.\n */\nfunction hasBareUrlInVisibleText(html: string): boolean {\n const stripped = html\n .replace(/<a\\b[^>]*>.*?<\\/a>/gis, ' ')\n .replace(/<style\\b[^>]*>.*?<\\/style>/gis, ' ')\n .replace(/<script\\b[^>]*>.*?<\\/script>/gis, ' ')\n .replace(/<head\\b[^>]*>.*?<\\/head>/gis, ' ')\n return /https?:\\/\\/[^\\s<>\"']+/i.test(stripped)\n}\n\nfunction findSpamSignals(text: string): string[] {\n const out = new Set<string>()\n for (const { pattern, phrase } of SPAM_PHRASES) {\n if (pattern.test(text)) out.add(phrase)\n }\n if (/!{3,}/.test(text)) out.add('excessive \"!!!\"')\n return Array.from(out)\n}\n\n// --- unknown_variable helpers ----------------------------------------------\n\n/** Render-context keys mailery provides regardless of the host schema. */\nconst BUILTIN_VAR_ROOTS = new Set([\n 'contact',\n 'vars',\n 'event',\n 'unsubscribeUrl',\n 'viewInBrowserUrl',\n 'preferenceCenterUrl',\n 'senderAddress',\n 'this',\n])\n\nconst PATH_TOKEN = /^@?[A-Za-z_][\\w$]*(\\.[A-Za-z_][\\w$]*)*$/\n\n/**\n * Extract `{{ ... }}` expressions and return the dotted paths that cannot be\n * found in the vars JSON Schema. Conservative by design: helper arguments,\n * block-relative paths, and any schema shape we can't confidently walk are\n * treated as valid — a warning here should never be a false alarm the\n * operator has to fight.\n */\nexport function findUnknownVariables(source: string, schema: Record<string, unknown>): string[] {\n // Block helpers introduce relative scopes ({{#each topics}} → {{title}}),\n // so bare single-segment identifiers can't be validated when any exist.\n const hasBlockScopes = /\\{\\{[#^]\\s*(each|with)\\b/.test(source)\n\n const unknown = new Set<string>()\n const re = /\\{\\{\\{?\\s*([^{}]+?)\\s*\\}?\\}\\}/g\n let m: RegExpExecArray | null\n while ((m = re.exec(source))) {\n const expr = m[1]!.trim()\n if (!expr || /^[#^/>!]/.test(expr) || expr === 'else') continue // blocks, partials, comments\n if (expr.includes('(')) continue // subexpressions — too dynamic to check\n\n // Helper call: skip the helper name, validate path-shaped args.\n // Single token: validate it directly.\n const parts = expr.split(/\\s+/)\n const candidates = parts.length > 1 ? parts.slice(1) : parts\n for (const raw of candidates) {\n if (!PATH_TOKEN.test(raw)) continue // quoted strings, numbers, key=val hash args\n if (raw.startsWith('@')) continue // @index, @key, @root\n const segments = raw.split('.')\n if (BUILTIN_VAR_ROOTS.has(segments[0]!)) continue\n if (hasBlockScopes && segments.length === 1) continue // possibly block-relative\n if (!schemaHasPath(schema, segments)) unknown.add(raw)\n }\n }\n return Array.from(unknown)\n}\n\n/**\n * Walk a JSON Schema along `segments`. Returns false only when we positively\n * know the path is absent (an object node with declared properties that lacks\n * the segment and forbids extras). Unions, arrays, open objects → true.\n */\nfunction schemaHasPath(node: unknown, segments: string[]): boolean {\n if (segments.length === 0) return true\n if (!node || typeof node !== 'object') return true // can't tell — accept\n const n = node as Record<string, any>\n\n // Union shapes (zod nullable/optional/union): valid if any branch accepts.\n for (const key of ['anyOf', 'oneOf', 'allOf']) {\n if (Array.isArray(n[key])) {\n return (n[key] as unknown[]).some((branch) => schemaHasPath(branch, segments))\n }\n }\n\n if (Array.isArray(n.type) && n.type.includes('object') && !n.properties) return true\n if (n.type === 'array') {\n if (segments[0] === 'length') return true // {{topics.length}}\n return schemaHasPath(n.items, segments)\n }\n\n const props = n.properties\n if (!props || typeof props !== 'object') return true // not a closed object — accept\n\n const [head, ...rest] = segments\n if (head! in props) return schemaHasPath(props[head!], rest)\n // Segment missing — only reject when the object doesn't allow extras.\n if (n.additionalProperties === undefined || n.additionalProperties === false) return false\n return true\n}\n\nfunction isAllCaps(subject: string): boolean {\n const letters = subject.replace(/[^a-zA-Z]/g, '')\n if (letters.length < 5) return false\n const upper = subject.replace(/[^A-Z]/g, '').length\n return upper / letters.length > 0.5\n}\n","/**\n * Admin router — serves the prebuilt React SPA + REST endpoints the SPA\n * consumes. Mount inside a host Express app, gated by host auth.\n *\n * app.use('/admin/mailer', requireAdmin, createAdminRouter(mailer))\n *\n * REST routes under /api/* are documented in plans/14-admin-api.md.\n */\n\nimport express, { Router, type Request, type Response, type NextFunction } from 'express'\nimport multer from 'multer'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { ObjectId } from 'mongodb'\n\nimport type { Mailer } from '../mailer.js'\nimport {\n applyTracking,\n compileMailyTemplate,\n compileTemplate,\n renderTemplate,\n} from '../templates/render.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { lintTemplate } from '../templates/linter.js'\nimport { resolveVars, varsJsonSchema, RESERVED_VAR_KEYS } from '../adapters/vars.js'\nimport type { Contact } from '../../shared/types.js'\nimport { runSetupChecks } from './setup-status.js'\nimport { sha256Hex, signUnsubscribeToken } from '../tokens.js'\nimport { effectiveOverallStatus } from '../runner/health.js'\nimport { runDnsblChecks } from '../runner/dnsbl.js'\nimport { runPostmasterPull } from '../runner/postmaster.js'\nimport { runSndsPull } from '../runner/snds.js'\nimport { ingestDmarcAttachment, resolveSourceTags, suggestPolicyProgression } from '../runner/dmarc.js'\nimport { computeListHygiene } from '../runner/hygiene.js'\nimport {\n createMailTesterClient,\n evaluateMailTesterGate,\n findCachedScore,\n mailTesterContentKey,\n persistScore,\n type MailTesterClient,\n} from '../runner/mail-tester.js'\nimport { HEALTH_AGG_ID, healthBucketId } from '../models/index.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nfunction defaultSpaDir(): string {\n // After tsup build: dist/index.{js,cjs} + dist/admin/spa/. __dirname = dist/.\n return path.resolve(__dirname, 'admin/spa')\n}\n\nexport interface AdminRouterOptions {\n /** Override path to the built SPA. Defaults to `dist/admin/spa` shipped with the package. */\n spaDir?: string\n /** Resolve actor metadata from a Request. Defaults to `human:${req.user?.email || 'anonymous'}`. */\n getActor?: (req: Request) => string\n /**\n * Inject a Mail-Tester client (tests use a stub). When omitted, a real\n * client is created from `mailer.config.mailTester`.\n */\n mailTesterClient?: MailTesterClient\n}\n\nexport function createAdminRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const router = Router()\n const spaDir = opts.spaDir ?? defaultSpaDir()\n const getActor =\n opts.getActor ?? ((req: Request) => `human:${(req as any).user?.email ?? 'anonymous'}`)\n\n // Static assets — long cache, hashed filenames.\n router.use(\n '/_assets',\n express.static(spaDir, {\n maxAge: '1y',\n immutable: true,\n index: false,\n }),\n )\n\n // JSON body parsing for mutating endpoints.\n router.use('/api', express.json({ limit: '1mb' }))\n\n // Inject actor on every API request (read after the host's auth middleware).\n router.use('/api', (req: Request, _res, next: NextFunction) => {\n ;(req as any).actor = getActor(req)\n next()\n })\n\n router.use('/api', apiRouter(mailer, opts))\n\n // SPA shell — any other route returns index.html so client-side routing\n // doesn't 404 on refresh.\n router.get(/.*/, (_req: Request, res: Response) => {\n res.sendFile(path.join(spaDir, 'index.html'))\n })\n\n return router\n}\n\n// ---------------------------------------------------------------------------\n// JSON API\n// ---------------------------------------------------------------------------\n\nfunction apiRouter(mailer: Mailer, opts: AdminRouterOptions = {}): Router {\n const r = Router()\n const c = mailer.collections\n\n // Computed once — the vars schema is fixed for the process lifetime.\n const varsSchema = mailer.config.varsAdapter ? varsJsonSchema(mailer.config.varsAdapter) : null\n\n function getMailTesterClient(): MailTesterClient | null {\n if (opts.mailTesterClient) return opts.mailTesterClient\n const cfg = mailer.config.mailTester\n if (!cfg?.apiKey) return null\n return createMailTesterClient(cfg)\n }\n\n // Vars contract for the template editor — JSON Schema of the host's\n // varsAdapter (null when none configured) plus the mailery-provided\n // built-in keys, so autocomplete/linting have one source of truth.\n r.get(\n '/vars-schema',\n asyncHandler(async (_req, res) => {\n res.json({ schema: varsSchema, builtins: RESERVED_VAR_KEYS })\n }),\n )\n\n r.get(\n '/me',\n asyncHandler(async (req, res) => {\n const [flows, templates, broadcasts, contacts, suppressions, healthDocs] = await Promise.all([\n c.flows.estimatedDocumentCount(),\n c.templates.estimatedDocumentCount(),\n c.broadcasts.estimatedDocumentCount(),\n c.subscriptions.countDocuments({ status: 'subscribed' }),\n c.suppressions.estimatedDocumentCount(),\n c.health.find({}).limit(500).toArray(),\n ])\n res.json({\n actor: (req as any).actor,\n counts: { flows, templates, broadcasts, contacts, suppressions },\n health: { status: effectiveOverallStatus(healthDocs) },\n providers: {\n names: Object.keys(mailer.config.providers),\n default: mailer.config.defaultProvider,\n },\n broadcastConfirmationThreshold: mailer.config.broadcastConfirmationThreshold,\n })\n }),\n )\n\n // ----- Dashboard ----------------------------------------------------------\n r.get(\n '/dashboard',\n asyncHandler(async (_req, res) => {\n const now = Date.now()\n const HOUR = 60 * 60 * 1000\n const since24h = new Date(now - 24 * HOUR)\n const since48h = new Date(now - 48 * HOUR)\n\n const [\n sentTotal, deliveredCount, bouncedCount, openedCount, clickedCount,\n sentPrev, deliveredPrev, openedPrev, clickedPrev,\n hourly,\n ] = await Promise.all([\n c.sends.countDocuments({ queuedAt: { $gt: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, status: 'bounced' }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since24h }, firstClickAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, status: 'delivered' }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, openedAt: { $ne: null } }),\n c.sends.countDocuments({ queuedAt: { $gt: since48h, $lte: since24h }, firstClickAt: { $ne: null } }),\n c.sends\n .aggregate<{ _id: number; sends: number; opens: number }>([\n { $match: { queuedAt: { $gt: since24h } } },\n {\n $project: {\n hour: {\n $toInt: {\n $divide: [{ $subtract: [now, { $toLong: '$queuedAt' }] }, HOUR],\n },\n },\n opened: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] },\n },\n },\n { $group: { _id: '$hour', sends: { $sum: 1 }, opens: { $sum: '$opened' } } },\n ])\n .toArray(),\n ])\n\n const sendSeries = new Array(24).fill(0)\n const openSeries = new Array(24).fill(0)\n for (const row of hourly) {\n const idx = 23 - Math.max(0, Math.min(23, row._id))\n sendSeries[idx] = row.sends\n openSeries[idx] = row.opens\n }\n\n const delta = (cur: number, prev: number): number | null => {\n if (prev === 0) return null\n return (cur - prev) / prev\n }\n const rateDelta = (curN: number, curD: number, prevN: number, prevD: number): number | null => {\n if (prevD === 0 || curD === 0) return null\n return curN / curD - prevN / prevD\n }\n\n const healthDocs = await c.health.find({}).limit(500).toArray()\n const healthAgg = healthDocs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const recentFlowsRaw = await c.flows.find({ enabled: true }).limit(5).toArray()\n const flowStatsMap = await computeFlowStats(mailer)\n const recentFlows = recentFlowsRaw.map((f) => ({ ...f, stats: flowStatsMap.get(f.slug) ?? emptyFlowStats() }))\n const recentSends = await c.sends.find().sort({ queuedAt: -1 }).limit(6).toArray()\n const recentAudit = await c.auditLog.find().sort({ occurredAt: -1 }).limit(5).toArray()\n\n const queueCounts = await collectQueueCounts(mailer)\n const lastSendError = await c.sends\n .findOne({ status: { $in: ['bounced', 'failed'] } }, { sort: { queuedAt: -1 } })\n const lastSendOk = await c.sends\n .findOne({ status: 'delivered' }, { sort: { queuedAt: -1 } })\n const providerOk =\n lastSendOk && lastSendError\n ? new Date(lastSendOk.queuedAt as Date).getTime() >= new Date(lastSendError.queuedAt as Date).getTime()\n : lastSendOk\n ? true\n : lastSendError\n ? false\n : null\n\n res.json({\n kpis: {\n sends: { value: sentTotal, delta: delta(sentTotal, sentPrev) },\n deliveredRate: {\n value: sentTotal === 0 ? null : deliveredCount / sentTotal,\n delta: rateDelta(deliveredCount, sentTotal, deliveredPrev, sentPrev),\n bounced: bouncedCount,\n },\n openRate: {\n value: sentTotal === 0 ? null : openedCount / sentTotal,\n delta: rateDelta(openedCount, sentTotal, openedPrev, sentPrev),\n },\n clickRate: {\n value: sentTotal === 0 ? null : clickedCount / sentTotal,\n delta: rateDelta(clickedCount, sentTotal, clickedPrev, sentPrev),\n },\n },\n series: { hourly: { sends: sendSeries, opens: openSeries } },\n health: {\n status: effectiveOverallStatus(healthDocs),\n rates: healthAgg?.rates ?? null,\n thresholds: {\n hardBounceRatePctTrip: mailer.config.circuitBreaker.hardBounceRatePctTrip,\n complaintRatePctTrip: mailer.config.circuitBreaker.complaintRatePctTrip,\n combinedBounceRatePctTrip: mailer.config.circuitBreaker.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: mailer.config.circuitBreaker.failedToSendRatePctDegrade,\n },\n },\n queue: {\n inFlight: queueCounts?.inFlight ?? null,\n delayed: queueCounts?.delayed ?? null,\n providerOk,\n providerName: mailer.config.defaultProvider,\n },\n recentFlows,\n recentSends,\n recentAudit,\n })\n }),\n )\n\n // ----- Events registry ----------------------------------------------------\n r.get(\n '/events',\n asyncHandler(async (_req, res) => {\n const registered = mailer.events.list()\n const seenNames = await c.events.distinct('name')\n const known = new Set(registered.map((r) => r.name))\n const unregistered = (seenNames as string[]).filter((n) => n && !known.has(n))\n res.json({\n registered: registered.sort((a, b) => a.name.localeCompare(b.name)),\n seen: unregistered.sort(),\n })\n }),\n )\n\n // ----- Flows --------------------------------------------------------------\n r.get(\n '/flows',\n asyncHandler(async (_req, res) => {\n const flows = await c.flows.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeFlowStats(mailer)\n res.json(flows.map((f) => ({ ...f, stats: stats.get(f.slug) ?? emptyFlowStats() })))\n }),\n )\n\n r.get(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeFlowStats(mailer, flow.slug)).get(flow.slug) ?? emptyFlowStats()\n return res.json({ ...flow, stats })\n }),\n )\n\n r.post(\n '/flows/:slug/pause',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: false, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.pause',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/resume',\n asyncHandler(async (req, res) => {\n const before = await c.flows.findOne({ slug: req.params.slug })\n if (!before) return res.status(404).json({ error: 'not_found' })\n await c.flows.updateOne({ _id: before._id }, { $set: { enabled: true, updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.resume',\n resource: { collection: 'mailer_flows', id: before._id, slug: before.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates ----------------------------------------------------------\n r.get(\n '/templates',\n asyncHandler(async (_req, res) => {\n const templates = await c.templates.find().sort({ updatedAt: -1 }).toArray()\n const stats = await computeTemplateStats(mailer)\n res.json(templates.map((t) => ({ ...t, stats: stats.get(t.slug) ?? emptyTemplateStats() })))\n }),\n )\n\n r.get(\n '/templates/:slug',\n asyncHandler(async (req, res) => {\n const template = await c.templates.findOne({ slug: req.params.slug })\n if (!template) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeTemplateStats(mailer, template.slug)).get(template.slug) ?? emptyTemplateStats()\n return res.json({ ...template, stats })\n }),\n )\n\n // ----- Broadcasts ---------------------------------------------------------\n r.get(\n '/broadcasts',\n asyncHandler(async (_req, res) => {\n const broadcasts = await c.broadcasts.find().sort({ createdAt: -1 }).toArray()\n const stats = await computeBroadcastStats(mailer)\n res.json(broadcasts.map((b) => ({ ...b, stats: stats.get(String(b._id)) ?? emptyBroadcastStats() })))\n }),\n )\n\n r.get(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const broadcast = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!broadcast) return res.status(404).json({ error: 'not_found' })\n const stats = (await computeBroadcastStats(mailer, broadcast._id)).get(String(broadcast._id)) ?? emptyBroadcastStats()\n return res.json({ ...broadcast, stats })\n }),\n )\n\n // ----- Contacts -----------------------------------------------------------\n r.get(\n '/contacts',\n asyncHandler(async (req, res) => {\n const cursor = typeof req.query.cursor === 'string' ? req.query.cursor : undefined\n const limit = Math.min(Number(req.query.limit ?? 50), 200)\n const [{ contacts, nextCursor }, counts] = await Promise.all([\n mailer.adapter.query({}, { limit, cursor }),\n (async () => {\n const rows = await c.subscriptions\n .aggregate<{ _id: string; n: number }>([{ $group: { _id: '$status', n: { $sum: 1 } } }])\n .toArray()\n const out: Record<string, number> = { subscribed: 0, pending_doi: 0, unsubscribed: 0, bounced: 0, complained: 0 }\n let total = 0\n for (const r of rows) {\n if (r._id) out[r._id] = r.n\n total += r.n\n }\n return { ...out, total }\n })(),\n ])\n res.json({ contacts, nextCursor, counts })\n }),\n )\n\n r.get(\n '/contacts/:externalId',\n asyncHandler(async (req, res) => {\n const externalId = String(req.params.externalId)\n const [contact, subscription, recentEvents, recentSends, activeRuns] = await Promise.all([\n mailer.adapter.getById(externalId),\n c.subscriptions.findOne({ externalId }),\n c.events.find({ externalId }).sort({ occurredAt: -1 }).limit(50).toArray(),\n c.sends.find({ externalId }).sort({ queuedAt: -1 }).limit(50).toArray(),\n c.flowRuns.find({ externalId, status: 'active' }).sort({ nextActionAt: 1 }).limit(50).toArray(),\n ])\n if (!contact) return res.status(404).json({ error: 'not_found' })\n return res.json({ contact, subscription, recentEvents, recentSends, activeRuns })\n }),\n )\n\n // ----- Sends --------------------------------------------------------------\n r.get(\n '/sends',\n asyncHandler(async (req, res) => {\n const limit = Math.min(Number(req.query.limit ?? 100), 500)\n const status = typeof req.query.status === 'string' ? req.query.status : undefined\n const filter: any = {}\n if (status) filter.status = status\n const sends = await c.sends.find(filter).sort({ queuedAt: -1 }).limit(limit).toArray()\n res.json(sends)\n }),\n )\n\n r.get(\n '/sends/:id',\n asyncHandler(async (req, res) => {\n const id = String(req.params.id)\n if (!ObjectId.isValid(id)) return res.status(400).json({ error: 'bad_id' })\n const send = await c.sends.findOne({ _id: new ObjectId(id) })\n if (!send) return res.status(404).json({ error: 'not_found' })\n const events = send.providerMessageId\n ? await c.webhookEvents\n .find({ providerMessageId: send.providerMessageId })\n .sort({ receivedAt: -1 })\n .limit(100)\n .toArray()\n : []\n return res.json({ send, webhookEvents: events })\n }),\n )\n\n // ----- Suppressions -------------------------------------------------------\n r.get(\n '/suppressions',\n asyncHandler(async (_req, res) => {\n const rows = await c.suppressions.find().sort({ addedAt: -1 }).limit(500).toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/suppressions',\n asyncHandler(async (req, res) => {\n const { email, scope, reason, source, notes } = req.body ?? {}\n await mailer.suppress(email, { scope, reason, source, notes })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'suppression.add',\n resource: { collection: 'mailer_suppressions' },\n diffSummary: `${email} → ${scope}/${reason}`,\n })\n res.json({ ok: true })\n }),\n )\n\n // ----- Audit log ----------------------------------------------------------\n r.get(\n '/audit',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog.find().sort({ occurredAt: -1 }).limit(200).toArray()\n res.json(rows)\n }),\n )\n\n // ----- Setup status -------------------------------------------------------\n r.get(\n '/setup-status',\n asyncHandler(async (_req, res) => {\n const status = await runSetupChecks(mailer)\n res.json(status)\n }),\n )\n\n // ----- Health -------------------------------------------------------------\n r.get(\n '/health',\n asyncHandler(async (_req, res) => {\n const cb = mailer.config.circuitBreaker\n const thresholds = {\n hardBounceRatePctTrip: cb.hardBounceRatePctTrip,\n complaintRatePctTrip: cb.complaintRatePctTrip,\n combinedBounceRatePctTrip: cb.combinedBounceRatePctTrip,\n failedToSendRatePctDegrade: cb.failedToSendRatePctDegrade,\n }\n const docs = await c.health.find({}).limit(500).toArray()\n const aggregate = docs.find((d) => d._id === HEALTH_AGG_ID) ?? null\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n const overall = effectiveOverallStatus(docs)\n if (docs.length === 0) {\n // No tick has run yet. UI renders \"—\" / muted dots when status is null.\n res.json({ status: null, rates: null, counters: null, aggregate: null, buckets: [], thresholds })\n return\n }\n // Keep top-level `status` / `rates` for back-compat with consumers that\n // expect a single status (broadcast-new pre-flight, shell pill).\n res.json({\n status: overall,\n rates: aggregate?.rates ?? null,\n counters: aggregate?.counters ?? null,\n aggregate,\n buckets,\n thresholds,\n })\n }),\n )\n\n r.get(\n '/health/trips',\n asyncHandler(async (_req, res) => {\n const rows = await c.auditLog\n .find({ action: { $in: ['health.trip', 'health.resume'] } })\n .sort({ occurredAt: -1 })\n .limit(50)\n .toArray()\n res.json(rows)\n }),\n )\n\n r.post(\n '/health/resume',\n asyncHandler(async (req, res) => {\n const body = (req.body ?? {}) as { senderDomain?: string; kind?: 'marketing' | 'transactional' }\n // Half-specified body (only senderDomain or only kind) is almost\n // certainly an operator error — fail closed rather than silently\n // resume every tripped bucket.\n if ((body.senderDomain != null) !== (body.kind != null)) {\n return res.status(400).json({\n error: 'validation_failed',\n message: 'senderDomain and kind must both be provided to target a single bucket, or both omitted to resume all tripped buckets.',\n })\n }\n if (body.kind && !['marketing', 'transactional'].includes(body.kind)) {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be \"marketing\" or \"transactional\"' })\n }\n const target = body.senderDomain && body.kind\n ? { _id: healthBucketId(body.senderDomain.toLowerCase(), body.kind) }\n // Explicitly exclude the aggregate doc — it never trips, but guard\n // anyway so a future schema change can't accidentally flip its status.\n : { status: 'tripped' as const, _id: { $ne: HEALTH_AGG_ID } }\n\n const result = await c.health.updateMany(\n target,\n { $set: { status: 'healthy', manuallyResumedAt: new Date(), updatedAt: new Date() } },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'health.resume',\n resource: {\n collection: 'mailer_health',\n id: body.senderDomain && body.kind ? `${body.senderDomain}|${body.kind}` : 'all-tripped',\n },\n })\n res.json({ ok: true, resumed: result.modifiedCount })\n }),\n )\n\n // ----- DNSBL --------------------------------------------------------------\n r.get(\n '/dnsbl',\n asyncHandler(async (_req, res) => {\n const checks = await c.dnsblChecks.find({}).sort({ result: 1, target: 1, list: 1 }).limit(500).toArray()\n const latestRunAt = checks.reduce<Date | null>((acc, d) => {\n const t = new Date(d.runAt)\n return acc && acc.getTime() >= t.getTime() ? acc : t\n }, null)\n res.json({\n checks,\n latestRunAt: latestRunAt ? latestRunAt.toISOString() : null,\n intervalHours: mailer.config.dnsbl?.intervalHours ?? 24,\n })\n }),\n )\n\n r.post(\n '/dnsbl/recheck',\n asyncHandler(async (req, res) => {\n const result = await runDnsblChecks(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dnsbl.recheck',\n resource: { collection: 'mailer_dnsbl_checks' },\n diffSummary: result.ran\n ? `${result.totalChecks} checks, ${result.listedCount} listed`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Postmaster Tools ---------------------------------------------------\n r.get(\n '/postmaster',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.postmaster\n const configured = !!cfg?.clientId && !!cfg?.clientSecret && !!cfg?.refreshToken\n const all = await c.postmasterSnapshots.find({}).sort({ domain: 1, date: -1 }).limit(2000).toArray()\n // Group by domain, keep last 30 entries per domain.\n const byDomain = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byDomain.get(s.domain) ?? []\n if (arr.length < 30) arr.push(s)\n byDomain.set(s.domain, arr)\n }\n const domains = Array.from(byDomain.entries()).map(([domain, snapshots]) => ({\n domain,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n domains,\n })\n }),\n )\n\n r.post(\n '/postmaster/refresh',\n asyncHandler(async (req, res) => {\n const result = await runPostmasterPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'postmaster.refresh',\n resource: { collection: 'mailer_postmaster_snapshots' },\n diffSummary: result.ran\n ? `fetched ${result.fetched ?? 0}, tripped ${(result.trippedDomains ?? []).length}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- List Hygiene -------------------------------------------------------\n // The hygiene aggregation iterates every send doc — at scale that's\n // expensive. Cache the result for 60s and serialize concurrent requests\n // so a few rapid-fire dashboard loads can't pile up multiple full scans.\n let hygieneCache: { computedAt: number; report: Awaited<ReturnType<typeof computeListHygiene>> } | null = null\n let hygieneInFlight: Promise<Awaited<ReturnType<typeof computeListHygiene>>> | null = null\n const HYGIENE_CACHE_MS = 60_000\n\n r.get(\n '/hygiene',\n asyncHandler(async (req, res) => {\n const force = req.query.refresh === '1' || req.query.refresh === 'true'\n const now = Date.now()\n if (!force && hygieneCache && now - hygieneCache.computedAt < HYGIENE_CACHE_MS) {\n return res.json(hygieneCache.report)\n }\n if (!hygieneInFlight) {\n hygieneInFlight = (async () => {\n try {\n const report = await computeListHygiene(mailer.getRunnerContext())\n hygieneCache = { computedAt: Date.now(), report }\n return report\n } finally {\n hygieneInFlight = null\n }\n })()\n }\n const report = await hygieneInFlight\n res.json(report)\n }),\n )\n\n // ----- DMARC RUA ingestion ------------------------------------------------\n const dmarcUpload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB; reports are typically <100KB\n })\n\n r.post(\n '/dmarc/upload',\n dmarcUpload.single('file'),\n asyncHandler(async (req, res) => {\n const file = (req as any).file as Express.Multer.File | undefined\n if (!file) return res.status(400).json({ error: 'no_file', message: 'expected a \"file\" field' })\n\n try {\n const result = await ingestDmarcAttachment(mailer.getRunnerContext(), file.buffer, file.originalname)\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.ingest',\n resource: { collection: 'mailer_dmarc_reports', id: result.reportId },\n diffSummary: result.duplicate\n ? `duplicate report ${result.reportId}`\n : `ingested ${result.totalMessages} msgs (${result.passCount} pass / ${result.failCount} fail) for ${result.domain}`,\n })\n return res.json(result)\n } catch (err: any) {\n return res.status(400).json({ error: 'ingest_failed', message: String(err?.message ?? err) })\n }\n }),\n )\n\n r.get(\n '/dmarc',\n asyncHandler(async (_req, res) => {\n const ctx = mailer.getRunnerContext()\n const tagged = await resolveSourceTags(ctx)\n const reports = await c.dmarcReports.find({}).sort({ rangeEnd: -1 }).limit(200).toArray()\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n // Cap at 5k rows — busy domains can easily generate that many failure\n // rows over 30 days. We only consume these for per-domain progression\n // suggestions (untagged-source check); a partial page is fine.\n const recentFailures = await c.dmarcFailures\n .find({ receivedAt: { $gte: since30 } })\n .sort({ receivedAt: -1 })\n .limit(5000)\n .toArray()\n\n const byDomain = new Map<string, { passCount: number; failCount: number; totalMessages: number; reportCount: number; latestRangeEnd: Date | null; latestPolicy: 'none' | 'quarantine' | 'reject' | null; latestPct: number | null; reports: typeof reports }>()\n for (const r of reports) {\n const cur = byDomain.get(r.domain) ?? { passCount: 0, failCount: 0, totalMessages: 0, reportCount: 0, latestRangeEnd: null, latestPolicy: null, latestPct: null, reports: [] }\n cur.passCount += r.passCount\n cur.failCount += r.failCount\n cur.totalMessages += r.totalMessages\n cur.reportCount += 1\n const re = new Date(r.rangeEnd)\n if (!cur.latestRangeEnd || re > cur.latestRangeEnd) {\n cur.latestRangeEnd = re\n cur.latestPolicy = r.policyP\n cur.latestPct = r.policyPct\n }\n cur.reports.push(r)\n byDomain.set(r.domain, cur)\n }\n\n // Build per-day alignment series (last 14 days) per domain for sparklines.\n const since14 = Date.now() - 14 * 86_400_000\n\n const domains = Array.from(byDomain.entries()).map(([domain, s]) => {\n // Sparkline series — pass rate per day from recent reports.\n const dayTotals = new Map<string, { pass: number; total: number }>()\n for (const r of s.reports) {\n if (new Date(r.rangeEnd).getTime() < since14) continue\n const day = new Date(r.rangeEnd).toISOString().slice(0, 10)\n const d = dayTotals.get(day) ?? { pass: 0, total: 0 }\n d.pass += r.passCount\n d.total += r.passCount + r.failCount\n dayTotals.set(day, d)\n }\n const series = Array.from(dayTotals.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([day, d]) => ({ day, alignmentRate: d.total === 0 ? null : d.pass / d.total }))\n\n // Policy progression suggestion.\n const knownIps = new Set(Array.from(tagged.values()).filter((t) => !t.ignored).map((t) => t.ip))\n const ignoredIps = new Set(Array.from(tagged.values()).filter((t) => t.ignored).map((t) => t.ip))\n const suggested = suggestPolicyProgression({\n reports: s.reports.map((r) => ({ rangeEnd: new Date(r.rangeEnd), passCount: r.passCount, failCount: r.failCount })),\n failures: recentFailures.filter((f) => f.domain === domain).map((f) => ({ sourceIp: f.sourceIp, count: f.count, receivedAt: new Date(f.receivedAt) })),\n knownSourceIps: knownIps,\n ignoredSourceIps: ignoredIps,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n })\n\n return {\n domain,\n passCount: s.passCount,\n failCount: s.failCount,\n totalMessages: s.totalMessages,\n reportCount: s.reportCount,\n latestRangeEnd: s.latestRangeEnd,\n alignmentRate: s.totalMessages === 0 ? null : s.passCount / s.totalMessages,\n currentPolicy: s.latestPolicy,\n currentPct: s.latestPct,\n progression: suggested\n ? { ...suggested, current: { policy: s.latestPolicy, pct: s.latestPct } }\n : null,\n series,\n }\n })\n\n const topFailures = await c.dmarcFailures\n .aggregate<{ _id: { sourceIp: string; domain: string }; total: number; days: number; lastSeen: Date; sample: any }>([\n { $match: { receivedAt: { $gte: since30 } } },\n {\n $group: {\n _id: { sourceIp: '$sourceIp', domain: '$domain' },\n total: { $sum: '$count' },\n days: { $addToSet: '$day' },\n lastSeen: { $max: '$receivedAt' },\n sample: { $first: '$$ROOT' },\n },\n },\n { $project: { sourceIp: '$_id.sourceIp', domain: '$_id.domain', total: 1, days: { $size: '$days' }, lastSeen: 1, sample: 1 } },\n { $sort: { total: -1 } },\n { $limit: 50 },\n ])\n .toArray()\n\n const sources = topFailures.map((f) => {\n const tag = tagged.get(f._id.sourceIp)\n return {\n sourceIp: f._id.sourceIp,\n domain: f._id.domain,\n totalMessages: f.total,\n daysSeen: f.days,\n lastSeen: f.lastSeen,\n dkimResult: f.sample.dkimResult,\n spfResult: f.sample.spfResult,\n dispositionApplied: f.sample.dispositionApplied,\n label: tag?.label ?? null,\n ignored: !!tag?.ignored,\n tagSource: tag?.source ?? null,\n }\n })\n\n res.json({\n domains,\n sources,\n recentReports: reports.slice(0, 30),\n retentionDays: mailer.config.dmarc?.retentionDays ?? 90,\n })\n }),\n )\n\n // ----- DMARC source tags (mutable from UI) --------------------------------\n r.put(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const body = (req.body ?? {}) as { label?: string; ignored?: boolean }\n if (!body.label || typeof body.label !== 'string') {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const label = body.label.trim().slice(0, 200)\n if (!label) {\n return res.status(400).json({ error: 'validation_failed', message: 'label is required' })\n }\n const ignored = !!body.ignored\n await c.dmarcSourceTags.updateOne(\n { ip },\n { $set: { ip, label, ignored, setBy: (req as any).actor ?? 'unknown', setAt: new Date() } },\n { upsert: true },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.upsert',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n diffSummary: `${ip} → \"${label}\"${ignored ? ' (ignored)' : ''}`,\n })\n res.json({ ok: true })\n }),\n )\n\n r.delete(\n '/dmarc/sources/:ip',\n asyncHandler(async (req, res) => {\n const ip = String(req.params.ip ?? '')\n if (!net.isIP(ip)) {\n return res.status(400).json({ error: 'validation_failed', message: 'invalid IP' })\n }\n const result = await c.dmarcSourceTags.deleteOne({ ip })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'dmarc.source_tag.delete',\n resource: { collection: 'mailer_dmarc_source_tags', id: ip },\n })\n res.json({ ok: true, deleted: result.deletedCount })\n }),\n )\n\n // ----- Microsoft SNDS -----------------------------------------------------\n r.get(\n '/snds',\n asyncHandler(async (_req, res) => {\n const cfg = mailer.config.snds\n const configured = !!cfg?.accessKey\n const all = await c.sndsSnapshots.find({}).sort({ ip: 1, activityStart: -1 }).limit(2000).toArray()\n const byIp = new Map<string, typeof all>()\n for (const s of all) {\n const arr = byIp.get(s.ip) ?? []\n if (arr.length < 30) arr.push(s)\n byIp.set(s.ip, arr)\n }\n const ips = Array.from(byIp.entries()).map(([ip, snapshots]) => ({\n ip,\n latest: snapshots[0] ?? null,\n history: snapshots,\n }))\n res.json({\n configured,\n intervalHours: cfg?.intervalHours ?? 24,\n ips,\n })\n }),\n )\n\n r.post(\n '/snds/refresh',\n asyncHandler(async (req, res) => {\n const result = await runSndsPull(mailer.getRunnerContext(), { force: true })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'snds.refresh',\n resource: { collection: 'mailer_snds_snapshots' },\n diffSummary: result.ran\n ? `parsed ${result.rowsParsed ?? 0}, persisted ${result.rowsPersisted ?? 0}`\n : `not run: ${result.reason}`,\n })\n res.json(result)\n }),\n )\n\n // ----- Flows: create / edit / publish ------------------------------------\n r.post(\n '/flows',\n asyncHandler(async (req, res) => {\n const { slug, name, description, trigger, goal, audience } = req.body ?? {}\n if (!slug || !name || !trigger?.eventName) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, and trigger.eventName required' })\n }\n const now = new Date()\n const doc = {\n slug,\n name,\n description: description ?? '',\n trigger: { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false },\n enabled: false,\n steps: [],\n version: 0,\n draft: {\n steps: [],\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor ?? 'unknown',\n lastModifiedAt: now,\n },\n goal: goal ?? 'activation',\n audience: audience ?? '',\n expectedVolumePerWeek: null,\n stats: { activeRuns: 0, completedRuns: 0, sendsTotal: 0, sendsLast7Days: 0 },\n lastTriggerScanAt: null,\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n }\n try {\n await c.flows.insertOne(doc as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.create',\n resource: { collection: 'mailer_flows', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/flows/:slug/draft',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const { steps, notes, trigger, name, description, goal, audience } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (Array.isArray(steps)) set['draft.steps'] = steps\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (trigger?.eventName) set.trigger = { type: 'event' as const, eventName: trigger.eventName, once: trigger.once !== false }\n if (typeof name === 'string') set.name = name\n if (typeof description === 'string') set.description = description\n if (typeof goal === 'string') set.goal = goal\n if (typeof audience === 'string') set.audience = audience\n\n await c.flows.updateOne({ _id: flow._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.draft.update',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Updated draft (${steps ? `${steps.length} steps` : 'metadata only'})`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/flows/:slug/publish',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const draftSteps = flow.draft?.steps ?? flow.steps\n if (!Array.isArray(draftSteps) || draftSteps.length === 0) {\n return res.status(400).json({ error: 'empty_flow', message: 'flow has no steps to publish' })\n }\n const nextVersion = (flow.version ?? 0) + 1\n const now = new Date()\n await c.flowVersions.insertOne({\n flowId: flow._id!,\n version: nextVersion,\n steps: draftSteps,\n trigger: flow.trigger,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n await c.flows.updateOne(\n { _id: flow._id },\n {\n $set: {\n steps: draftSteps,\n version: nextVersion,\n enabled: true,\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.publish',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({ ok: true, version: nextVersion })\n }),\n )\n\n r.delete(\n '/flows/:slug',\n asyncHandler(async (req, res) => {\n const flow = await c.flows.findOne({ slug: req.params.slug })\n if (!flow) return res.status(404).json({ error: 'not_found' })\n const everRan = await c.flowRuns.countDocuments({ flowId: flow._id }, { limit: 1 })\n if (everRan > 0) return res.status(409).json({ error: 'has_runs', message: 'flow has runs — pause it instead' })\n await c.flows.deleteOne({ _id: flow._id })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'flow.delete',\n resource: { collection: 'mailer_flows', id: flow._id, slug: flow.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Templates: create / edit / publish --------------------------------\n r.post(\n '/templates',\n asyncHandler(async (req, res) => {\n const { slug, name, kind, subject, preheader, fromName, fromEmail } = req.body ?? {}\n if (!slug || !name || !kind) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, kind required' })\n }\n if (kind !== 'marketing' && kind !== 'transactional') {\n return res.status(400).json({ error: 'validation_failed', message: 'kind must be marketing or transactional' })\n }\n const resolvedFromEmail =\n fromEmail ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.email : undefined) ??\n mailer.config.fromDefaults?.email ??\n 'noreply@example.com'\n const senderCheck = validateSenderDomain(resolvedFromEmail, kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n const now = new Date()\n try {\n await c.templates.insertOne({\n slug,\n name,\n description: '',\n kind,\n fromName:\n fromName ??\n (kind === 'transactional' ? mailer.config.transactionalFromDefaults?.name : undefined) ??\n mailer.config.fromDefaults?.name ??\n 'Mailery',\n fromEmail: resolvedFromEmail,\n replyTo: null,\n providerOverride: null,\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n body: { mjml: '', editorJson: null, html: '', plainText: '', compiledAt: null },\n variablesSchema: {},\n draft: {\n subject: subject ?? `Untitled — ${name}`,\n preheader: preheader ?? '',\n mjml: '',\n editorJson: null,\n notes: 'Initial draft',\n lastModifiedBy: (req as any).actor,\n lastModifiedAt: now,\n },\n tags: [],\n trackOpens: kind === 'marketing',\n trackClicks: kind === 'marketing',\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0, lastSentAt: null },\n publishedAt: null,\n publishedBy: null,\n createdAt: now,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.create',\n resource: { collection: 'mailer_templates', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/templates/:slug/draft',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const { subject, preheader, mjml, editorJson, notes, name, fromName, fromEmail, replyTo, kind, trackOpens, trackClicks } = req.body ?? {}\n\n const set: Record<string, unknown> = {\n 'draft.lastModifiedBy': (req as any).actor,\n 'draft.lastModifiedAt': new Date(),\n updatedAt: new Date(),\n }\n if (typeof subject === 'string') set['draft.subject'] = subject\n if (typeof preheader === 'string') set['draft.preheader'] = preheader\n if (typeof mjml === 'string') set['draft.mjml'] = mjml\n if (editorJson !== undefined) set['draft.editorJson'] = editorJson\n if (typeof notes === 'string') set['draft.notes'] = notes\n if (typeof name === 'string') set.name = name\n if (typeof fromName === 'string') set.fromName = fromName\n if (typeof fromEmail === 'string') set.fromEmail = fromEmail\n if (typeof replyTo === 'string' || replyTo === null) set.replyTo = replyTo\n if (kind === 'marketing' || kind === 'transactional') set.kind = kind\n\n // Validate resulting (kind, fromEmail) against the senderDomains registry\n // whenever either field is being touched.\n if (typeof fromEmail === 'string' || kind === 'marketing' || kind === 'transactional') {\n const resultingKind = (set.kind as typeof tpl.kind) ?? tpl.kind\n const resultingFromEmail = (set.fromEmail as string) ?? tpl.fromEmail\n const senderCheck = validateSenderDomain(resultingFromEmail, resultingKind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n }\n if (typeof trackOpens === 'boolean') set.trackOpens = trackOpens\n if (typeof trackClicks === 'boolean') set.trackClicks = trackClicks\n\n await c.templates.updateOne({ _id: tpl._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.draft.update',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // ----- Mail-Tester deliverability check ----------------------------------\n r.get(\n '/templates/:slug/mail-tester',\n asyncHandler(async (req, res) => {\n const cfg = mailer.config.mailTester\n const configured = !!cfg?.apiKey\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Cache key must reflect the same fingerprint the check + publish gate\n // use — render the *current* draft if there is one, otherwise the\n // most recent published body. Previously this mixed draft.subject\n // with published body.html, which always missed pre-first-publish\n // and drifted whenever a subject edit followed a publish.\n let bodyHash = ''\n let subject = tpl.subject ?? ''\n if (tpl.draft) {\n try {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : tpl.draft.mjml\n ? await compileTemplate(tpl.draft.mjml)\n : null\n if (compiled) {\n bodyHash = sha256Hex(compiled.html)\n subject = tpl.draft.subject || subject\n }\n } catch {\n // If the draft no longer compiles, fall back to the published body.\n }\n }\n if (!bodyHash && tpl.body?.html) {\n bodyHash = sha256Hex(tpl.body.html)\n }\n const key = bodyHash ? mailTesterContentKey({ bodyHash, subject, fromEmail: tpl.fromEmail }) : null\n const cached = key ? await findCachedScore(mailer.getRunnerContext(), key) : null\n\n res.json({\n configured,\n minScore: cfg?.minScore ?? 8.0,\n requireScore: !!cfg?.requireScore,\n cacheHours: cfg?.cacheHours ?? 24,\n score: cached,\n })\n }),\n )\n\n r.post(\n '/templates/:slug/mail-tester-check',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) {\n return res.status(400).json({\n error: 'not_configured',\n message: 'Mail-Tester is not configured. Set mailer.config.mailTester.apiKey to enable.',\n })\n }\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Save a draft before running a deliverability check.' })\n\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n\n const bodyHash = sha256Hex(compiled.html)\n const contentKey = mailTesterContentKey({ bodyHash, subject: draft.subject, fromEmail: tpl.fromEmail })\n const ctx = mailer.getRunnerContext()\n\n // Cache hit — return without burning a credit.\n const cached = await findCachedScore(ctx, contentKey)\n if (cached) {\n return res.json({ cached: true, status: 'ready', score: cached })\n }\n\n // Provision a new test address and send the rendered draft to it.\n const { checkId, emailAddress } = await client.provisionCheck()\n const provider = mailer.providers[tpl.providerOverride ?? mailer.config.defaultProvider]\n if (!provider) {\n return res.status(500).json({ error: 'provider_unknown', message: `default provider ${mailer.config.defaultProvider} is not registered` })\n }\n\n try {\n await provider.send({\n to: emailAddress,\n fromName: tpl.fromName,\n fromEmail: tpl.fromEmail,\n replyTo: tpl.replyTo ?? undefined,\n subject: draft.subject,\n html: compiled.html,\n text: compiled.plainText,\n headers: {},\n messageMeta: { mailTesterCheckId: checkId },\n })\n } catch (err: any) {\n return res.status(502).json({ error: 'send_failed', message: String(err?.message ?? err) })\n }\n\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.start',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Sent draft to ${emailAddress} for Mail-Tester check ${checkId}`,\n })\n\n res.json({\n cached: false,\n status: 'pending',\n checkId,\n contentKey,\n message: 'Test email sent. Poll /mail-tester-result?checkId=...&contentKey=... for the score.',\n })\n }),\n )\n\n r.get(\n '/templates/:slug/mail-tester-result',\n asyncHandler(async (req, res) => {\n const client = getMailTesterClient()\n if (!client) return res.status(400).json({ error: 'not_configured' })\n\n const checkId = String(req.query.checkId ?? '')\n if (!checkId) return res.status(400).json({ error: 'validation_failed', message: 'checkId is required' })\n\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft', message: 'Draft no longer exists.' })\n\n // Re-derive the content key server-side from the current draft so an\n // attacker can't land a score under an arbitrary fingerprint and game\n // the publish gate. We must recompile to recompute bodyHash.\n let compiled: { html: string; plainText: string }\n try {\n if (draft.editorJson) compiled = await compileMailyTemplate(draft.editorJson)\n else if (draft.mjml) compiled = await compileTemplate(draft.mjml)\n else return res.status(400).json({ error: 'empty_draft' })\n } catch (err: any) {\n return res.status(400).json({ error: 'compile_failed', message: String(err?.message ?? err) })\n }\n const contentKey = mailTesterContentKey({\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n\n const result = await client.fetchResult(checkId)\n if (!result.ready) {\n return res.json({ status: 'pending', score: null })\n }\n\n const ctx = mailer.getRunnerContext()\n const persisted = await persistScore(ctx, { templateSlug: tpl.slug, contentKey, checkId, result })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'mail_tester.check.complete',\n resource: { collection: 'mailer_mail_tester_scores', id: contentKey, slug: tpl.slug },\n diffSummary: `Score ${result.score.toFixed(1)}`,\n })\n res.json({ status: 'ready', score: persisted })\n }),\n )\n\n r.post(\n '/templates/:slug/lint',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Lint against the supplied draft if present, otherwise the saved draft,\n // otherwise the last-published body. Keep this tolerant so the editor\n // can call it without juggling round-trips.\n const body = (req.body ?? {}) as {\n subject?: string\n preheader?: string\n mjml?: string\n editorJson?: Record<string, unknown> | null\n fromEmail?: string\n kind?: 'marketing' | 'transactional'\n }\n\n const subject = body.subject ?? tpl.draft?.subject ?? tpl.subject ?? ''\n const preheader = body.preheader ?? tpl.draft?.preheader ?? tpl.preheader ?? ''\n const mjml = body.mjml ?? tpl.draft?.mjml ?? tpl.body?.mjml ?? ''\n const editorJson = body.editorJson !== undefined ? body.editorJson : (tpl.draft?.editorJson ?? tpl.body?.editorJson ?? null)\n const fromEmail = body.fromEmail ?? tpl.fromEmail\n // Whitelist kind — otherwise body.kind:'foo' bypasses the marketing-\n // only missing_unsubscribe_tag check by hitting neither branch.\n const kind = body.kind === 'marketing' || body.kind === 'transactional' ? body.kind : tpl.kind\n\n let html = ''\n let plainText = ''\n try {\n if (editorJson) {\n const compiled = await compileMailyTemplate(editorJson)\n html = compiled.html\n plainText = compiled.plainText\n } else if (mjml) {\n const compiled = await compileTemplate(mjml)\n html = compiled.html\n plainText = compiled.plainText\n }\n } catch (err: any) {\n return res.status(200).json({\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n compileFailed: true,\n })\n }\n\n // Script-seeded templates can have no draft source at all (body.html +\n // body.plainText inserted directly, editorJson/mjml empty). Fall back to\n // the stored body so lint judges what actually sends instead of\n // reporting an empty template.\n if (!html && typeof tpl.body?.html === 'string') html = tpl.body.html\n if (!plainText && typeof tpl.body?.plainText === 'string') plainText = tpl.body.plainText\n\n const lint = lintTemplate(\n { subject, preheader, mjml, editorJson, html, plainText, kind, fromEmail },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n res.json({ ...lint, compileFailed: false })\n }),\n )\n\n r.post(\n '/templates/:slug/publish',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n const draft = tpl.draft\n if (!draft) return res.status(400).json({ error: 'no_draft' })\n\n // Short-circuit sender-domain check — preserves the pre-linter 400\n // sender_domain_invalid contract so external callers (and the SPA's\n // own publish modal) can key on it without conflating with lint errors.\n const senderCheck = validateSenderDomain(tpl.fromEmail, tpl.kind, mailer.config.senderDomains)\n if (!senderCheck.ok) {\n return res.status(400).json({\n error: 'sender_domain_invalid',\n code: senderCheck.code,\n message: senderCheck.reason,\n })\n }\n\n let compiled: { html: string; plainText: string; errors: any[] }\n try {\n if (draft.editorJson) {\n compiled = await compileMailyTemplate(draft.editorJson)\n } else if (draft.mjml) {\n compiled = await compileTemplate(draft.mjml)\n } else {\n return res.status(400).json({ error: 'empty_draft', message: 'draft has no MJML or editorJson content' })\n }\n } catch (err: any) {\n // Same shape as the lint endpoint's compileFailed branch so the UI\n // can surface compile errors uniformly with lint errors.\n return res.status(422).json({\n error: 'compile_failed',\n message: String(err?.message ?? err),\n lint: {\n errors: [{ rule: 'compile_failed', severity: 'error', message: `Compile error: ${String(err?.message ?? err)}` }],\n warnings: [],\n infos: [],\n },\n })\n }\n\n const lint = lintTemplate(\n {\n subject: draft.subject,\n preheader: draft.preheader,\n mjml: draft.mjml ?? '',\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n kind: tpl.kind,\n fromEmail: tpl.fromEmail,\n },\n { senderDomains: mailer.config.senderDomains, varsJsonSchema: varsSchema },\n )\n\n if (lint.errors.length > 0) {\n return res.status(422).json({\n error: 'lint_failed',\n message: `Template publish blocked by ${lint.errors.length} content issue(s).`,\n lint,\n })\n }\n\n // Mail-Tester gate. Blocks when a cached score for this exact content is\n // below minScore, and — when `requireScore` is configured — when no score\n // for this content exists at all. Operator can override either with\n // `bypassMailTester: true` in the request body.\n const bypass = Boolean(req.body?.bypassMailTester)\n if (!bypass) {\n const gate = await evaluateMailTesterGate(mailer.getRunnerContext(), {\n bodyHash: sha256Hex(compiled.html),\n subject: draft.subject,\n fromEmail: tpl.fromEmail,\n })\n if (!gate.allowed) {\n return res.status(422).json({\n error: 'mail_tester_blocked',\n code: gate.code,\n message: gate.reason,\n score: gate.score,\n hint:\n gate.code === 'no_score'\n ? 'POST to `/templates/:slug/mail-tester-check`, poll `/mail-tester-result`, then publish — or POST `bypassMailTester: true` to publish anyway.'\n : 'Re-run the deliverability check after fixing the feedback, or POST `bypassMailTester: true` to publish anyway.',\n })\n }\n }\n\n const now = new Date()\n const nextVersion = await c.templateVersions.countDocuments({ templateId: tpl._id }) + 1\n await c.templateVersions.insertOne({\n templateId: tpl._id!,\n version: nextVersion,\n mjml: draft.mjml,\n html: compiled.html,\n plainText: compiled.plainText,\n subject: draft.subject,\n preheader: draft.preheader,\n publishedAt: now,\n publishedBy: (req as any).actor,\n })\n\n await c.templates.updateOne(\n { _id: tpl._id },\n {\n $set: {\n subject: draft.subject,\n preheader: draft.preheader,\n body: {\n mjml: draft.mjml,\n editorJson: draft.editorJson,\n html: compiled.html,\n plainText: compiled.plainText,\n compiledAt: now,\n },\n draft: null,\n publishedAt: now,\n publishedBy: (req as any).actor,\n updatedAt: now,\n },\n },\n )\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.publish',\n resource: { collection: 'mailer_templates', id: tpl._id, slug: tpl.slug },\n diffSummary: `Published v${nextVersion}`,\n })\n return res.json({\n ok: true,\n version: nextVersion,\n warnings: compiled.errors,\n lint, // warnings + infos for UI\n })\n }),\n )\n\n r.post(\n '/templates/:slug/preview',\n asyncHandler(async (req, res) => {\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n const useDraft = req.body?.useDraft !== false\n let html = ''\n let plainText = ''\n if (useDraft && tpl.draft) {\n const compiled = tpl.draft.editorJson\n ? await compileMailyTemplate(tpl.draft.editorJson)\n : await compileTemplate(tpl.draft.mjml || '<mjml><mj-body></mj-body></mjml>')\n html = compiled.html\n plainText = compiled.plainText\n } else {\n if (!tpl.body?.html) {\n return res.status(409).json({ error: 'not_published', message: 'Template has not been published yet.' })\n }\n html = tpl.body.html\n plainText = tpl.body.plainText\n }\n\n // Preview as a real contact when contactId is given — pulls the actual\n // contact through the adapter and runs the host's varsAdapter, so the\n // preview shows exactly what that person would receive.\n let contact: Contact\n const contactId = typeof req.body?.contactId === 'string' ? req.body.contactId : null\n if (contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = found\n } else {\n contact = req.body?.sampleContact ?? {\n externalId: 'preview-contact',\n email: 'preview@example.com',\n tags: [],\n fields: { firstName: 'Alex' },\n }\n }\n\n // Optional simulated trigger-event properties, so account/topic-scoped\n // templates ({{event.*}} or resolver branching) preview realistically.\n const eventProperties =\n req.body?.eventProperties && typeof req.body.eventProperties === 'object'\n ? (req.body.eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'preview',\n templateSlug: tpl.slug,\n eventProperties,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: req.body?.vars ?? {},\n event: eventProperties ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/preview`,\n senderAddress: mailer.config.senderAddress,\n }\n\n const previewTpl = { ...tpl, body: { ...tpl.body, html, plainText } }\n const rendered = await renderTemplate(previewTpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n return res.json({\n subject: rendered.subject,\n preheader: rendered.preheader,\n html: rendered.html,\n plainText: rendered.plainText,\n contact: { externalId: contact.externalId, email: contact.email },\n })\n }),\n )\n\n r.post(\n '/templates/:slug/send-test',\n asyncHandler(async (req, res) => {\n const { to, sampleData, contactId, eventProperties } = req.body ?? {}\n if (!to) return res.status(400).json({ error: 'to_required' })\n const tpl = await c.templates.findOne({ slug: req.params.slug })\n if (!tpl) return res.status(404).json({ error: 'not_found' })\n\n // Render as a real contact when contactId is given (vars included),\n // but always deliver to the operator-typed address.\n let contact: Contact\n if (typeof contactId === 'string' && contactId) {\n const found = await mailer.adapter.getById(contactId)\n if (!found) return res.status(404).json({ error: 'contact_not_found', contactId })\n contact = { ...found, email: to }\n } else {\n contact = sampleData?.contact ?? {\n externalId: 'test-recipient',\n email: to,\n tags: [],\n fields: { firstName: 'Test' },\n }\n contact.email = to\n }\n\n const evProps =\n eventProperties && typeof eventProperties === 'object'\n ? (eventProperties as Record<string, unknown>)\n : undefined\n\n let resolved: Record<string, unknown> = {}\n try {\n resolved = await resolveVars(mailer.config.varsAdapter, contact, {\n reason: 'test',\n templateSlug: tpl.slug,\n eventProperties: evProps,\n })\n } catch (err: any) {\n return res.status(502).json({\n error: 'vars_resolve_failed',\n message: `varsAdapter.resolve threw: ${String(err?.message ?? err)}`,\n })\n }\n\n const renderCtx = {\n ...resolved,\n contact,\n vars: sampleData?.vars ?? {},\n event: evProps ?? {},\n unsubscribeUrl: `${mailer.config.publicUrl}/m/unsub/test`,\n senderAddress: mailer.config.senderAddress,\n }\n const rendered = await renderTemplate(tpl as any, renderCtx, { helpers: mailer.config.handlebarsHelpers })\n const tracking = applyTracking(rendered.html, {\n sendId: `test-${Date.now()}`,\n publicUrl: mailer.config.publicUrl,\n trackOpens: false,\n trackClicks: false,\n })\n\n const provider = mailer.providers[tpl.providerOverride ?? mailer.config.defaultProvider]!\n const result = await provider.send({\n to,\n fromName: rendered.fromName,\n fromEmail: rendered.fromEmail,\n subject: `[TEST] ${rendered.subject}`,\n html: tracking.html,\n text: rendered.plainText,\n })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'template.send-test',\n resource: { collection: 'mailer_templates', slug: tpl.slug },\n diffSummary: `to=${to}`,\n })\n // Avoid unused — sign helper is exposed for future preview routes.\n void signUnsubscribeToken\n return res.json({ ok: true, providerId: result.providerId })\n }),\n )\n\n // ----- Broadcasts: create / patch / schedule / cancel --------------------\n r.post(\n '/broadcasts',\n asyncHandler(async (req, res) => {\n const { slug, name, templateSlug, segmentDefinition } = req.body ?? {}\n if (!slug || !name || !templateSlug) {\n return res.status(400).json({ error: 'validation_failed', message: 'slug, name, templateSlug required' })\n }\n const now = new Date()\n try {\n await c.broadcasts.insertOne({\n slug,\n name,\n templateSlug,\n segmentDefinition: segmentDefinition ?? { filters: [{ kind: 'subscriptionStatus', equals: 'subscribed' }] },\n status: 'draft',\n scheduledAt: null,\n startedAt: null,\n completedAt: null,\n confirmationRequired: true,\n confirmedCount: null,\n confirmedAt: null,\n confirmedBy: null,\n recipientCount: null,\n stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0 },\n createdAt: now,\n createdBy: (req as any).actor,\n updatedAt: now,\n } as any)\n } catch (err: any) {\n if (err?.code === 11000) return res.status(409).json({ error: 'slug_taken' })\n throw err\n }\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.create',\n resource: { collection: 'mailer_broadcasts', slug },\n })\n return res.json({ ok: true, slug })\n }),\n )\n\n r.patch(\n '/broadcasts/:slug',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { name, templateSlug, segmentDefinition } = req.body ?? {}\n const set: Record<string, unknown> = { updatedAt: new Date() }\n if (typeof name === 'string') set.name = name\n if (typeof templateSlug === 'string') set.templateSlug = templateSlug\n if (segmentDefinition) set.segmentDefinition = segmentDefinition\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/segment/count',\n asyncHandler(async (req, res) => {\n const segmentDefinition = req.body?.segmentDefinition\n if (!segmentDefinition?.filters) return res.status(400).json({ error: 'segment_required' })\n const t0 = Date.now()\n // V1: only host-side filter translation. Mailer-side filters\n // (subscription status, fired events, etc.) and the suppression check\n // are applied at dispatch time over the streamed cursor, so the live\n // counter would have to scan-and-filter the full audience to be\n // precise. We return the upper-bound count and tell the UI it's an\n // estimate. When richer estimation lands, swap this for a sampled\n // pass that includes mailer-side filters + suppression.\n const hostFilter: any = {}\n for (const f of segmentDefinition.filters) {\n if (f.kind === 'hasTag') hostFilter.hasTag = f.tag\n if (f.kind === 'fieldEquals') hostFilter.fieldEquals = { field: f.field, value: f.value }\n }\n const hasMailerFilters = segmentDefinition.filters.some((f: any) =>\n ['subscriptionStatus', 'firedEvent', 'notFiredEvent', 'notHasTag', 'opened', 'notOpened', 'subscribedAfter', 'subscribedBefore'].includes(f.kind),\n )\n const upperBound = await mailer.adapter.count(hostFilter)\n return res.json({\n upperBound,\n approximate: hasMailerFilters,\n computedMs: Date.now() - t0,\n })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/schedule',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n if (b.status !== 'draft') return res.status(409).json({ error: 'not_draft' })\n const { scheduledAt, confirmedCount, respectRecipientTimezone } = req.body ?? {}\n if (!scheduledAt) return res.status(400).json({ error: 'scheduledAt_required' })\n const scheduled = new Date(scheduledAt)\n if (Number.isNaN(scheduled.getTime())) return res.status(400).json({ error: 'bad_scheduledAt' })\n\n const threshold = mailer.config.broadcastConfirmationThreshold\n if (typeof confirmedCount !== 'number') {\n return res.status(400).json({ error: 'confirmedCount_required' })\n }\n\n const set: Record<string, unknown> = {\n status: 'scheduled',\n scheduledAt: scheduled,\n confirmedCount,\n confirmedAt: new Date(),\n confirmedBy: (req as any).actor,\n updatedAt: new Date(),\n }\n if (respectRecipientTimezone) set.respectRecipientTimezone = true\n\n await c.broadcasts.updateOne({ _id: b._id }, { $set: set })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.schedule',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n diffSummary: `scheduled at ${scheduled.toISOString()} · confirmedCount=${confirmedCount} · threshold=${threshold}`,\n })\n return res.json({ ok: true })\n }),\n )\n\n r.post(\n '/broadcasts/:slug/cancel',\n asyncHandler(async (req, res) => {\n const b = await c.broadcasts.findOne({ slug: req.params.slug })\n if (!b) return res.status(404).json({ error: 'not_found' })\n await c.broadcasts.updateOne({ _id: b._id }, { $set: { status: 'cancelled', updatedAt: new Date() } })\n await mailer.audit({\n actor: (req as any).actor,\n action: 'broadcast.cancel',\n resource: { collection: 'mailer_broadcasts', id: b._id, slug: b.slug },\n })\n return res.json({ ok: true })\n }),\n )\n\n // Catch-all 404 for /api.\n r.use((_req, res) => res.status(404).json({ error: 'not_found' }))\n\n return r\n}\n\ntype AsyncHandler = (req: Request, res: Response, next: NextFunction) => Promise<unknown>\nfunction asyncHandler(fn: AsyncHandler) {\n return (req: Request, res: Response, next: NextFunction) => {\n fn(req, res, next).catch(next)\n }\n}\n\n/**\n * Sum inFlight and delayed across every queue the driver exposes. Returns\n * `null` for either count when the driver doesn't implement that accessor\n * (e.g. Agenda/Noop), so the UI can render \"—\" instead of a misleading 0.\n */\nasync function collectQueueCounts(\n mailer: Mailer,\n): Promise<{ inFlight: number | null; delayed: number | null }> {\n const qs = Object.values(mailer.queues) as Array<{\n getInFlightCount?: () => Promise<number | null>\n getDelayedCount?: () => Promise<number | null>\n }>\n const sum = async (key: 'getInFlightCount' | 'getDelayedCount'): Promise<number | null> => {\n let total = 0\n let supported = false\n for (const q of qs) {\n const fn = q[key]\n if (!fn) continue\n try {\n const v = await fn.call(q)\n if (v == null) continue\n total += v\n supported = true\n } catch {\n // Treat one queue's failure as \"unknown\" — surface as null upstream.\n return null\n }\n }\n return supported ? total : null\n }\n const [inFlight, delayed] = await Promise.all([sum('getInFlightCount'), sum('getDelayedCount')])\n return { inFlight, delayed }\n}\n\n// ---------------------------------------------------------------------------\n// Live stats aggregation\n//\n// The flow / template / broadcast list endpoints used to return zeros for\n// every metric because no rollup ever wrote to `stats.*` on those docs. We\n// now compute them on-the-fly from the canonical `sends` and `flowRuns`\n// collections. Optional slug/id filters keep single-resource reads cheap.\n// ---------------------------------------------------------------------------\n\ninterface FlowStats {\n activeRuns: number\n completedRuns: number\n sendsLast7Days: number\n sendsTotal: number\n}\nfunction emptyFlowStats(): FlowStats {\n return { activeRuns: 0, completedRuns: 0, sendsLast7Days: 0, sendsTotal: 0 }\n}\n\nasync function computeFlowStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, FlowStats>> {\n const out = new Map<string, FlowStats>()\n const match = slugFilter ? { flowSlug: slugFilter } : {}\n\n const runRows = await mailer.collections.flowRuns\n .aggregate<{ _id: { flowSlug: string; status: string }; count: number }>([\n { $match: match },\n { $group: { _id: { flowSlug: '$flowSlug', status: '$status' }, count: { $sum: 1 } } },\n ])\n .toArray()\n for (const row of runRows) {\n const slug = row._id.flowSlug\n if (!slug) continue\n const cur = out.get(slug) ?? emptyFlowStats()\n if (row._id.status === 'active') cur.activeRuns += row.count\n else if (row._id.status === 'completed') cur.completedRuns += row.count\n out.set(slug, cur)\n }\n\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n const sendRows = await mailer.collections.sends\n .aggregate<{ _id: string; total: number; last7: number }>([\n { $match: { flowRunId: { $ne: null } } },\n {\n $lookup: {\n from: mailer.collections.flowRuns.collectionName,\n localField: 'flowRunId',\n foreignField: '_id',\n as: 'run',\n pipeline: slugFilter\n ? [{ $match: { flowSlug: slugFilter } }, { $project: { flowSlug: 1 } }]\n : [{ $project: { flowSlug: 1 } }],\n },\n },\n { $unwind: '$run' },\n {\n $group: {\n _id: '$run.flowSlug',\n total: { $sum: 1 },\n last7: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of sendRows) {\n if (!row._id) continue\n const cur = out.get(row._id) ?? emptyFlowStats()\n cur.sendsTotal = row.total\n cur.sendsLast7Days = row.last7\n out.set(row._id, cur)\n }\n\n return out\n}\n\ninterface TemplateStats {\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n}\nfunction emptyTemplateStats(): TemplateStats {\n return { sent: 0, opened: 0, clicked: 0, bounced: 0, sentLast7Days: 0, lastSentAt: null }\n}\n\nasync function computeTemplateStats(mailer: Mailer, slugFilter?: string): Promise<Map<string, TemplateStats>> {\n const out = new Map<string, TemplateStats>()\n const match: Record<string, unknown> = {}\n if (slugFilter) match.templateSlug = slugFilter\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: string\n sent: number\n opened: number\n clicked: number\n bounced: number\n sentLast7Days: number\n lastSentAt: Date | null\n }>([\n { $match: match },\n {\n $group: {\n _id: '$templateSlug',\n sent: { $sum: 1 },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n sentLast7Days: { $sum: { $cond: [{ $gte: ['$queuedAt', sevenDaysAgo] }, 1, 0] } },\n lastSentAt: { $max: '$queuedAt' },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(row._id, {\n sent: row.sent,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n sentLast7Days: row.sentLast7Days,\n lastSentAt: row.lastSentAt ?? null,\n })\n }\n return out\n}\n\ninterface BroadcastStats {\n delivered: number\n opened: number\n clicked: number\n bounced: number\n}\nfunction emptyBroadcastStats(): BroadcastStats {\n return { delivered: 0, opened: 0, clicked: 0, bounced: 0 }\n}\n\nasync function computeBroadcastStats(\n mailer: Mailer,\n idFilter?: ObjectId,\n): Promise<Map<string, BroadcastStats>> {\n const out = new Map<string, BroadcastStats>()\n const match: Record<string, unknown> = { broadcastId: { $ne: null } }\n if (idFilter) match.broadcastId = idFilter\n\n const rows = await mailer.collections.sends\n .aggregate<{\n _id: ObjectId\n delivered: number\n opened: number\n clicked: number\n bounced: number\n }>([\n { $match: match },\n {\n $group: {\n _id: '$broadcastId',\n delivered: { $sum: { $cond: [{ $eq: ['$status', 'delivered'] }, 1, 0] } },\n opened: { $sum: { $cond: [{ $ifNull: ['$openedAt', false] }, 1, 0] } },\n clicked: { $sum: { $cond: [{ $ifNull: ['$firstClickAt', false] }, 1, 0] } },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n for (const row of rows) {\n if (!row._id) continue\n out.set(String(row._id), {\n delivered: row.delivered,\n opened: row.opened,\n clicked: row.clicked,\n bounced: row.bounced,\n })\n }\n return out\n}\n","/**\n * Setup-status: a small suite of synchronous checks the admin dashboard\n * surfaces as a banner. Each check returns an `ok | warn | error` verdict\n * with a short message and optional hint. The endpoint exists to catch the\n * \"silent misconfiguration that breaks sends\" class of bug — missing DOI\n * template, workers not running, fromDefaults on a domain that doesn't pass\n * the senderDomains registry, etc.\n */\n\nimport type { Mailer } from '../mailer.js'\nimport { validateSenderDomain } from '../templates/sender-domain.js'\nimport { resolveSourceTags } from '../runner/dmarc.js'\nimport { HEALTH_AGG_ID } from '../models/index.js'\n\nexport type CheckSeverity = 'ok' | 'warn' | 'error'\n\nexport interface SetupCheck {\n /** Stable identifier, e.g. 'mongo', 'workers_heartbeat'. */\n name: string\n /** Human-readable label, e.g. \"MongoDB connection\". */\n label: string\n severity: CheckSeverity\n message: string\n /** Optional remediation hint shown when the user expands the row. */\n hint?: string\n}\n\nexport interface SetupStatus {\n overall: CheckSeverity\n generatedAt: string\n checks: SetupCheck[]\n}\n\nexport async function runSetupChecks(mailer: Mailer): Promise<SetupStatus> {\n const checks: SetupCheck[] = []\n\n checks.push(await checkMongo(mailer))\n checks.push(await checkQueue(mailer))\n // Run the heartbeat check even in a workerless process: in a web/worker\n // split the workerless web process is the one WITH the admin UI, so it is\n // exactly where an operator will look for \"are the workers alive\". The\n // heartbeat lives in Mongo, which both processes share, so the check works\n // from either side — only the remediation wording differs.\n if (mailer.config.queue.driver !== 'noop') {\n checks.push(await checkWorkersHeartbeat(mailer))\n }\n checks.push(await checkCircuitBreaker(mailer))\n checks.push(await checkDnsbl(mailer))\n checks.push(await checkPostmaster(mailer))\n checks.push(await checkSnds(mailer))\n const jmrp = checkJmrp(mailer)\n if (jmrp) checks.push(jmrp)\n checks.push(await checkDmarc(mailer))\n checks.push(...checkFromDefaultsAgainstRegistry(mailer))\n checks.push(...(await checkPublishedTemplates(mailer)))\n checks.push(await checkPostalAddress(mailer))\n checks.push(await checkDoiTemplate(mailer))\n\n const overall: CheckSeverity = checks.some((c) => c.severity === 'error')\n ? 'error'\n : checks.some((c) => c.severity === 'warn')\n ? 'warn'\n : 'ok'\n\n return {\n overall,\n generatedAt: new Date().toISOString(),\n checks,\n }\n}\n\nasync function checkMongo(mailer: Mailer): Promise<SetupCheck> {\n try {\n await mailer.db.admin().ping()\n return { name: 'mongo', label: 'MongoDB connection', severity: 'ok', message: 'reachable' }\n } catch (err) {\n return {\n name: 'mongo',\n label: 'MongoDB connection',\n severity: 'error',\n message: `MongoDB ping failed: ${(err as Error)?.message ?? err}`,\n hint: 'Mailery is configured against an unreachable Mongo. Sends, flow advancement, and admin reads will all fail.',\n }\n }\n}\n\nasync function checkQueue(mailer: Mailer): Promise<SetupCheck> {\n const driver = mailer.config.queue.driver\n if (driver === 'noop') {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'ok',\n message: 'driver: noop (synchronous-only mode)',\n }\n }\n try {\n await mailer.queues.send.getWaitingCount()\n return { name: 'queue', label: 'Queue driver', severity: 'ok', message: `driver: ${driver}` }\n } catch (err) {\n return {\n name: 'queue',\n label: 'Queue driver',\n severity: 'error',\n message: `${driver} queue is not responding: ${(err as Error)?.message ?? err}`,\n hint:\n driver === 'bull'\n ? 'Check Redis connectivity (queue.redis.url).'\n : 'Check the @hokify/agenda + Mongo connection.',\n }\n }\n}\n\nasync function checkWorkersHeartbeat(mailer: Mailer): Promise<SetupCheck> {\n // The aggregate doc's updatedAt is touched on every counter increment and\n // on every evaluate tick, so it's the canonical worker-heartbeat marker.\n const h = await mailer.collections.health.findOne(\n {},\n { sort: { updatedAt: -1 } },\n )\n const tickIntervalMs = mailer.config.tickIntervalSeconds * 1000\n const staleAfterMs = Math.max(tickIntervalMs * 3, 30_000) // tolerate a couple missed ticks\n\n // This process may not run the workers itself (web/worker split) — keep the\n // verdicts identical either way, but point the operator at the right place.\n const workerless = mailer.config.workerless\n\n if (!h) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'warn',\n message: workerless ? 'no tick has run yet (workers run in another process)' : 'no tick has run yet',\n hint: workerless\n ? 'This process is workerless; the heartbeat comes from your separate worker process. If that process is started, the heartbeat will appear within one tick interval — a fresh install legitimately has none yet.'\n : 'If your separate worker process is started, the heartbeat will appear within one tick interval. If you forgot to run `mailer.startWorkers()`, sends will sit queued indefinitely.',\n }\n }\n\n const ageMs = Date.now() - new Date(h.updatedAt).getTime()\n if (ageMs > staleAfterMs) {\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'error',\n message: `last tick ${humanDuration(ageMs)} ago (expected within ${humanDuration(tickIntervalMs)})`,\n hint: workerless\n ? 'Workers run in another process, and that process appears to be down. Sends and flow advancement are halted. Restart the process that calls `mailer.startWorkers()`.'\n : 'Workers appear to be down. Sends and flow advancement are halted. Restart your worker process (`mailer.startWorkers()`).',\n }\n }\n return {\n name: 'workers_heartbeat',\n label: 'Background workers',\n severity: 'ok',\n message: `last tick ${humanDuration(ageMs)} ago${workerless ? ' (worker process)' : ''}`,\n }\n}\n\nasync function checkCircuitBreaker(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.health.find({}).toArray()\n const buckets = docs.filter((d) => d._id !== HEALTH_AGG_ID)\n\n if (buckets.length === 0) {\n // No telemetry yet (heartbeat-only state, no sends recorded). Claiming\n // \"healthy\" misleads — there's nothing to base it on.\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'ok',\n message: 'no telemetry yet',\n hint: 'The breaker tracks bounce / complaint rates per (sender domain × kind) and starts evaluating once enough sends have been recorded. Send some mail to populate.',\n }\n }\n\n const tripped = buckets.filter((d) => d.status === 'tripped')\n if (tripped.length > 0) {\n const summary = tripped\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'error',\n message: `tripped: ${summary}`,\n hint: 'Marketing sends are held for the listed bucket(s). Investigate the underlying bounce / complaint cause, then POST /api/health/resume (with optional senderDomain + kind to resume one bucket).',\n }\n }\n\n const degraded = buckets.filter((d) => d.status === 'degraded')\n if (degraded.length > 0) {\n const summary = degraded\n .map((d) => `${d.senderDomain ?? '_unknown'}/${d.kind}`)\n .join(', ')\n return {\n name: 'circuit_breaker',\n label: 'Circuit breaker',\n severity: 'warn',\n message: `degraded: ${summary}`,\n hint: 'Marketing sends still flow but failure rate is above the degraded threshold for the listed bucket(s). Investigate provider errors before they escalate to tripped.',\n }\n }\n\n return { name: 'circuit_breaker', label: 'Circuit breaker', severity: 'ok', message: 'healthy' }\n}\n\nasync function checkDnsbl(mailer: Mailer): Promise<SetupCheck> {\n const docs = await mailer.collections.dnsblChecks.find({}).toArray()\n if (docs.length === 0) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: 'no checks run yet',\n hint: 'Checks run automatically once per dnsbl.intervalHours (default 24h). To run now, POST /api/dnsbl/recheck.',\n }\n }\n const listed = docs.filter((d) => d.result === 'listed')\n if (listed.length > 0) {\n const summary = listed\n .map((d) => `${d.target} on ${d.listLabel}`)\n .slice(0, 3)\n .join('; ')\n const more = listed.length > 3 ? ` (+${listed.length - 3} more)` : ''\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'error',\n message: `${listed.length} listing(s): ${summary}${more}`,\n hint: 'A sender domain or IP is listed on a public DNSBL. Investigate the listing source — most lists publish a removal procedure on their website. Mail to the affected (domain, kind) bucket will likely land in spam until delisted.',\n }\n }\n const errored = docs.filter((d) => d.result === 'error')\n if (errored.length === docs.length) {\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'warn',\n message: `all ${docs.length} checks errored`,\n hint: 'Lookups against block lists are failing — usually a DNS-resolution problem on the host running mailery, or a list rate-limiting your public resolver. Verify outbound DNS works.',\n }\n }\n return {\n name: 'dnsbl',\n label: 'DNS block-list checks',\n severity: 'ok',\n message: `clean (${docs.length} checks)`,\n }\n}\n\nasync function checkPostmaster(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.postmaster\n if (!cfg?.clientId || !cfg?.clientSecret || !cfg?.refreshToken) {\n // Postmaster is opt-in (needs OAuth setup) and only meaningful at >100/day\n // to Gmail. Treat \"not configured\" as ok so it doesn't spam every operator\n // with a permanent warning banner.\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n message: 'not configured (optional)',\n hint: 'Set mailer.config.postmaster with an OAuth client + refresh token to pull authoritative Gmail reputation data. Only meaningful at >100 sends/day to Gmail.',\n }\n }\n\n const snapshots = await mailer.collections.postmasterSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs once per postmaster.intervalHours (default 24h). To run now, POST /api/postmaster/refresh. Postmaster only reports for domains with >100 messages/day to Gmail; smaller senders see empty responses.',\n }\n }\n\n // Find the latest snapshot per domain (snapshots are already sorted by fetchedAt desc).\n const latestByDomain = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByDomain.has(s.domain)) latestByDomain.set(s.domain, s)\n }\n const bad: string[] = []\n const low: string[] = []\n for (const s of latestByDomain.values()) {\n if (s.domainReputation === 'BAD') bad.push(s.domain)\n else if (s.domainReputation === 'LOW') low.push(s.domain)\n }\n\n if (bad.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'error',\n message: `BAD reputation on ${bad.join(', ')}`,\n hint: 'Gmail considers these domains spammy. Most mail to Gmail addresses will land in spam folder. Marketing breaker has been tripped for affected domains. See docs/guide/warming.md §6 for recovery.',\n }\n }\n if (low.length > 0) {\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'warn',\n message: `LOW reputation on ${low.join(', ')}`,\n hint: 'Reputation has slipped below Medium. Review recent complaint + bounce activity, slow down marketing volume, and re-engage your most active segment only.',\n }\n }\n return {\n name: 'postmaster',\n label: 'Google Postmaster Tools',\n severity: 'ok',\n // Includes REPUTATION_CATEGORY_UNSPECIFIED (\"no data yet\") domains —\n // surface that explicitly so the operator isn't misled.\n message: (() => {\n const tiers = new Set(Array.from(latestByDomain.values()).map((d) => d.domainReputation))\n const hasUnspec = tiers.has('REPUTATION_CATEGORY_UNSPECIFIED' as any)\n return `${latestByDomain.size} domain(s) tracked${hasUnspec ? ' (some have no reputation data yet)' : ', all High/Medium'}`\n })(),\n }\n}\n\n/**\n * JMRP enrolment is a manual one-time setup on the Microsoft sender-support\n * portal — there's no API to confirm completion. We surface a persistent\n * info-level reminder whenever the operator has configured a dedicated IP,\n * regardless of whether SNDS itself is set up. Operators can suppress this\n * by setting `dnsbl.dedicatedIps = []` once they've confirmed enrolment in\n * their runbook.\n */\nfunction checkJmrp(mailer: Mailer): SetupCheck | null {\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n if (!hasDedicatedIp) return null\n return {\n name: 'snds_jmrp',\n label: 'Microsoft JMRP enrolment',\n severity: 'ok',\n message: 'manual setup — confirm in your runbook',\n hint: 'Outlook spam complaints only land in mailery if you enrol each sending IP in JMRP. Visit https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx and complete the form for each IP. There is no API to verify completion; mailery shows this reminder whenever dedicatedIps is non-empty.',\n }\n}\n\nasync function checkSnds(mailer: Mailer): Promise<SetupCheck> {\n const cfg = mailer.config.snds\n const hasDedicatedIp = (mailer.config.dnsbl?.dedicatedIps?.length ?? 0) > 0\n\n if (!cfg?.accessKey) {\n if (!hasDedicatedIp) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: 'not applicable (no dedicated IP)',\n hint: 'SNDS reports IP-level Outlook/Hotmail reputation. Only meaningful when you send from a dedicated IP. Skip unless you do.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'dedicated IP configured but SNDS access key not set',\n hint: 'Sign in at https://sendersupport.olc.protection.outlook.com/snds/ , request access for your IP(s), then set mailer.config.snds.accessKey to enable daily pulls. Also enrol in JMRP at https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx so Outlook complaints flow back to your suppression list.',\n }\n }\n\n const snapshots = await mailer.collections.sndsSnapshots.find({}).sort({ fetchedAt: -1 }).toArray()\n if (snapshots.length === 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: 'configured but no data yet',\n hint: 'A pull runs every snds.intervalHours (default 24h). To run now, POST /api/snds/refresh. If you just enrolled, SNDS data can take 1-2 days to populate.',\n }\n }\n\n const latestByIp = new Map<string, typeof snapshots[number]>()\n for (const s of snapshots) {\n if (!latestByIp.has(s.ip)) latestByIp.set(s.ip, s)\n }\n const red: string[] = []\n const yellow: string[] = []\n for (const s of latestByIp.values()) {\n if (s.filterResult === 'RED') red.push(s.ip)\n else if (s.filterResult === 'YELLOW') yellow.push(s.ip)\n }\n\n if (red.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'error',\n message: `RED filter on ${red.join(', ')}`,\n hint: 'Outlook/Hotmail is filtering mail from these IPs as spam. Reduce volume, audit recent complaints / trap hits, fix any auth alignment problems, and wait for reputation to recover (typically 1-2 weeks).',\n }\n }\n if (yellow.length > 0) {\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'warn',\n message: `YELLOW filter on ${yellow.join(', ')}`,\n hint: 'Outlook is putting some mail from these IPs in the junk folder. Investigate recent complaint rate and trap hits before reputation slips to RED.',\n }\n }\n return {\n name: 'snds',\n label: 'Microsoft SNDS',\n severity: 'ok',\n message: `${latestByIp.size} IP(s) tracked, all GREEN`,\n }\n}\n\nasync function checkDmarc(mailer: Mailer): Promise<SetupCheck> {\n const reportCount = await mailer.collections.dmarcReports.estimatedDocumentCount()\n if (reportCount === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: 'no reports ingested yet',\n hint: 'Publish DMARC `rua=mailto:<your-mailbox>` in DNS, then upload received reports via /admin/mailer/api/dmarc/upload (or drag-drop in the Health screen). RUA tells you who is sending mail as your domain — both legitimate sources and spoofers.',\n }\n }\n\n const since = new Date(Date.now() - 7 * 86_400_000)\n const recent = await mailer.collections.dmarcReports.find({ rangeEnd: { $gte: since } }).toArray()\n if (recent.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `no reports in the last 7 days (${reportCount} total)`,\n hint: 'Receivers email RUA reports daily. A gap suggests inbound delivery is broken or the rua= mailbox is no longer monitored. Check inbound mail flow.',\n }\n }\n\n // Merge config-defined tags with DB-defined tags so operator tags set via\n // the admin UI count. Both labeled (non-ignored) and ignored sources are\n // treated as \"known\" — operator already triaged them.\n const tagged = await resolveSourceTags(mailer.getRunnerContext())\n const known = new Set(Array.from(tagged.keys()))\n const since30 = new Date(Date.now() - 30 * 86_400_000)\n const failures = await mailer.collections.dmarcFailures.find({ receivedAt: { $gte: since30 } }).toArray()\n const unknownFailing = failures.filter((f) => !known.has(f.sourceIp))\n\n if (unknownFailing.length === 0) {\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'ok',\n message: `${recent.length} report(s) this week, no failing unknown sources`,\n }\n }\n\n const totalFailing = unknownFailing.reduce((acc, f) => acc + f.count, 0)\n const ips = Array.from(new Set(unknownFailing.map((f) => f.sourceIp))).slice(0, 3)\n const more = unknownFailing.length > 3 ? ` (+${unknownFailing.length - 3} more)` : ''\n return {\n name: 'dmarc',\n label: 'DMARC RUA reports',\n severity: 'warn',\n message: `${totalFailing} failing message(s) from ${ips.join(', ')}${more}`,\n hint: 'These IPs sent mail claiming to be from your domain that failed DMARC alignment. Tag known-legit sources in mailer.config.dmarc.knownSources to silence them. Untagged sources are likely either forgotten SaaS tools or active spoofing.',\n }\n}\n\nfunction checkFromDefaultsAgainstRegistry(mailer: Mailer): SetupCheck[] {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const out: SetupCheck[] = []\n const from = mailer.config.fromDefaults?.email\n const tx = mailer.config.transactionalFromDefaults?.email\n\n if (from) {\n const r = validateSenderDomain(from, 'marketing', registry)\n if (!r.ok) {\n out.push({\n name: 'from_defaults_marketing',\n label: 'fromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New marketing templates that fall back to fromDefaults will fail to publish.',\n })\n }\n }\n\n if (tx) {\n const r = validateSenderDomain(tx, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_from_defaults',\n label: 'transactionalFromDefaults vs senderDomains',\n severity: 'error',\n message: r.reason,\n hint: 'New transactional templates that fall back to transactionalFromDefaults will fail to publish.',\n })\n }\n } else if (from) {\n // No transactional defaults set; transactional creates will fall back to\n // fromDefaults. Check whether that fallback is valid for transactional.\n const r = validateSenderDomain(from, 'transactional', registry)\n if (!r.ok) {\n out.push({\n name: 'transactional_fallback',\n label: 'Transactional fallback',\n severity: 'warn',\n message: `transactionalFromDefaults is unset and fromDefaults (${from}) is invalid for transactional templates`,\n hint: 'Set transactionalFromDefaults to a transactional-kind domain, or set senderDomains entry for the existing one to \"both\".',\n })\n }\n }\n\n return out\n}\n\nasync function checkPublishedTemplates(mailer: Mailer): Promise<SetupCheck[]> {\n const registry = mailer.config.senderDomains\n if (!registry || Object.keys(registry).length === 0) return []\n\n const published = await mailer.collections.templates\n .find({ publishedAt: { $ne: null } }, { projection: { slug: 1, kind: 1, fromEmail: 1 } })\n .toArray()\n\n const broken: Array<{ slug: string; reason: string }> = []\n for (const tpl of published) {\n const r = validateSenderDomain(tpl.fromEmail, tpl.kind, registry)\n if (!r.ok) broken.push({ slug: tpl.slug, reason: r.reason })\n }\n\n if (broken.length === 0) return []\n const list = broken.slice(0, 5).map((b) => `${b.slug} (${b.reason})`).join('; ')\n const more = broken.length > 5 ? ` …and ${broken.length - 5} more` : ''\n return [\n {\n name: 'published_template_domains',\n label: 'Published templates',\n severity: 'error',\n message: `${broken.length} published template${broken.length === 1 ? '' : 's'} use a fromEmail that no longer matches senderDomains: ${list}${more}`,\n hint: 'These templates will still send with their stored fromEmail until re-published. Edit each template and republish to surface the validation, or update senderDomains.',\n },\n ]\n}\n\nasync function checkPostalAddress(mailer: Mailer): Promise<SetupCheck> {\n if (mailer.config.senderAddress) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'set' }\n }\n const marketingCount = await mailer.collections.templates.countDocuments({\n kind: 'marketing',\n publishedAt: { $ne: null },\n })\n if (marketingCount === 0) {\n return { name: 'postal_address', label: 'CAN-SPAM postal address', severity: 'ok', message: 'no published marketing templates yet' }\n }\n return {\n name: 'postal_address',\n label: 'CAN-SPAM postal address',\n severity: 'warn',\n message: `${marketingCount} published marketing template${marketingCount === 1 ? '' : 's'} but senderAddress is unset`,\n hint: 'CAN-SPAM requires a postal address in marketing emails. Set `senderAddress` in your Mailer config and reference the `{{senderAddress}}` render variable in your templates.',\n }\n}\n\nasync function checkDoiTemplate(mailer: Mailer): Promise<SetupCheck> {\n if (!mailer.config.requireDoubleOptIn) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: 'DOI not required' }\n }\n const tpl = await mailer.collections.templates.findOne({\n slug: mailer.config.doiTemplateSlug,\n publishedAt: { $ne: null },\n })\n if (tpl) {\n return { name: 'doi_template', label: 'DOI template', severity: 'ok', message: `template \"${tpl.slug}\" published` }\n }\n return {\n name: 'doi_template',\n label: 'DOI template',\n severity: 'error',\n message: `requireDoubleOptIn is true but no published template with slug \"${mailer.config.doiTemplateSlug}\"`,\n hint: 'New subscriptions will silently fail to send confirmation emails. Create and publish a template with this slug, or unset requireDoubleOptIn.',\n }\n}\n\nfunction humanDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`\n return `${Math.round(ms / 3_600_000)}h`\n}\n","/**\n * List hygiene aggregations. Reports the engagement health of the\n * subscriber list: how many contacts engaged recently, how many are\n * stale, and what the bounce/complaint impact of sunsetting the stale\n * cohort would be.\n *\n * Pure read — no writes. Caller decides when to run.\n */\n\nimport type { RunnerContext } from './index.js'\n\nconst DAY_MS = 86_400_000\n\nexport const HYGIENE_BUCKETS = [\n { label: 'Engaged (last 30 days)', maxDays: 30 },\n { label: 'Engaged (31-60 days)', minDays: 30, maxDays: 60 },\n { label: 'Engaged (61-90 days)', minDays: 60, maxDays: 90 },\n { label: 'Engaged (91-180 days)', minDays: 90, maxDays: 180 },\n { label: 'Inactive (>180 days)', minDays: 180 },\n { label: 'Never engaged', neverEngaged: true },\n] as const\n\nexport interface HygieneBucket {\n label: string\n /** Lower bound of \"days since last engagement\" inclusive. Null for never-engaged. */\n minDays?: number | null\n /** Upper bound of \"days since last engagement\" exclusive. Null = unbounded. */\n maxDays?: number | null\n /** True for the \"never engaged\" bucket (sent but no open/click ever). */\n neverEngaged?: boolean\n count: number\n pctOfTotal: number\n}\n\nexport interface HygieneReport {\n totalSubscribers: number\n totalWithSends: number\n buckets: HygieneBucket[]\n sunsetCandidate: {\n /** Cohort: subscribed contacts whose lastEngagedAt is >180 days ago, or who have never engaged after >180 days of being subscribed. */\n count: number\n pctOfTotal: number\n /** Lifetime metrics for the cohort, when data exists. */\n cohortLifetime: {\n totalSends: number\n bouncedRate: number\n hardBouncedRate: number\n complaintRate: number\n } | null\n /** Projected impact: how recent (90d) rates would change if this cohort were sunset. */\n projectedImpact: {\n recentTotalSends: number\n recentBounced: number\n recentComplained: number\n cohortRecentSends: number\n cohortRecentBounced: number\n cohortRecentComplained: number\n currentOverallBounceRate: number\n projectedBounceRate: number\n currentOverallComplaintRate: number\n projectedComplaintRate: number\n } | null\n }\n computedAt: string\n}\n\nexport interface ComputeHygieneOptions {\n /** Override now() for tests. */\n now?: number\n /** Days of inactivity considered \"stale\" enough to sunset. Default 180. */\n sunsetThresholdDays?: number\n /** Window for projected-impact calculations. Default 90. */\n recentWindowDays?: number\n}\n\nexport async function computeListHygiene(\n ctx: RunnerContext,\n opts: ComputeHygieneOptions = {},\n): Promise<HygieneReport> {\n const now = opts.now ?? Date.now()\n const sunsetDays = opts.sunsetThresholdDays ?? 180\n const recentDays = opts.recentWindowDays ?? 90\n const recentCutoff = new Date(now - recentDays * DAY_MS)\n\n const totalSubscribers = await ctx.collections.subscriptions.countDocuments({ status: 'subscribed' })\n\n // Restrict the engagement aggregation to currently-subscribed contacts.\n // We materialize the subscriber externalId set in memory (one short\n // string per row). At ~10M subscribers this would be ~hundreds of MB —\n // a real concern at that scale. Below ~1M it's negligible. If list\n // sizes ever push past that, move to a server-side $lookup join inside\n // the sends aggregation.\n const subscribedIds = new Set<string>()\n {\n const cursor = ctx.collections.subscriptions\n .find({ status: 'subscribed' }, { projection: { externalId: 1 } })\n for await (const s of cursor) subscribedIds.add(s.externalId)\n }\n\n type EngagementRow = {\n _id: string\n lastOpened: Date | null\n lastClicked: Date | null\n firstSent: Date | null\n totalSends: number\n bounced: number\n hardBounced: number\n complained: number\n recentSends: number\n recentBounced: number\n recentComplained: number\n }\n\n // Single aggregation: group by externalId, computing engagement + lifetime\n // counts + recent-window counts in one pass. Cursor iteration avoids\n // loading the full per-contact map at once; allowDiskUse keeps Mongo from\n // OOMing on the $group stage at scale.\n const cursor = ctx.collections.sends.aggregate<EngagementRow>(\n [\n {\n $group: {\n _id: '$externalId',\n lastOpened: { $max: '$openedAt' },\n lastClicked: { $max: '$firstClickAt' },\n firstSent: { $min: '$queuedAt' },\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n hardBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $eq: ['$bounceType', 'hard'] }] },\n 1,\n 0,\n ],\n },\n },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n recentSends: { $sum: { $cond: [{ $gte: ['$queuedAt', recentCutoff] }, 1, 0] } },\n recentBounced: {\n $sum: {\n $cond: [\n { $and: [{ $eq: ['$status', 'bounced'] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n recentComplained: {\n $sum: {\n $cond: [\n { $and: [{ $ne: ['$complainedAt', null] }, { $gte: ['$queuedAt', recentCutoff] }] },\n 1,\n 0,\n ],\n },\n },\n },\n },\n ],\n { allowDiskUse: true },\n )\n\n const buckets: HygieneBucket[] = HYGIENE_BUCKETS.map((b) => ({\n label: b.label,\n minDays: 'minDays' in b ? b.minDays : null,\n maxDays: 'maxDays' in b ? b.maxDays : null,\n neverEngaged: 'neverEngaged' in b && b.neverEngaged,\n count: 0,\n pctOfTotal: 0,\n }))\n\n let totalWithSends = 0\n let sunsetCount = 0\n\n const cohortLifetimeAcc = { totalSends: 0, bounced: 0, hardBounced: 0, complained: 0 }\n const cohortRecentAcc = { totalSends: 0, bounced: 0, complained: 0 }\n\n for await (const row of cursor) {\n if (!subscribedIds.has(row._id)) continue\n totalWithSends++\n\n const lastOpened = row.lastOpened ? new Date(row.lastOpened).getTime() : null\n const lastClicked = row.lastClicked ? new Date(row.lastClicked).getTime() : null\n const lastEngaged = lastOpened == null && lastClicked == null\n ? null\n : Math.max(lastOpened ?? 0, lastClicked ?? 0)\n\n let isSunset = false\n if (lastEngaged == null) {\n const firstSent = row.firstSent ? new Date(row.firstSent).getTime() : null\n buckets[5]!.count++\n if (firstSent != null && now - firstSent > sunsetDays * DAY_MS) {\n isSunset = true\n }\n } else {\n const daysSince = (now - lastEngaged) / DAY_MS\n if (daysSince <= 30) buckets[0]!.count++\n else if (daysSince <= 60) buckets[1]!.count++\n else if (daysSince <= 90) buckets[2]!.count++\n else if (daysSince <= 180) buckets[3]!.count++\n else {\n buckets[4]!.count++\n isSunset = true\n }\n }\n\n if (isSunset) {\n sunsetCount++\n cohortLifetimeAcc.totalSends += row.totalSends\n cohortLifetimeAcc.bounced += row.bounced\n cohortLifetimeAcc.hardBounced += row.hardBounced\n cohortLifetimeAcc.complained += row.complained\n cohortRecentAcc.totalSends += row.recentSends\n cohortRecentAcc.bounced += row.recentBounced\n cohortRecentAcc.complained += row.recentComplained\n }\n }\n\n for (const b of buckets) {\n b.pctOfTotal = totalSubscribers === 0 ? 0 : b.count / totalSubscribers\n }\n\n const cohortLifetime: HygieneReport['sunsetCandidate']['cohortLifetime'] =\n cohortLifetimeAcc.totalSends > 0\n ? {\n totalSends: cohortLifetimeAcc.totalSends,\n bouncedRate: cohortLifetimeAcc.bounced / cohortLifetimeAcc.totalSends,\n hardBouncedRate: cohortLifetimeAcc.hardBounced / cohortLifetimeAcc.totalSends,\n complaintRate: cohortLifetimeAcc.complained / cohortLifetimeAcc.totalSends,\n }\n : null\n\n // Recent-window overall stats are bounded by the date window and small at\n // any realistic volume.\n let projectedImpact: HygieneReport['sunsetCandidate']['projectedImpact'] = null\n const recentAll = await ctx.collections.sends\n .aggregate<{ totalSends: number; bounced: number; complained: number }>([\n { $match: { queuedAt: { $gte: recentCutoff } } },\n {\n $group: {\n _id: null,\n totalSends: { $sum: 1 },\n bounced: { $sum: { $cond: [{ $eq: ['$status', 'bounced'] }, 1, 0] } },\n complained: { $sum: { $cond: [{ $ne: ['$complainedAt', null] }, 1, 0] } },\n },\n },\n ])\n .toArray()\n\n if (recentAll[0] && recentAll[0].totalSends > 0) {\n const all = recentAll[0]\n const cohort = cohortRecentAcc\n const currentBounceRate = all.bounced / all.totalSends\n const currentComplaintRate = all.complained / all.totalSends\n const remainingSends = all.totalSends - cohort.totalSends\n const remainingBounces = all.bounced - cohort.bounced\n const remainingComplaints = all.complained - cohort.complained\n const projectedBounceRate = remainingSends > 0 ? remainingBounces / remainingSends : 0\n const projectedComplaintRate = remainingSends > 0 ? remainingComplaints / remainingSends : 0\n\n projectedImpact = {\n recentTotalSends: all.totalSends,\n recentBounced: all.bounced,\n recentComplained: all.complained,\n cohortRecentSends: cohort.totalSends,\n cohortRecentBounced: cohort.bounced,\n cohortRecentComplained: cohort.complained,\n currentOverallBounceRate: currentBounceRate,\n projectedBounceRate,\n currentOverallComplaintRate: currentComplaintRate,\n projectedComplaintRate,\n }\n }\n\n return {\n totalSubscribers,\n totalWithSends,\n buckets,\n sunsetCandidate: {\n count: sunsetCount,\n pctOfTotal: totalSubscribers === 0 ? 0 : sunsetCount / totalSubscribers,\n cohortLifetime,\n projectedImpact,\n },\n computedAt: new Date(now).toISOString(),\n }\n}\n","/**\n * Mail-Tester deliverability check.\n *\n * 1. Operator clicks \"Run deliverability check\" in the template editor.\n * 2. Mailery provisions a check (gets a unique test address from Mail-Tester).\n * 3. Mailery sends the rendered draft to that address via the operator's\n * default provider.\n * 4. Mailery polls Mail-Tester for the score (typically arrives 10-30s after\n * receipt) and caches it keyed on a content fingerprint.\n * 5. If the score is below `minScore` the publish endpoint refuses unless\n * the operator passes `bypassMailTester: true` in the publish request.\n *\n * The client interface is pluggable so tests inject a stub. Real\n * implementation hits https://mail-tester.com/api/.\n */\n\nimport crypto from 'node:crypto'\n\nimport type { MailTesterConfig } from '../config.js'\nimport type { MailTesterFeedback, MailTesterScoreDoc } from '../models/index.js'\nimport type { RunnerContext } from './index.js'\n\nexport type Fetcher = (url: string, init?: RequestInit) => Promise<Response>\n\nexport interface ProvisionedCheck {\n checkId: string\n emailAddress: string\n}\n\nexport interface MailTesterResult {\n ready: boolean\n score: number\n feedback: MailTesterFeedback[]\n rawSummary: string | null\n}\n\nexport interface MailTesterClient {\n provisionCheck(): Promise<ProvisionedCheck>\n fetchResult(checkId: string): Promise<MailTesterResult>\n}\n\nconst FETCH_TIMEOUT_MS = 15_000\n\nexport function createMailTesterClient(\n cfg: MailTesterConfig,\n fetcher: Fetcher = globalThis.fetch,\n): MailTesterClient {\n const base = cfg.baseUrl ?? 'https://mail-tester.com/api'\n\n function sanitize(s: string): string {\n if (!cfg.apiKey) return s\n return s.split(cfg.apiKey).join('<redacted>').split(encodeURIComponent(cfg.apiKey)).join('<redacted>')\n }\n\n async function call(method: string, path: string, body?: unknown): Promise<any> {\n const ctl = new AbortController()\n const t = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS)\n let res: Response\n try {\n res = await fetcher(`${base}/${encodeURIComponent(cfg.apiKey)}${path}`, {\n method,\n headers: { 'content-type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n signal: ctl.signal,\n })\n } catch (err: any) {\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} failed: ${sanitize(String(err?.message ?? err))}`)\n } finally {\n clearTimeout(t)\n }\n if (!res.ok) {\n const text = await safeText(res)\n throw new Error(`Mail-Tester ${method} ${sanitize(path)} → ${res.status}: ${sanitize(text)}`)\n }\n return res.json()\n }\n\n return {\n async provisionCheck() {\n const data = await call('POST', '/new')\n const checkId = String(data.check_id ?? data.checkId ?? '')\n const emailAddress = String(data.email_address ?? data.email ?? '')\n if (!checkId || !emailAddress) throw new Error('Mail-Tester /new returned an unexpected shape')\n return { checkId, emailAddress }\n },\n async fetchResult(checkId) {\n const data = await call('GET', `/${encodeURIComponent(checkId)}`)\n // Ready is decided independently from score finiteness so a malformed\n // score number can't accidentally surface as `score: 0` and trip the\n // publish gate.\n const ready = Boolean(data.ready ?? data.complete ?? data.score != null)\n const scoreRaw = Number(data.score)\n const score = Number.isFinite(scoreRaw) ? scoreRaw : 0\n const feedback: MailTesterFeedback[] = Array.isArray(data.feedback)\n ? data.feedback.map(normalizeFeedback)\n : []\n const rawSummary = typeof data.summary === 'string' ? data.summary : null\n return { ready: ready && Number.isFinite(scoreRaw), score, feedback, rawSummary }\n },\n }\n}\n\nfunction normalizeFeedback(raw: any): MailTesterFeedback {\n const severity = String(raw.severity ?? 'info').toLowerCase()\n return {\n category: String(raw.category ?? 'other'),\n severity: severity === 'error' || severity === 'warning' || severity === 'info' ? severity : 'info',\n message: String(raw.message ?? ''),\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try { return await res.text() } catch { return '<no body>' }\n}\n\n// ---------------------------------------------------------------------------\n// Content fingerprint + cache lookups\n// ---------------------------------------------------------------------------\n\nexport function mailTesterContentKey(input: { bodyHash: string; subject: string; fromEmail: string }): string {\n return crypto\n .createHash('sha256')\n .update(`${input.bodyHash}|${input.subject}|${input.fromEmail}`)\n .digest('hex')\n}\n\nexport async function findCachedScore(\n ctx: RunnerContext,\n contentKey: string,\n): Promise<MailTesterScoreDoc | null> {\n const doc = await ctx.collections.mailTesterScores.findOne({ contentKey })\n if (!doc) return null\n if (new Date(doc.expiresAt).getTime() < Date.now()) return null\n return doc\n}\n\nexport async function persistScore(\n ctx: RunnerContext,\n input: {\n templateSlug: string\n contentKey: string\n checkId: string\n result: MailTesterResult\n },\n): Promise<MailTesterScoreDoc> {\n const cfg = ctx.config.mailTester\n const hours = cfg?.cacheHours ?? 24\n const now = new Date()\n const expiresAt = new Date(now.getTime() + hours * 60 * 60 * 1000)\n const doc: MailTesterScoreDoc = {\n templateSlug: input.templateSlug,\n contentKey: input.contentKey,\n checkId: input.checkId,\n score: input.result.score,\n feedback: input.result.feedback,\n rawSummary: input.result.rawSummary,\n fetchedAt: now,\n expiresAt,\n }\n await ctx.collections.mailTesterScores.updateOne(\n { contentKey: input.contentKey },\n { $set: doc },\n { upsert: true },\n )\n return doc\n}\n\n// ---------------------------------------------------------------------------\n// Publish gate\n// ---------------------------------------------------------------------------\n\nexport interface MailTesterGateResult {\n allowed: boolean\n /** Reason for blocking. Null when allowed. */\n reason: string | null\n /** The cached score (if one exists for the content being published). */\n score: MailTesterScoreDoc | null\n /**\n * Why the gate blocked, for callers that render different guidance:\n * - 'low_score' — a score exists and is below minScore\n * - 'no_score' — requireScore is on and this content was never checked\n * Null when allowed.\n */\n code: 'low_score' | 'no_score' | null\n}\n\n/**\n * Check whether a publish is allowed under the Mail-Tester gate.\n *\n * Default mode (`requireScore` unset/false) blocks only content already known\n * to score below `minScore`. That is a ratchet on known-bad content, not a\n * gate: the content key covers body + subject + fromEmail, so any edit misses\n * the cache and publishes freely — a failing score is one whitespace change\n * away from irrelevant.\n *\n * With `requireScore: true`, a cache miss blocks too, so every publish is\n * backed by a score for that exact content. Costs one Mail-Tester credit per\n * content revision. Either mode is overridable per-request with\n * `bypassMailTester: true`.\n *\n * We never auto-trigger a check at publish time — that would send mail as a\n * side effect of a publish request.\n */\nexport async function evaluateMailTesterGate(\n ctx: RunnerContext,\n input: { bodyHash: string; subject: string; fromEmail: string },\n): Promise<MailTesterGateResult> {\n const cfg = ctx.config.mailTester\n if (!cfg?.apiKey) return { allowed: true, reason: null, score: null, code: null }\n\n const minScore = cfg.minScore ?? 8.0\n const key = mailTesterContentKey(input)\n const cached = await findCachedScore(ctx, key)\n\n if (!cached) {\n if (cfg.requireScore) {\n return {\n allowed: false,\n reason:\n 'No Mail-Tester score for this exact content. Run a deliverability check before publishing.',\n score: null,\n code: 'no_score',\n }\n }\n return { allowed: true, reason: null, score: null, code: null }\n }\n\n if (cached.score < minScore) {\n return {\n allowed: false,\n reason: `Mail-Tester score ${cached.score.toFixed(1)} is below minimum ${minScore.toFixed(1)}`,\n score: cached,\n code: 'low_score',\n }\n }\n return { allowed: true, reason: null, score: cached, code: null }\n}\n","/**\n * Public router — endpoints that must be reachable by email clients and\n * provider webhooks. Mount under your tracking base path (default `/m`).\n *\n * app.use('/m', createPublicRouter(mailer))\n *\n * Routes:\n * GET /open/:sendId.png — open pixel (records open, returns 1×1 PNG)\n * GET /click/:sendId/:linkId — click redirect (records click, 302 → target)\n * GET /unsub/:token — confirmation page (one-click POST link)\n * POST /unsub/:token — RFC 8058 one-click unsubscribe\n * POST /webhooks/:provider — inbound provider event webhook\n */\n\nimport express, { Router, type Request, type Response } from 'express'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { ObjectId } from 'mongodb'\n\nimport { sha256Hex, verifyUnsubscribeToken, verifyDoiToken } from '../tokens.js'\nimport type { Mailer } from '../mailer.js'\n\nexport interface PublicRouterOptions {\n /**\n * Path on disk where unsubscribe events fall back to when Mongo is degraded.\n * Defaults to /tmp/mailery-pending-unsubs.jsonl.\n */\n pendingUnsubsPath?: string\n}\n\n// 1×1 transparent PNG (43 bytes)\nconst PIXEL = Buffer.from(\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',\n 'base64',\n)\n\nexport function createPublicRouter(mailer: Mailer, opts: PublicRouterOptions = {}): Router {\n const router = Router()\n const pendingUnsubsPath = opts.pendingUnsubsPath ?? '/tmp/mailery-pending-unsubs.jsonl'\n\n // Parse JSON for webhooks — capture raw body for signature verification.\n router.use(\n '/webhooks',\n express.json({\n limit: '5mb',\n verify: (req: any, _res, buf) => {\n req.rawBody = buf\n },\n }),\n )\n\n // Pre-parsed JSON for the POST one-click unsubscribe path (RFC 8058 sends a\n // small form/JSON body; we accept either by reading the URL only).\n router.use('/unsub', express.urlencoded({ extended: false }))\n\n // -------------------------------------------------------------------------\n // GET /open/:sendId.png\n // -------------------------------------------------------------------------\n router.get('/open/:sendId.png', async (req: Request, res: Response) => {\n res.setHeader('Content-Type', 'image/png')\n res.setHeader('Content-Length', String(PIXEL.length))\n res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')\n res.status(200).end(PIXEL)\n\n // Async update — never block the response.\n const id = (req.params as any).sendId as string\n if (!ObjectId.isValid(id)) return\n const sendId = new ObjectId(id)\n try {\n const send = await mailer.collections.sends.findOne({ _id: sendId }, { projection: { openedAt: 1 } })\n if (!send) return\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: {\n openedAt: send.openedAt ?? new Date(),\n status: 'delivered' as const,\n },\n $inc: { openCount: 1 },\n },\n )\n } catch (err) {\n console.error('mailery: open pixel update failed', err)\n }\n })\n\n // -------------------------------------------------------------------------\n // GET /click/:sendId/:linkId\n // -------------------------------------------------------------------------\n router.get('/click/:sendId/:linkId', async (req: Request, res: Response) => {\n const { sendId: sendIdStr, linkId } = req.params as { sendId: string; linkId: string }\n if (!ObjectId.isValid(sendIdStr)) return res.status(400).end()\n const sendId = new ObjectId(sendIdStr)\n\n const send = await mailer.collections.sends.findOne(\n { _id: sendId },\n { projection: { links: 1, firstClickAt: 1 } },\n )\n if (!send) return res.status(404).end()\n\n const link = (send.links ?? []).find((l) => l.linkId === linkId)\n if (!link) return res.status(404).end()\n\n res.redirect(302, link.url)\n\n try {\n await mailer.collections.sends.updateOne(\n { _id: sendId },\n {\n $set: { firstClickAt: send.firstClickAt ?? new Date() },\n $inc: { clickCount: 1 },\n $push: {\n clickedLinks: {\n url: link.url,\n linkId,\n clickedAt: new Date(),\n },\n },\n },\n )\n } catch (err) {\n console.error('mailery: click recording failed', err)\n }\n })\n\n // -------------------------------------------------------------------------\n // GET + POST /unsub/:token\n // -------------------------------------------------------------------------\n router.get('/unsub/:token', (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) return sendUnsubError(res, 'Invalid or expired link.')\n\n res.status(200).type('html').send(`<!doctype html>\n<html><head>\n <meta charset=\"utf-8\" />\n <title>Unsubscribe</title>\n <style>body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:48px auto;padding:0 16px;color:#1c1917;line-height:1.5}h1{font-size:20px}button{padding:10px 18px;background:#dc2626;color:#fff;border:0;border-radius:6px;font-size:14px;cursor:pointer}</style>\n</head><body>\n <h1>Confirm unsubscribe</h1>\n <p>Click the button below to unsubscribe <strong>${escapeHtml(decoded.email)}</strong>${decoded.scope === 'all' ? ' from everything' : ' from marketing emails'}.</p>\n <form method=\"POST\" action=\"${escapeHtml(req.originalUrl)}\">\n <button type=\"submit\">Unsubscribe</button>\n </form>\n</body></html>`)\n })\n\n router.post('/unsub/:token', async (req: Request, res: Response) => {\n const decoded = verifyUnsubscribeToken((req.params as any).token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n res.status(200).end() // never 5xx; let provider stop retrying\n return\n }\n\n // Reply 200 immediately. INVARIANT 8: bulletproof unsubscribe.\n res.status(200).type('html').send('<!doctype html><html><body><p>You are unsubscribed.</p></body></html>')\n\n try {\n await mailer.unsubscribe(decoded.email, {\n scope: decoded.scope,\n reason: 'user_request',\n source: 'one-click',\n })\n } catch (err) {\n try {\n fs.appendFileSync(\n pendingUnsubsPath,\n JSON.stringify({ email: decoded.email, scope: decoded.scope, at: Date.now() }) + '\\n',\n )\n } catch (diskErr) {\n console.error('mailery: unsub disk fallback failed', { err, diskErr })\n }\n }\n })\n\n // -------------------------------------------------------------------------\n // GET /confirm-doi/:token\n // -------------------------------------------------------------------------\n router.get('/confirm-doi/:token', async (req: Request, res: Response) => {\n const token = (req.params as any).token as string\n const decoded = verifyDoiToken(token, mailer.config.unsubscribeSecret)\n if (!decoded) {\n return res.status(400).type('html').send('<!doctype html><html><body><p>Confirmation link is invalid or expired.</p></body></html>')\n }\n const now = new Date()\n const result = await mailer.collections.subscriptions.updateOne(\n { externalId: decoded.externalId, status: 'pending_doi' },\n {\n $set: {\n status: 'subscribed',\n subscribedAt: now,\n doiConfirmedAt: now,\n doiIp: req.ip ?? null,\n doiUserAgent: (req.headers['user-agent'] as string | undefined) ?? null,\n updatedAt: now,\n },\n },\n )\n if (result.matchedCount === 0) {\n return res.status(200).type('html').send('<!doctype html><html><body><p>Already confirmed. Thanks.</p></body></html>')\n }\n try {\n await mailer.fire('subscription.confirmed', decoded.externalId, {}, `doi-confirmed:${decoded.externalId}`)\n } catch {\n /* swallow — subscription is confirmed regardless */\n }\n return res.status(200).type('html').send('<!doctype html><html><body><p>Thanks — you\\'re subscribed.</p></body></html>')\n })\n\n // -------------------------------------------------------------------------\n // POST /webhooks/:provider\n // -------------------------------------------------------------------------\n router.post('/webhooks/:provider', async (req: Request, res: Response) => {\n const providerName = (req.params as any).provider as string\n const provider = mailer.providers[providerName]\n if (!provider) return res.status(404).end()\n\n const rawBody = (req as any).rawBody as Buffer | undefined\n if (!rawBody) return res.status(400).end()\n\n const headers = lowercaseHeaders(req.headers)\n const valid = await provider.verifyWebhook(rawBody, headers)\n if (!valid) return res.status(401).end()\n\n const events = provider.parseWebhookEvents(req.body, headers)\n\n // Always 200 fast — fail-open, retry inbound is wasted bandwidth.\n res.status(200).end()\n\n // Preserve the original provider payload alongside each normalized event so the\n // audit trail isn't reduced to just our extracted fields. The raw body is the\n // full provider response array; we record it once per parsed event for clarity.\n const rawBodyRef = req.body as unknown\n for (const evt of events) {\n try {\n await mailer.collections.webhookEvents.updateOne(\n { provider: providerName, providerEventId: evt.providerEventId },\n {\n $setOnInsert: {\n provider: providerName,\n providerEventId: evt.providerEventId,\n eventType: evt.type,\n normalizedType: evt.type,\n providerMessageId: evt.providerMessageId,\n email: evt.email,\n occurredAt: evt.occurredAt,\n receivedAt: new Date(),\n processed: false,\n raw: { normalized: evt, providerBody: rawBodyRef },\n },\n },\n { upsert: true },\n )\n } catch (err) {\n console.error('mailery: webhook dedupe insert failed', err)\n }\n }\n\n if (events.length > 0) {\n try {\n await mailer.queues.webhook.add('webhook', { provider: providerName })\n } catch {\n /* will be picked up by next tick */\n }\n }\n\n // Bypass linting — `path` import retained for any future on-disk fallback.\n void path\n })\n\n return router\n}\n\nfunction sendUnsubError(res: Response, msg: string): Response {\n return res.status(400).type('html').send(`<!doctype html><html><body><p>${escapeHtml(msg)}</p></body></html>`)\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\nfunction lowercaseHeaders(h: any): Record<string, string> {\n const out: Record<string, string> = {}\n for (const k of Object.keys(h)) {\n const v = h[k]\n out[k.toLowerCase()] = Array.isArray(v) ? v.join(',') : String(v ?? '')\n }\n return out\n}\n\n// silence unused\nvoid sha256Hex\n","/**\n * Enumerable option lists for the union types in `./types.ts`. Used by the\n * admin client to render dropdowns + by tooling to enumerate the surface.\n *\n * Kept in `shared/` so the client and server agree on the canonical labels +\n * default constructors. Pure data + pure functions — no React, no DOM.\n */\n\nimport type { FlowStep, Predicate, SegmentFilter } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Flow step types\n// ---------------------------------------------------------------------------\n\nexport interface FlowStepKindOption {\n value: FlowStep['type']\n label: string\n /** Icon name from the client's icon set (lookup at render time). */\n icon: string\n /** Visual class on the canvas chip. */\n iconClass: string\n /** One-line description for tooltips / docs generation. */\n description: string\n}\n\nexport const FLOW_STEP_KINDS: readonly FlowStepKindOption[] = [\n { value: 'wait', label: 'Wait', icon: 'Clock', iconClass: 'wait', description: 'Pause the run for a duration before continuing.' },\n { value: 'condition', label: 'Condition', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Exit or skip on false.' },\n { value: 'branch', label: 'Branch', icon: 'Branch', iconClass: 'condition', description: 'Evaluate a predicate. Recurse into one of two sub-lists.' },\n { value: 'send', label: 'Send', icon: 'Mail', iconClass: 'send', description: 'Send a template to the contact.' },\n { value: 'tag', label: 'Tag', icon: 'Tag', iconClass: 'tag', description: 'Add or remove tags on the contact.' },\n { value: 'fire_event', label: 'Fire event', icon: 'Activity', iconClass: 'send', description: 'Insert a synthetic event (cross-flow handoff).' },\n { value: 'webhook', label: 'Webhook', icon: 'Webhook', iconClass: 'tag', description: 'POST to an external URL.' },\n { value: 'exit', label: 'Exit', icon: 'Exit', iconClass: 'exit', description: 'End the run with an optional reason.' },\n] as const\n\nexport function defaultFlowStep(type: FlowStep['type']): FlowStep {\n switch (type) {\n case 'wait': return { type: 'wait', value: 1, unit: 'days' }\n case 'condition': return { type: 'condition', test: { hasTag: 'engaged' }, ifFalse: 'exit' }\n case 'branch': return { type: 'branch', test: { hasTag: 'vip' }, ifTrueSteps: [], ifFalseSteps: [] }\n case 'send': return { type: 'send', templateSlug: '' }\n case 'tag': return { type: 'tag', addTags: [], removeTags: [] }\n case 'fire_event': return { type: 'fire_event', eventName: '' }\n case 'webhook': return { type: 'webhook', url: '', method: 'POST' }\n case 'exit': return { type: 'exit' }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Predicate kinds (the union variants of Predicate, minus composites)\n// ---------------------------------------------------------------------------\n\nexport type PredicateKind =\n | 'hasTag'\n | 'notHasTag'\n | 'fieldEquals'\n | 'fieldExists'\n | 'triggerPropertyEquals'\n | 'triggerPropertyTruthy'\n | 'hasFiredEvent'\n | 'notHasFiredEvent'\n | 'subscriptionStatus'\n | 'hasOpened'\n | 'hasClicked'\n | 'hasOpenedExcludingBots'\n | 'hasClickedExcludingBots'\n | 'openedAtLeastN'\n | 'clickedAtLeastN'\n\nexport interface PredicateKindOption {\n value: PredicateKind\n label: string\n /** True when this predicate's signal is noisy (Apple MPP, bot prefetch). */\n noisy?: boolean\n}\n\nexport const PREDICATE_KINDS: readonly PredicateKindOption[] = [\n { value: 'hasTag', label: 'has tag' },\n { value: 'notHasTag', label: 'does NOT have tag' },\n { value: 'fieldEquals', label: 'field equals' },\n { value: 'fieldExists', label: 'field exists' },\n { value: 'triggerPropertyEquals', label: 'trigger property equals' },\n { value: 'triggerPropertyTruthy', label: 'trigger property is set' },\n { value: 'hasFiredEvent', label: 'fired event' },\n { value: 'notHasFiredEvent', label: 'has NOT fired event' },\n { value: 'subscriptionStatus', label: 'subscription status' },\n { value: 'hasOpened', label: 'opened', noisy: true },\n { value: 'hasClicked', label: 'clicked', noisy: true },\n { value: 'hasOpenedExcludingBots', label: 'opened (excl. bots)' },\n { value: 'hasClickedExcludingBots', label: 'clicked (excl. bots)' },\n { value: 'openedAtLeastN', label: 'opened at least N' },\n { value: 'clickedAtLeastN', label: 'clicked at least N' },\n] as const\n\n/** Identify which kind of predicate this object is (or null for composites/unknown). */\nexport function predicateKind(p: Predicate | null | undefined): PredicateKind | null {\n if (!p) return null\n for (const k of PREDICATE_KINDS) {\n if (k.value in (p as object)) return k.value\n }\n return null\n}\n\nexport function defaultPredicate(kind: PredicateKind): Predicate {\n switch (kind) {\n case 'hasTag': return { hasTag: 'engaged' }\n case 'notHasTag': return { notHasTag: 'cold' }\n case 'fieldEquals': return { fieldEquals: { field: 'tier', value: 'Pro' } }\n case 'fieldExists': return { fieldExists: 'tier' }\n case 'triggerPropertyEquals': return { triggerPropertyEquals: { key: 'plan', value: 'pro' } }\n case 'triggerPropertyTruthy': return { triggerPropertyTruthy: 'wasReferred' }\n case 'hasFiredEvent': return { hasFiredEvent: 'Activated app' }\n case 'notHasFiredEvent': return { notHasFiredEvent: 'Cancelled' }\n case 'subscriptionStatus': return { subscriptionStatus: 'subscribed' }\n case 'hasOpened': return { hasOpened: { sinceFlowStart: true } }\n case 'hasClicked': return { hasClicked: { sinceFlowStart: true } }\n case 'hasOpenedExcludingBots': return { hasOpenedExcludingBots: { sinceFlowStart: true } }\n case 'hasClickedExcludingBots': return { hasClickedExcludingBots: { sinceFlowStart: true } }\n case 'openedAtLeastN': return { openedAtLeastN: { count: 1, withinDays: 7 } }\n case 'clickedAtLeastN': return { clickedAtLeastN: { count: 1, withinDays: 7 } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Segment filter kinds\n// ---------------------------------------------------------------------------\n\nexport type SegmentFilterKind = SegmentFilter['kind']\n\nexport interface SegmentFilterKindOption {\n value: SegmentFilterKind\n label: string\n /** Where the filter is evaluated: host-side via adapter, or mailer-side post-filter. */\n side: 'host' | 'mailer' | 'composite'\n}\n\nexport const SEGMENT_FILTER_KINDS: readonly SegmentFilterKindOption[] = [\n { value: 'subscriptionStatus', label: 'Subscription status', side: 'mailer' },\n { value: 'hasTag', label: 'Has tag', side: 'host' },\n { value: 'notHasTag', label: 'Does NOT have tag', side: 'host' },\n { value: 'fieldEquals', label: 'Field equals', side: 'host' },\n { value: 'fieldIn', label: 'Field in list', side: 'host' },\n { value: 'fieldExists', label: 'Field exists', side: 'host' },\n { value: 'firedEvent', label: 'Fired event', side: 'mailer' },\n { value: 'notFiredEvent', label: 'Has NOT fired event', side: 'mailer' },\n { value: 'subscribedAfter', label: 'Subscribed after', side: 'mailer' },\n { value: 'subscribedBefore', label: 'Subscribed before', side: 'mailer' },\n { value: 'opened', label: 'Opened', side: 'mailer' },\n { value: 'notOpened', label: 'Did NOT open', side: 'mailer' },\n { value: 'any', label: 'Any of (OR)', side: 'composite' },\n { value: 'not', label: 'NOT', side: 'composite' },\n] as const\n\nexport function defaultSegmentFilter(kind: SegmentFilterKind): SegmentFilter {\n switch (kind) {\n case 'subscriptionStatus': return { kind: 'subscriptionStatus', equals: 'subscribed' }\n case 'hasTag': return { kind: 'hasTag', tag: '' }\n case 'notHasTag': return { kind: 'notHasTag', tag: '' }\n case 'fieldEquals': return { kind: 'fieldEquals', field: '', value: '' }\n case 'fieldIn': return { kind: 'fieldIn', field: '', values: [] }\n case 'fieldExists': return { kind: 'fieldExists', field: '' }\n case 'firedEvent': return { kind: 'firedEvent', eventName: '', withinDays: 30 }\n case 'notFiredEvent': return { kind: 'notFiredEvent', eventName: '', withinDays: 90 }\n case 'subscribedAfter': return { kind: 'subscribedAfter', date: new Date(Date.now() - 30 * 86_400_000) }\n case 'subscribedBefore': return { kind: 'subscribedBefore', date: new Date() }\n case 'opened': return { kind: 'opened', withinDays: 14 }\n case 'notOpened': return { kind: 'notOpened', withinDays: 14 }\n case 'any': return { kind: 'any', filters: [] }\n case 'not': return { kind: 'not', filter: { kind: 'hasTag', tag: '' } }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dedupe policies for event registration\n// ---------------------------------------------------------------------------\n\nexport interface DedupePolicyOption {\n value: 'once-per-contact' | 'once-per-day' | 'every-time'\n label: string\n description: string\n derivedKeyShape: string\n}\n\nexport const DEDUPE_POLICIES: readonly DedupePolicyOption[] = [\n {\n value: 'once-per-contact',\n label: 'Once per contact',\n description: 'Lifecycle markers (Created, Activated)',\n derivedKeyShape: '${externalId}:${eventName}',\n },\n {\n value: 'once-per-day',\n label: 'Once per day',\n description: 'Daily behaviors (Viewed Storyboard)',\n derivedKeyShape: '${externalId}:${eventName}:${YYYY-MM-DD}',\n },\n {\n value: 'every-time',\n label: 'Every time',\n description: 'True every-occurrence events (Imported)',\n derivedKeyShape: '${externalId}:${eventName}:${UUIDv4}',\n },\n] as const\n"]}
|