mailery 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +65 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +65 -30
- package/dist/index.js.map +1 -1
- package/dist/{null-DxTHQSrJ.d.cts → null-B3N6bTpc.d.cts} +33 -5
- package/dist/{null-DxTHQSrJ.d.ts → null-B3N6bTpc.d.ts} +33 -5
- package/dist/testing.cjs +63 -28
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -3
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +63 -28
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/testing.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Db } from 'mongodb';
|
|
2
|
-
import { C as ContactAdapter, a as Contact, A as AdapterFilter, b as AdapterSort, M as MailProvider, S as SendArgs, c as SendResult, N as NormalizedEvent, F as FlowStep,
|
|
3
|
-
export {
|
|
2
|
+
import { C as ContactAdapter, a as Contact, A as AdapterFilter, b as AdapterSort, M as MailProvider, S as SendArgs, c as SendResult, N as NormalizedEvent, F as FlowStep, a8 as FlowTrigger, r as FlowGoal, _ as TemplateKind, T as TemplateDoc, g as FlowDoc, D as DeliveryWindow, R as RunnerContext, e as Mailer, a9 as QueueDriverConfig } from './null-B3N6bTpc.cjs';
|
|
3
|
+
export { y as NullProvider } from './null-B3N6bTpc.cjs';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import 'handlebars';
|
|
6
6
|
import 'ioredis';
|
|
@@ -257,7 +257,7 @@ interface TestMailerOptions {
|
|
|
257
257
|
/** Call `mailer.startWorkers()` after init. Requires a non-noop `queue`. */
|
|
258
258
|
startWorkers?: boolean;
|
|
259
259
|
/** Override Mailer config (excluding required fields the harness fills in). */
|
|
260
|
-
config?: Partial<Omit<Parameters<typeof Mailer.init>[0], 'db' | 'adapter' | 'queue' | 'providers' | 'defaultProvider'>>;
|
|
260
|
+
config?: Partial<Omit<Parameters<typeof Mailer.init>[0], 'db' | 'mongo' | 'adapter' | 'queue' | 'providers' | 'defaultProvider'>>;
|
|
261
261
|
}
|
|
262
262
|
interface SeedContactOptions {
|
|
263
263
|
/** Also create a `subscribed` subscription row. Default true. */
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Db } from 'mongodb';
|
|
2
|
-
import { C as ContactAdapter, a as Contact, A as AdapterFilter, b as AdapterSort, M as MailProvider, S as SendArgs, c as SendResult, N as NormalizedEvent, F as FlowStep,
|
|
3
|
-
export {
|
|
2
|
+
import { C as ContactAdapter, a as Contact, A as AdapterFilter, b as AdapterSort, M as MailProvider, S as SendArgs, c as SendResult, N as NormalizedEvent, F as FlowStep, a8 as FlowTrigger, r as FlowGoal, _ as TemplateKind, T as TemplateDoc, g as FlowDoc, D as DeliveryWindow, R as RunnerContext, e as Mailer, a9 as QueueDriverConfig } from './null-B3N6bTpc.js';
|
|
3
|
+
export { y as NullProvider } from './null-B3N6bTpc.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import 'handlebars';
|
|
6
6
|
import 'ioredis';
|
|
@@ -257,7 +257,7 @@ interface TestMailerOptions {
|
|
|
257
257
|
/** Call `mailer.startWorkers()` after init. Requires a non-noop `queue`. */
|
|
258
258
|
startWorkers?: boolean;
|
|
259
259
|
/** Override Mailer config (excluding required fields the harness fills in). */
|
|
260
|
-
config?: Partial<Omit<Parameters<typeof Mailer.init>[0], 'db' | 'adapter' | 'queue' | 'providers' | 'defaultProvider'>>;
|
|
260
|
+
config?: Partial<Omit<Parameters<typeof Mailer.init>[0], 'db' | 'mongo' | 'adapter' | 'queue' | 'providers' | 'defaultProvider'>>;
|
|
261
261
|
}
|
|
262
262
|
interface SeedContactOptions {
|
|
263
263
|
/** Also create a `subscribed` subscription row. Default true. */
|
package/dist/testing.js
CHANGED
|
@@ -16125,7 +16125,7 @@ function derivePlaintext(html) {
|
|
|
16125
16125
|
var PLAIN_TEXT = { noEscape: true };
|
|
16126
16126
|
async function renderTemplate(template, ctx, opts = {}) {
|
|
16127
16127
|
const hb = makeHandlebars(opts.helpers);
|
|
16128
|
-
const subject = hb.compile(template.subject)(ctx);
|
|
16128
|
+
const subject = hb.compile(template.subject, PLAIN_TEXT)(ctx).replace(/[\r\n]+/g, " ");
|
|
16129
16129
|
const preheader = hb.compile(template.preheader)(ctx);
|
|
16130
16130
|
let html;
|
|
16131
16131
|
if (template.body.html) {
|
|
@@ -17510,7 +17510,7 @@ async function runDnsblChecks(ctx, opts = {}) {
|
|
|
17510
17510
|
let listedCount = 0;
|
|
17511
17511
|
async function processPair(p) {
|
|
17512
17512
|
const queryName = buildQueryName(p.target, p.targetKind, spamhausQueryHost(p.list.host, cfg.spamhausDqsKey));
|
|
17513
|
-
const lookup2 = queryName ? await queryDnsbl(resolver, queryName) : { result: "error", returnCodes: [], errorMessage: "unsupported target format" };
|
|
17513
|
+
const lookup2 = queryName ? await queryDnsbl(resolver, queryName, p.list.host) : { result: "error", returnCodes: [], errorMessage: "unsupported target format" };
|
|
17514
17514
|
if (lookup2.transient) return;
|
|
17515
17515
|
if (lookup2.result === "listed") listedCount++;
|
|
17516
17516
|
await ctx.collections.dnsblChecks.updateOne(
|
|
@@ -17571,10 +17571,10 @@ function buildQueryName(target, kind, listHost) {
|
|
|
17571
17571
|
return `${domain}.${listHost}`;
|
|
17572
17572
|
}
|
|
17573
17573
|
var TRANSIENT_DNS_CODES = /* @__PURE__ */ new Set(["ESERVFAIL", "EREFUSED", "ETIMEOUT", "ETIMEDOUT", "ECONNRESET", "ECONNREFUSED"]);
|
|
17574
|
-
async function queryDnsbl(resolver, query) {
|
|
17574
|
+
async function queryDnsbl(resolver, query, listHost) {
|
|
17575
17575
|
try {
|
|
17576
17576
|
const records = await resolver.resolve4(query);
|
|
17577
|
-
return interpretRecords(records);
|
|
17577
|
+
return interpretRecords(records, listHost);
|
|
17578
17578
|
} catch (err) {
|
|
17579
17579
|
const code = err?.code;
|
|
17580
17580
|
if (code === "ENOTFOUND" || code === "ENODATA") {
|
|
@@ -17600,10 +17600,17 @@ var REFUSAL_REASONS = {
|
|
|
17600
17600
|
"127.255.255.254": "queried through a public or shared DNS resolver, which Spamhaus blocks. Set dnsbl.spamhausDqsKey (free Spamhaus DQS key) or use a private resolver",
|
|
17601
17601
|
"127.255.255.255": "this resolver has exceeded the free query limit"
|
|
17602
17602
|
};
|
|
17603
|
-
function interpretRecords(records) {
|
|
17603
|
+
function interpretRecords(records, listHost) {
|
|
17604
17604
|
if (!records || records.length === 0) {
|
|
17605
17605
|
return { result: "clean", returnCodes: [], errorMessage: null };
|
|
17606
17606
|
}
|
|
17607
|
+
if (listHost && REGISTRABLE_ONLY_LISTS.has(listHost) && records.every((r) => r === "127.0.0.1")) {
|
|
17608
|
+
return {
|
|
17609
|
+
result: "error",
|
|
17610
|
+
returnCodes: records,
|
|
17611
|
+
errorMessage: `${listHost} refused the query (127.0.0.1): queried through a public or shared DNS resolver, or over the free query limit. Use a private resolver`
|
|
17612
|
+
};
|
|
17613
|
+
}
|
|
17607
17614
|
const errorish = records.filter((r) => r.startsWith("127.255.255."));
|
|
17608
17615
|
if (errorish.length === records.length) {
|
|
17609
17616
|
const reasons = [...new Set(records.map((r) => REFUSAL_REASONS[r] ?? "unrecognised refusal code"))];
|
|
@@ -18457,6 +18464,7 @@ async function processScheduledBroadcasts2(ctx) {
|
|
|
18457
18464
|
}
|
|
18458
18465
|
|
|
18459
18466
|
// src/server/mailer.ts
|
|
18467
|
+
var STORAGE_REQUIRED = "Mailer.init: give exactly one of `db` (an open Db) or `mongo` (a connection mailery opens)";
|
|
18460
18468
|
var Mailer = class _Mailer {
|
|
18461
18469
|
db;
|
|
18462
18470
|
collections;
|
|
@@ -18466,6 +18474,8 @@ var Mailer = class _Mailer {
|
|
|
18466
18474
|
config;
|
|
18467
18475
|
events;
|
|
18468
18476
|
queueDriver;
|
|
18477
|
+
/** The client `Mailer.init` opened from `config.mongo`; closed by `stop()`. Null when the host gave `db`. */
|
|
18478
|
+
ownedClient;
|
|
18469
18479
|
workersStarted = false;
|
|
18470
18480
|
runnerContext;
|
|
18471
18481
|
constructor(args) {
|
|
@@ -18475,6 +18485,7 @@ var Mailer = class _Mailer {
|
|
|
18475
18485
|
this.adapter = args.adapter;
|
|
18476
18486
|
this.providers = args.providers;
|
|
18477
18487
|
this.queueDriver = args.queueDriver;
|
|
18488
|
+
this.ownedClient = args.ownedClient;
|
|
18478
18489
|
this.queues = args.queueDriver.queues;
|
|
18479
18490
|
this.events = args.events;
|
|
18480
18491
|
this.runnerContext = {
|
|
@@ -18571,36 +18582,58 @@ var Mailer = class _Mailer {
|
|
|
18571
18582
|
});
|
|
18572
18583
|
}
|
|
18573
18584
|
static async init(input) {
|
|
18574
|
-
|
|
18575
|
-
if (!resolveProvider(
|
|
18585
|
+
if (input.db == null === (input.mongo == null)) throw new Error(STORAGE_REQUIRED);
|
|
18586
|
+
if (!resolveProvider(input.providers, input.defaultProvider)) {
|
|
18576
18587
|
throw new Error(
|
|
18577
|
-
`defaultProvider "${
|
|
18588
|
+
`defaultProvider "${input.defaultProvider}" is not a registered provider. Registered: ${registeredProviderNames(input.providers).join(", ") || "(none)"}`
|
|
18578
18589
|
);
|
|
18579
18590
|
}
|
|
18580
|
-
if (
|
|
18591
|
+
if (input.defaultTransactionalProvider != null && !resolveProvider(input.providers, input.defaultTransactionalProvider)) {
|
|
18581
18592
|
throw new Error(
|
|
18582
|
-
`defaultTransactionalProvider "${
|
|
18593
|
+
`defaultTransactionalProvider "${input.defaultTransactionalProvider}" is not a registered provider. Registered: ${registeredProviderNames(input.providers).join(", ") || "(none)"}`
|
|
18583
18594
|
);
|
|
18584
18595
|
}
|
|
18585
|
-
if (
|
|
18596
|
+
if (input.varsAdapter) {
|
|
18586
18597
|
const { assertNoReservedVarKeys: assertNoReservedVarKeys2 } = await Promise.resolve().then(() => (init_vars(), vars_exports));
|
|
18587
|
-
assertNoReservedVarKeys2(
|
|
18588
|
-
}
|
|
18589
|
-
|
|
18590
|
-
|
|
18591
|
-
|
|
18592
|
-
|
|
18593
|
-
await
|
|
18594
|
-
|
|
18595
|
-
|
|
18596
|
-
|
|
18597
|
-
|
|
18598
|
-
|
|
18599
|
-
|
|
18600
|
-
|
|
18601
|
-
|
|
18602
|
-
|
|
18603
|
-
|
|
18598
|
+
assertNoReservedVarKeys2(input.varsAdapter);
|
|
18599
|
+
}
|
|
18600
|
+
let ownedClient = null;
|
|
18601
|
+
let db;
|
|
18602
|
+
if (input.mongo) {
|
|
18603
|
+
const { MongoClient: MongoClient2 } = await import('mongodb');
|
|
18604
|
+
ownedClient = await MongoClient2.connect(input.mongo.uri, input.mongo.clientOptions);
|
|
18605
|
+
db = ownedClient.db(input.mongo.dbName);
|
|
18606
|
+
} else if (input.db) {
|
|
18607
|
+
db = input.db;
|
|
18608
|
+
} else {
|
|
18609
|
+
throw new Error(STORAGE_REQUIRED);
|
|
18610
|
+
}
|
|
18611
|
+
try {
|
|
18612
|
+
const config = resolveConfig({
|
|
18613
|
+
...input,
|
|
18614
|
+
db,
|
|
18615
|
+
adapter: typeof input.adapter === "function" ? input.adapter(db) : input.adapter
|
|
18616
|
+
});
|
|
18617
|
+
const collections = getCollections(config.db, config.collectionPrefix);
|
|
18618
|
+
await ensureIndexes(config.db, config.collectionPrefix);
|
|
18619
|
+
const queueDriver = await createQueueDriver(config.queue, config.db);
|
|
18620
|
+
if (!config.workerless && config.queue.driver !== "noop") {
|
|
18621
|
+
await queueDriver.scheduleRepeatingTick(config.tickIntervalSeconds);
|
|
18622
|
+
}
|
|
18623
|
+
return new _Mailer({
|
|
18624
|
+
config,
|
|
18625
|
+
db: config.db,
|
|
18626
|
+
collections,
|
|
18627
|
+
adapter: config.adapter,
|
|
18628
|
+
providers: config.providers,
|
|
18629
|
+
queueDriver,
|
|
18630
|
+
events: new EventRegistry(),
|
|
18631
|
+
ownedClient
|
|
18632
|
+
});
|
|
18633
|
+
} catch (err) {
|
|
18634
|
+
await ownedClient?.close();
|
|
18635
|
+
throw err;
|
|
18636
|
+
}
|
|
18604
18637
|
}
|
|
18605
18638
|
// -------------------------------------------------------------------------
|
|
18606
18639
|
// Event registration + firing
|
|
@@ -19073,6 +19106,8 @@ var Mailer = class _Mailer {
|
|
|
19073
19106
|
async stop() {
|
|
19074
19107
|
await this.queueDriver.close();
|
|
19075
19108
|
this.workersStarted = false;
|
|
19109
|
+
await this.ownedClient?.close();
|
|
19110
|
+
this.ownedClient = null;
|
|
19076
19111
|
}
|
|
19077
19112
|
/** Used internally by the admin router and tests; not part of the public API. */
|
|
19078
19113
|
getRunnerContext() {
|