@bumail/queue 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/chunks/{index-vg971acr.js → index-3pt7rc59.js} +8 -3
- package/dist/chunks/index-3pt7rc59.js.map +12 -0
- package/dist/contract/checks.d.ts.map +1 -1
- package/dist/contract/queue-store.d.ts +1 -0
- package/dist/contract/queue-store.d.ts.map +1 -1
- package/dist/contract/types.d.ts +9 -0
- package/dist/contract/types.d.ts.map +1 -1
- package/dist/index.js +31 -17
- package/dist/index.js.map +9 -9
- package/dist/memory/index.js +1 -1
- package/dist/postgres/index.js +1 -1
- package/dist/queue/attempt.d.ts.map +1 -1
- package/dist/queue/deliver.d.ts.map +1 -1
- package/dist/queue/events.d.ts +6 -0
- package/dist/queue/events.d.ts.map +1 -1
- package/dist/queue/fallback.d.ts +2 -1
- package/dist/queue/fallback.d.ts.map +1 -1
- package/dist/queue/notify.d.ts.map +1 -1
- package/dist/queue/outcome.d.ts.map +1 -1
- package/dist/queue/settle.d.ts.map +1 -1
- package/dist/redis/index.js +1 -1
- package/dist/sqlite/index.js +1 -1
- package/docs/guide.md +38 -9
- package/docs/roadmap.md +12 -0
- package/docs/troubleshooting.md +12 -4
- package/package.json +1 -1
- package/dist/chunks/index-vg971acr.js.map +0 -12
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ deferred recipient.
|
|
|
126
126
|
|
|
127
127
|
With `fallback` (a smarthost), a recipient whose session by MX failed by a
|
|
128
128
|
connection failure, a timeout or a reputation refusal goes through that
|
|
129
|
-
smarthost at once (not after the final dot of `DATA`, where the MX may have taken the message); see [Falling back to a smarthost](docs/guide.md#falling-back-to-a-smarthost).
|
|
129
|
+
smarthost at once (not after the final dot of `DATA`, where the MX may have taken the message: that recipient is marked `mayHaveReachedMx` and never falls back on its own); see [Falling back to a smarthost](docs/guide.md#falling-back-to-a-smarthost).
|
|
130
130
|
|
|
131
131
|
## Several workers
|
|
132
132
|
|
|
@@ -297,7 +297,7 @@ control character in it.
|
|
|
297
297
|
| `createQueue(options)`, `Queue` | the queue: `enqueue`, `deliverDue`, `start`, `stop`, `on`, `list`, `get`, `retryNow`, `cancel`, `owner` |
|
|
298
298
|
| `QueueOptions` (`route`, `routes`, `fallback`), `Route`, `Smarthost`, `RetrySchedule`, `DsnOptions`, `QueueLimits`, `Clock`, `Sender` | what `createQueue` takes |
|
|
299
299
|
| `MessageSource`, `QueueEnvelope` | what `enqueue` takes |
|
|
300
|
-
| `QueueEvents`, `QueueListener`, `RecipientEvent` (`route`, `fallback`, `mxReply`), `DeferredEvent`, `DsnEvent`, `QueueErrorEvent` | the events |
|
|
300
|
+
| `QueueEvents`, `QueueListener`, `RecipientEvent` (`route`, `fallback`, `mxReply`, `mayHaveReachedMx`), `DeferredEvent`, `DsnEvent`, `QueueErrorEvent` | the events |
|
|
301
301
|
| `QueueStore` | the contract a store answers: `add`, `get`, `list`, `count`, `readMessage`, `claim`, `renew`, `complete`, `reschedule`, `cancel` |
|
|
302
302
|
| `QueueItem`, `RecipientState`, `RecipientStatus`, `FinalStatus`, `Diagnostic`, `Lease` | an item, and where each recipient stands |
|
|
303
303
|
| `NewQueueItem`, `AddOptions`, `ClaimRequest`, `AttemptResult`, `RecipientUpdate`, `QueueListOptions` | what a store takes |
|
|
@@ -58,6 +58,10 @@ function checkOwner(owner) {
|
|
|
58
58
|
}
|
|
59
59
|
function checkUpdate(update) {
|
|
60
60
|
checkStorable("A recipient", update.address);
|
|
61
|
+
const mark = update.mayHaveReachedMx;
|
|
62
|
+
if (mark !== undefined && mark !== true) {
|
|
63
|
+
throw invalid("mayHaveReachedMx must be true or absent");
|
|
64
|
+
}
|
|
61
65
|
const reply = update.reply;
|
|
62
66
|
if (reply === undefined)
|
|
63
67
|
return;
|
|
@@ -151,7 +155,8 @@ function applyAttempt(item, result) {
|
|
|
151
155
|
address: r.address,
|
|
152
156
|
status: update.status,
|
|
153
157
|
...update.reply ? { reply: update.reply } : {},
|
|
154
|
-
updatedAt: result.now
|
|
158
|
+
updatedAt: result.now,
|
|
159
|
+
...r.mayHaveReachedMx || update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {}
|
|
155
160
|
};
|
|
156
161
|
});
|
|
157
162
|
const { lease: _, ...rest } = item;
|
|
@@ -179,5 +184,5 @@ var claimable = (item, now) => item.nextAttemptAt <= now && (item.lease === unde
|
|
|
179
184
|
|
|
180
185
|
export { QueueError2, invalid, hasControl, replaceControls, cleanText, isStorable, asciiText, checkTime, checkOwner, checkNewItem, checkMaxItems, checkClaim, checkResult, checkList, isDone, applyAttempt, newItem, claimable };
|
|
181
186
|
|
|
182
|
-
//# debugId=
|
|
183
|
-
//# sourceMappingURL=index-
|
|
187
|
+
//# debugId=8430FF293E3942D164756E2164756E21
|
|
188
|
+
//# sourceMappingURL=index-3pt7rc59.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/errors.ts", "../src/text.ts", "../src/contract/checks.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Why the queue or a store refused a call. `INVALID`: an option or an\n * argument it cannot take. `MESSAGE_TOO_BIG`, `TOO_MANY_RECIPIENTS` and\n * `QUEUE_FULL`: a limit `enqueue` enforces. `CLOSED`: a store used after\n * `close()`. `LEASE_LOST`: given to the `error` event when another worker\n * took an item before its outcome was recorded — or, once the lease's\n * expiry passed, when the item is gone: lost or cancelled.\n * `MESSAGE_UNREADABLE`: given to the `error` event when the store holds an\n * item but not its message, whose pending recipients then fail.\n */\nexport type QueueErrorCode =\n\t| 'INVALID'\n\t| 'MESSAGE_TOO_BIG'\n\t| 'TOO_MANY_RECIPIENTS'\n\t| 'QUEUE_FULL'\n\t| 'CLOSED'\n\t| 'LEASE_LOST'\n\t| 'MESSAGE_UNREADABLE';\n\n/** Thrown by the queue and by every store, whichever answers the contract, with the same codes. */\nexport class QueueError extends Error {\n\toverride readonly name = 'QueueError';\n\treadonly code: QueueErrorCode;\n\n\tconstructor(code: QueueErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n}\n\n/** `INVALID`, for an option or an argument. */\nexport const invalid = (message: string) => new QueueError('INVALID', message);\n",
|
|
6
|
+
"/** Text from the other side, made safe to keep and to write in a header field. */\n\n/** C0, DEL and C1: every control character, CR, LF and TAB included. */\nconst isControl = (code: number) =>\n\tcode < 0x20 || (code >= 0x7f && code <= 0x9f);\n\n/** Whether the text holds a control character. */\nexport function hasControl(text: string): boolean {\n\tfor (let i = 0; i < text.length; i++) {\n\t\tif (isControl(text.charCodeAt(i))) return true;\n\t}\n\treturn false;\n}\n\n/** Each control character replaced by `by`. */\nexport function replaceControls(text: string, by: string): string {\n\tlet out = '';\n\tfor (let i = 0; i < text.length; i++) {\n\t\tout += isControl(text.charCodeAt(i)) ? by : (text[i] as string);\n\t}\n\treturn out;\n}\n\n/**\n * Every control character (CR and LF included) as a space, a lone\n * surrogate as U+FFFD, runs of space as one, cut at `max` characters with\n * `...`, never inside a surrogate pair: what a reply leaves in an item,\n * an event and a DSN.\n */\nexport function cleanText(text: string, max: number): string {\n\tconst clean = replaceControls(text.toWellFormed(), ' ')\n\t\t.replace(/ {2,}/g, ' ')\n\t\t.trim();\n\treturn clean.length > max ? `${cut(clean, max - 3)}...` : clean;\n}\n\n/**\n * The first `length` UTF-16 units, never ending inside a surrogate pair:\n * a lone surrogate is text no store can keep (PostgreSQL's `jsonb` refuses\n * it), nor any UTF-8 encode.\n */\nfunction cut(text: string, length: number): string {\n\tconst head = text.slice(0, length);\n\tconst last = head.charCodeAt(head.length - 1);\n\treturn last >= 0xd800 && last <= 0xdbff ? head.slice(0, -1) : head;\n}\n\n/**\n * Text every store can keep: no NUL (PostgreSQL's `text` and `jsonb` hold\n * none) and no lone surrogate. `cleanText`'s output always is.\n */\nexport const isStorable = (text: string): boolean =>\n\ttext.isWellFormed() && !text.includes('\\0');\n\n/** `cleanText`, then anything not printable ASCII as `?`: for a `message/delivery-status` field. */\nexport const asciiText = (text: string, max: number): string =>\n\tcleanText(text, max).replace(/[^ -~]/g, '?');\n",
|
|
7
|
+
"import { invalid } from '../errors';\nimport { isStorable } from '../text';\nimport type {\n\tAttemptResult,\n\tClaimRequest,\n\tDiagnostic,\n\tNewQueueItem,\n\tQueueItem,\n\tQueueListOptions,\n\tRecipientState,\n\tRecipientUpdate,\n} from './types';\n\n/** What every store checks the same way, so each refuses the same input with the same error. */\n\nconst isTime = (value: unknown): value is number =>\n\ttypeof value === 'number' && Number.isFinite(value);\n\n/** A time in milliseconds since the epoch, or `INVALID` naming it. */\nexport function checkTime(name: string, value: unknown): number {\n\tif (!isTime(value)) throw invalid(`${name} must be a finite number`);\n\treturn value;\n}\n\n/**\n * Text a store keeps: refused, the same way by every store, when it holds\n * a NUL or a lone surrogate, which PostgreSQL cannot keep and no UTF-8\n * encode can carry.\n */\nexport function checkStorable(name: string, text: string): void {\n\tif (!isStorable(text)) {\n\t\tthrow invalid(\n\t\t\t`${name} holds a NUL or a lone surrogate, which a store cannot keep`,\n\t\t);\n\t}\n}\n\n/** A lease owner: a non-empty string. */\nexport function checkOwner(owner: unknown): string {\n\tif (typeof owner !== 'string' || owner === '') {\n\t\tthrow invalid('owner must be a non-empty string');\n\t}\n\tcheckStorable('owner', owner);\n\treturn owner;\n}\n\n/** Every text of a recipient's outcome. */\nfunction checkUpdate(update: RecipientUpdate): void {\n\tcheckStorable('A recipient', update.address);\n\tconst mark = update.mayHaveReachedMx as unknown;\n\tif (mark !== undefined && mark !== true) {\n\t\tthrow invalid('mayHaveReachedMx must be true or absent');\n\t}\n\tconst reply = update.reply as Partial<Diagnostic> | undefined;\n\tif (reply === undefined) return;\n\tif (\n\t\ttypeof reply !== 'object' ||\n\t\treply === null ||\n\t\ttypeof reply.text !== 'string'\n\t) {\n\t\tthrow invalid('A reply is an object with a text');\n\t}\n\tcheckStorable('reply.text', reply.text);\n\tfor (const name of ['status', 'host'] as const) {\n\t\tconst value = reply[name];\n\t\tif (value === undefined) continue;\n\t\tif (typeof value !== 'string')\n\t\t\tthrow invalid(`reply.${name} must be a string`);\n\t\tcheckStorable(`reply.${name}`, value);\n\t}\n}\n\nexport function checkNewItem(item: NewQueueItem): void {\n\tif (typeof item !== 'object' || item === null) {\n\t\tthrow invalid('A new item is an object');\n\t}\n\tif (typeof item.from !== 'string') throw invalid('from must be a string');\n\tcheckStorable('from', item.from);\n\tconst to = item.to as unknown;\n\tif (\n\t\t!Array.isArray(to) ||\n\t\tto.length === 0 ||\n\t\t!to.every((a) => typeof a === 'string' && a !== '')\n\t) {\n\t\tthrow invalid('to must be a non-empty array of addresses');\n\t}\n\tfor (const address of to as string[]) checkStorable('A recipient', address);\n\tif (!(item.message instanceof Uint8Array)) {\n\t\tthrow invalid('message must be a Uint8Array');\n\t}\n\tcheckTime('createdAt', item.createdAt);\n}\n\n/** `maxItems`: a positive integer, or nothing. */\nexport function checkMaxItems(max: unknown): number | undefined {\n\tif (max === undefined) return undefined;\n\tif (typeof max !== 'number' || !Number.isInteger(max) || max < 1) {\n\t\tthrow invalid(`maxItems must be an integer of at least 1, not ${max}`);\n\t}\n\treturn max;\n}\n\nexport function checkClaim(request: ClaimRequest): void {\n\tif (typeof request !== 'object' || request === null) {\n\t\tthrow invalid('A claim is an object');\n\t}\n\tcheckOwner(request.owner);\n\tcheckTime('now', request.now);\n\tif (!isTime(request.leaseMs) || request.leaseMs <= 0) {\n\t\tthrow invalid('leaseMs must be a positive number');\n\t}\n}\n\nexport function checkResult(result: AttemptResult): void {\n\tif (typeof result !== 'object' || result === null) {\n\t\tthrow invalid('An attempt result is an object');\n\t}\n\tcheckTime('now', result.now);\n\tcheckTime('nextAttemptAt', result.nextAttemptAt);\n\tif (!Number.isInteger(result.attempts) || result.attempts < 0) {\n\t\tthrow invalid('attempts must be an integer of at least 0');\n\t}\n\tif (typeof result.delayNotified !== 'boolean') {\n\t\tthrow invalid('delayNotified must be true or false');\n\t}\n\tconst statuses = ['delivered', 'deferred', 'failed'];\n\tif (\n\t\t!Array.isArray(result.recipients) ||\n\t\t!result.recipients.every(\n\t\t\t(u) => typeof u?.address === 'string' && statuses.includes(u.status),\n\t\t)\n\t) {\n\t\tthrow invalid(\n\t\t\t'recipients must be an array of { address, status: delivered, deferred or failed }',\n\t\t);\n\t}\n\tfor (const update of result.recipients) checkUpdate(update);\n}\n\n/** The offset and limit of a list: integers, the limit 1 to 1000. */\nexport function checkList(options: QueueListOptions = {}): {\n\toffset: number;\n\tlimit: number;\n} {\n\tconst offset = options.offset ?? 0;\n\tconst limit = options.limit ?? 100;\n\tif (!Number.isInteger(offset) || offset < 0) {\n\t\tthrow invalid(`offset must be an integer of at least 0, not ${offset}`);\n\t}\n\tif (!Number.isInteger(limit) || limit < 1 || limit > 1000) {\n\t\tthrow invalid(`limit must be an integer from 1 to 1000, not ${limit}`);\n\t}\n\treturn { offset, limit };\n}\n\n/** Every recipient is `delivered` or `failed`. */\nexport const isDone = (item: Pick<QueueItem, 'recipients'>): boolean =>\n\titem.recipients.every(\n\t\t(r) => r.status === 'delivered' || r.status === 'failed',\n\t);\n\n/**\n * The item once an attempt is recorded: its recipients' outcomes, a final\n * state never changed again, the schedule, and no lease.\n */\nexport function applyAttempt(\n\titem: QueueItem,\n\tresult: AttemptResult,\n): QueueItem {\n\tconst updates = new Map(result.recipients.map((u) => [u.address, u]));\n\tconst recipients = item.recipients.map((r): RecipientState => {\n\t\tconst update = updates.get(r.address);\n\t\tif (!update || r.status === 'delivered' || r.status === 'failed') return r;\n\t\treturn {\n\t\t\taddress: r.address,\n\t\t\tstatus: update.status,\n\t\t\t...(update.reply ? { reply: update.reply } : {}),\n\t\t\tupdatedAt: result.now,\n\t\t\t...(r.mayHaveReachedMx || update.mayHaveReachedMx\n\t\t\t\t? { mayHaveReachedMx: true as const }\n\t\t\t\t: {}),\n\t\t};\n\t});\n\tconst { lease: _, ...rest } = item;\n\treturn {\n\t\t...rest,\n\t\trecipients,\n\t\tnextAttemptAt: result.nextAttemptAt,\n\t\tattempts: result.attempts,\n\t\tdelayNotified: result.delayNotified,\n\t};\n}\n\n/** A new item as a store first keeps it. */\nexport function newItem(id: string, item: NewQueueItem): QueueItem {\n\treturn {\n\t\tid,\n\t\tfrom: item.from,\n\t\trecipients: item.to.map((address) => ({ address, status: 'pending' })),\n\t\tsize: item.message.length,\n\t\tcreatedAt: item.createdAt,\n\t\tnextAttemptAt: item.createdAt,\n\t\tattempts: 0,\n\t\tdelayNotified: false,\n\t};\n}\n\n/** Whether a lease, if any, leaves the item free to claim at `now`. */\nexport const claimable = (item: QueueItem, now: number): boolean =>\n\titem.nextAttemptAt <= now &&\n\t(item.lease === undefined || item.lease.expiresAt <= now);\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "8430FF293E3942D164756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/contract/checks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EAEZ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAGhB,MAAM,SAAS,CAAC;AAOjB,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAG9D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM9D;AAED,yCAAyC;AACzC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMjD;
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/contract/checks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EAEZ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAGhB,MAAM,SAAS,CAAC;AAOjB,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAG9D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM9D;AAED,yCAAyC;AACzC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMjD;AA4BD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAmBrD;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAM9D;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAStD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAwBvD;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd,CAUA;AAED,kDAAkD;AAClD,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,KAAG,OAG3D,CAAC;AAEH;;;GAGG;AACH,wBAAgB,YAAY,CAC3B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,aAAa,GACnB,SAAS,CAuBX;AAED,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,CAWjE;AAED,uEAAuE;AACvE,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,EAAE,KAAK,MAAM,KAAG,OAEC,CAAC"}
|
|
@@ -51,6 +51,7 @@ export interface QueueStore {
|
|
|
51
51
|
* count, and lets go of the lease — in one step, while `owner` holds it.
|
|
52
52
|
* Returns the item as it now stands, done (every recipient final, and
|
|
53
53
|
* the item dropped) or not; `undefined` when `owner` no longer holds it.
|
|
54
|
+
* A recipient's `mayHaveReachedMx` mark, once recorded, is kept.
|
|
54
55
|
*/
|
|
55
56
|
complete(id: string, owner: string, result: AttemptResult): Promise<QueueItem | undefined>;
|
|
56
57
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue-store.d.ts","sourceRoot":"","sources":["../../src/contract/queue-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAU;IAC1B;;;;;;OAMG;IACH,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAElE,gGAAgG;IAChG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEhD,0DAA0D;IAC1D,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAEvD,sCAAsC;IACtC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAEzD;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAE7D;;;OAGG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtE
|
|
1
|
+
{"version":3,"file":"queue-store.d.ts","sourceRoot":"","sources":["../../src/contract/queue-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAU;IAC1B;;;;;;OAMG;IACH,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAElE,gGAAgG;IAChG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEhD,0DAA0D;IAC1D,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAEvD,sCAAsC;IACtC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAEzD;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAE7D;;;OAGG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtE;;;;;;OAMG;IACH,QAAQ,CACP,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa,GACnB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAElC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErE,0FAA0F;IAC1F,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;CACnD"}
|
package/dist/contract/types.d.ts
CHANGED
|
@@ -29,6 +29,13 @@ export interface RecipientState {
|
|
|
29
29
|
readonly reply?: Diagnostic;
|
|
30
30
|
/** When the status last changed, in milliseconds since the epoch. */
|
|
31
31
|
readonly updatedAt?: number;
|
|
32
|
+
/**
|
|
33
|
+
* `true` once a session by MX ended after the final dot with no reply:
|
|
34
|
+
* the receiving server may hold a copy. Absent while nothing says so,
|
|
35
|
+
* never `false`. The queue then never falls back to a smarthost for this
|
|
36
|
+
* recipient on its own; once recorded, the mark is kept.
|
|
37
|
+
*/
|
|
38
|
+
readonly mayHaveReachedMx?: true;
|
|
32
39
|
}
|
|
33
40
|
/** Who is delivering an item, until when. */
|
|
34
41
|
export interface Lease {
|
|
@@ -82,6 +89,8 @@ export interface RecipientUpdate {
|
|
|
82
89
|
readonly address: string;
|
|
83
90
|
readonly status: Exclude<RecipientStatus, 'pending'>;
|
|
84
91
|
readonly reply?: Diagnostic;
|
|
92
|
+
/** Marks the recipient `mayHaveReachedMx`; `true` or absent, any other value is `INVALID`. */
|
|
93
|
+
readonly mayHaveReachedMx?: true;
|
|
85
94
|
}
|
|
86
95
|
/** What `complete` records: the attempt's outcomes, and when to try again. */
|
|
87
96
|
export interface AttemptResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/contract/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE9E,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/contract/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
cleanText,
|
|
7
7
|
asciiText,
|
|
8
8
|
checkOwner
|
|
9
|
-
} from "./chunks/index-
|
|
9
|
+
} from "./chunks/index-3pt7rc59.js";
|
|
10
10
|
// src/queue/envelope.ts
|
|
11
11
|
import { isMailbox } from "@bumail/smtp/client";
|
|
12
12
|
var ADDRESS = /^[^\s<>]{1,64}@[^\s<>@]{1,253}$/u;
|
|
@@ -445,6 +445,7 @@ var badAddress = (address) => ({
|
|
|
445
445
|
text: "The address is not one SMTP can carry"
|
|
446
446
|
}
|
|
447
447
|
});
|
|
448
|
+
var marked = (u) => u.status === "delivered" ? u : { ...u, mayHaveReachedMx: true };
|
|
448
449
|
async function session(ctx, item, message, domain, group, route, override) {
|
|
449
450
|
const { settings } = ctx;
|
|
450
451
|
const max = settings.limits.maxReplyText;
|
|
@@ -455,10 +456,9 @@ async function session(ctx, item, message, domain, group, route, override) {
|
|
|
455
456
|
} catch (error) {
|
|
456
457
|
if (isRouteError(error))
|
|
457
458
|
ctx.events.emit("error", { error, id: item.id });
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
};
|
|
459
|
+
const updates = outcomesOfError(error, group, max, hostOf(route));
|
|
460
|
+
const doubt = route === "mx" && isSmtpError(error) && error.afterData;
|
|
461
|
+
return { updates: doubt ? updates.map(marked) : updates, error };
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
464
|
function merged(mx, fb) {
|
|
@@ -480,8 +480,9 @@ async function attemptGroup(ctx, item, message, domain, recipients, used) {
|
|
|
480
480
|
const first = await session(ctx, item, message, domain, group, route);
|
|
481
481
|
let updates = first.updates;
|
|
482
482
|
const { fallback } = settings.options;
|
|
483
|
+
const doubtful = new Set(item.recipients.filter((r) => r.mayHaveReachedMx).map((r) => r.address));
|
|
483
484
|
if (fallback !== undefined && route === "mx") {
|
|
484
|
-
const mx = new Map(updates.filter((u) => u.status !== "delivered" && fallsBack(u.reply, first.error)).map((u) => [u.address, u]));
|
|
485
|
+
const mx = new Map(updates.filter((u) => u.status !== "delivered" && !u.mayHaveReachedMx && !doubtful.has(u.address) && fallsBack(u.reply, first.error)).map((u) => [u.address, u]));
|
|
485
486
|
if (mx.size > 0) {
|
|
486
487
|
const again = [...mx.keys()];
|
|
487
488
|
const second = await session(ctx, item, message, domain, again, fallback, fallback);
|
|
@@ -754,6 +755,16 @@ function nextAttemptAt(createdAt, now, attempts, retry, random) {
|
|
|
754
755
|
}
|
|
755
756
|
|
|
756
757
|
// src/queue/notify.ts
|
|
758
|
+
var MAY_HAVE_REACHED = "An earlier attempt may have reached the receiving server, so the message may have been delivered.";
|
|
759
|
+
function reported(r, kind) {
|
|
760
|
+
if (kind !== "failed" || !r.mayHaveReachedMx)
|
|
761
|
+
return r.reply;
|
|
762
|
+
const reply = r.reply ?? { text: "" };
|
|
763
|
+
return {
|
|
764
|
+
...reply,
|
|
765
|
+
text: reply.text === "" ? MAY_HAVE_REACHED : `${reply.text} ${MAY_HAVE_REACHED}`
|
|
766
|
+
};
|
|
767
|
+
}
|
|
757
768
|
async function notify(ctx, item, message, kind, recipients, now) {
|
|
758
769
|
if (item.from === "" || recipients.length === 0)
|
|
759
770
|
return;
|
|
@@ -767,11 +778,10 @@ async function notify(ctx, item, message, kind, recipients, now) {
|
|
|
767
778
|
to: item.from,
|
|
768
779
|
arrival: new Date(item.createdAt),
|
|
769
780
|
date: lastAttempt,
|
|
770
|
-
recipients: recipients.map((r) =>
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
})),
|
|
781
|
+
recipients: recipients.map((r) => {
|
|
782
|
+
const reply = reported(r, kind);
|
|
783
|
+
return { address: r.address, ...reply ? { reply } : {}, lastAttempt };
|
|
784
|
+
}),
|
|
775
785
|
...kind === "delayed" ? { willRetryUntil: new Date(giveUpAt(item.createdAt, settings.retry)) } : {},
|
|
776
786
|
...message ? { original: message } : {},
|
|
777
787
|
returnContent: settings.dsn.returnContent,
|
|
@@ -800,13 +810,15 @@ function expired(update) {
|
|
|
800
810
|
return {
|
|
801
811
|
address: update.address,
|
|
802
812
|
status: "failed",
|
|
803
|
-
reply: { text: "", ...update.reply, status: "4.4.7" }
|
|
813
|
+
reply: { text: "", ...update.reply, status: "4.4.7" },
|
|
814
|
+
...update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {}
|
|
804
815
|
};
|
|
805
816
|
}
|
|
806
817
|
function settle(item, updates, skipped, now, settings) {
|
|
807
818
|
const attempts = item.attempts + (updates.length > 0 ? 1 : 0);
|
|
808
819
|
const next = nextAttemptAt(item.createdAt, now, attempts, settings.retry, settings.random);
|
|
809
|
-
const
|
|
820
|
+
const doubtful = new Set(item.recipients.filter((r) => r.mayHaveReachedMx).map((r) => r.address));
|
|
821
|
+
const all = updates.map((u) => doubtful.has(u.address) && u.status !== "delivered" ? { ...u, mayHaveReachedMx: true } : u).map((u) => u.status === "deferred" && next === undefined ? expired(u) : u);
|
|
810
822
|
const deferred = all.filter((u) => u.status === "deferred");
|
|
811
823
|
const { delayAfter } = settings.dsn;
|
|
812
824
|
const delayDsn = !item.delayNotified && item.from !== "" && delayAfter !== false && deferred.length > 0 && now - item.createdAt >= delayAfter;
|
|
@@ -868,13 +880,15 @@ function emitOutcomes(events, item, settled, used) {
|
|
|
868
880
|
attempts,
|
|
869
881
|
...used.get(u.address)
|
|
870
882
|
});
|
|
883
|
+
const marked = (u) => u.mayHaveReachedMx ? { mayHaveReachedMx: true } : {};
|
|
871
884
|
for (const u of settled.delivered)
|
|
872
885
|
events.emit("delivered", base(u));
|
|
873
886
|
for (const u of settled.deferred) {
|
|
874
|
-
events.emit("deferred", { ...base(u), nextAttemptAt });
|
|
887
|
+
events.emit("deferred", { ...base(u), ...marked(u), nextAttemptAt });
|
|
888
|
+
}
|
|
889
|
+
for (const u of settled.failed) {
|
|
890
|
+
events.emit("failed", { ...base(u), ...marked(u) });
|
|
875
891
|
}
|
|
876
|
-
for (const u of settled.failed)
|
|
877
|
-
events.emit("failed", base(u));
|
|
878
892
|
}
|
|
879
893
|
async function deliverItem(ctx, item) {
|
|
880
894
|
const { store } = ctx;
|
|
@@ -1224,5 +1238,5 @@ export {
|
|
|
1224
1238
|
createQueue
|
|
1225
1239
|
};
|
|
1226
1240
|
|
|
1227
|
-
//# debugId=
|
|
1241
|
+
//# debugId=CD3446FD48B7ED9C64756E2164756E21
|
|
1228
1242
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -3,30 +3,30 @@
|
|
|
3
3
|
"sources": ["../src/queue/envelope.ts", "../src/queue/events.ts", "../src/queue/settings/index.ts", "../src/queue/settings/numbers.ts", "../src/queue/settings/dsn.ts", "../src/queue/settings/limits.ts", "../src/queue/settings/sessions.ts", "../src/queue/settings/routes.ts", "../src/queue/deliver.ts", "../src/queue/attempt.ts", "../src/queue/outcome.ts", "../src/queue/fallback.ts", "../src/queue/route.ts", "../src/dsn/build.ts", "../src/dsn/content.ts", "../src/dsn/fields.ts", "../src/queue/retry.ts", "../src/queue/notify.ts", "../src/queue/settle.ts", "../src/queue/lease.ts", "../src/queue/limiter.ts", "../src/queue/worker.ts", "../src/queue/queue.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import { isMailbox } from '@bumail/smtp/client';\nimport { invalid, QueueError } from '../errors';\nimport { hasControl } from '../text';\n\n/** What `enqueue` takes as the message: its bytes, its text, or a stream of it. */\nexport type MessageSource = Uint8Array | string | ReadableStream<Uint8Array>;\n\n/** The SMTP envelope of a message to send. */\nexport interface QueueEnvelope {\n\t/** The reverse-path, `local@domain`; `''` for the null sender (a bounce of your own). */\n\treadonly from: string;\n\t/** One recipient or more, `local@domain` each. */\n\treadonly to: string | readonly string[];\n}\n\n/**\n * An address as SMTP carries it: a local part, `@`, a domain, 254\n * characters at most (RFC 5321 §4.5.3.1.3's path, less its brackets), with\n * no space, no control character and no angle bracket, so it can never\n * break a command line or a header field — and one `sendMail` takes\n * (`isMailbox`, RFC 5321's grammar), so it is refused here, never at\n * delivery, where it would fail its whole domain's group.\n */\nconst ADDRESS = /^[^\\s<>]{1,64}@[^\\s<>@]{1,253}$/u;\n\nexport function checkAddress(name: string, address: unknown): string {\n\tif (\n\t\ttypeof address !== 'string' ||\n\t\taddress.length > 254 ||\n\t\thasControl(address) ||\n\t\t!ADDRESS.test(address) ||\n\t\t!isMailbox(address)\n\t) {\n\t\tthrow invalid(\n\t\t\t`${name} must be an address, local@domain, not ${JSON.stringify(address)}`,\n\t\t);\n\t}\n\treturn address;\n}\n\n/** The recipient's domain, in lowercase: what deliveries are grouped by. */\nexport const domainOf = (address: string) =>\n\taddress.slice(address.lastIndexOf('@') + 1).toLowerCase();\n\n/** The envelope, checked: the sender, and each recipient once, at most `maxRecipients`. */\nexport function checkEnvelope(\n\tenvelope: QueueEnvelope,\n\tmaxRecipients: number,\n): { from: string; to: string[] } {\n\tif (typeof envelope !== 'object' || envelope === null) {\n\t\tthrow invalid('The envelope is an object: { from, to }');\n\t}\n\tconst from = envelope.from === '' ? '' : checkAddress('from', envelope.from);\n\tconst list = typeof envelope.to === 'string' ? [envelope.to] : envelope.to;\n\tif (!Array.isArray(list) || list.length === 0) {\n\t\tthrow invalid('to must hold one recipient or more');\n\t}\n\tconst seen = new Set<string>();\n\tconst to: string[] = [];\n\tfor (const address of list) {\n\t\tcheckAddress('Each recipient', address);\n\t\tconst key = `${address.slice(0, address.lastIndexOf('@'))}@${domainOf(address)}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tto.push(address);\n\t}\n\tif (to.length > maxRecipients) {\n\t\tthrow new QueueError(\n\t\t\t'TOO_MANY_RECIPIENTS',\n\t\t\t`The message has ${to.length} recipients; the limit is ${maxRecipients}`,\n\t\t);\n\t}\n\treturn { from, to };\n}\n\nconst tooBig = (max: number) =>\n\tnew QueueError(\n\t\t'MESSAGE_TOO_BIG',\n\t\t`The message is larger than the limit of ${max} bytes`,\n\t);\n\nconst CR = 0x0d;\nconst LF = 0x0a;\n\n/**\n * Refuses a message with a CR not followed by an LF, or an LF not after a\n * CR: `sendMail` would refuse it at delivery (`BARE_LINE_BREAK`, SMTP\n * smuggling), failing every recipient.\n */\nexport function checkLineEnds(bytes: Uint8Array): void {\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tconst byte = bytes[i];\n\t\tconst bare =\n\t\t\tbyte === CR\n\t\t\t\t? bytes[i + 1] !== LF\n\t\t\t\t: byte === LF && (i === 0 || bytes[i - 1] !== CR);\n\t\tif (bare) {\n\t\t\tthrow invalid(\n\t\t\t\t`The message has a bare CR or LF at byte ${i}: every line must end in CRLF`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** The message's bytes, read to its end but never past `max`: past it, `MESSAGE_TOO_BIG`. */\nexport async function readMessage(\n\tsource: MessageSource,\n\tmax: number,\n): Promise<Uint8Array> {\n\tif (typeof source === 'string') source = new TextEncoder().encode(source);\n\tif (source instanceof Uint8Array) {\n\t\tif (source.length > max) throw tooBig(max);\n\t\treturn source.slice();\n\t}\n\tif (!(source instanceof ReadableStream)) {\n\t\tthrow invalid(\n\t\t\t'The message is a Uint8Array, a string or a ReadableStream<Uint8Array>',\n\t\t);\n\t}\n\tconst chunks: Uint8Array[] = [];\n\tlet size = 0;\n\tconst reader = source.getReader();\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tif (!(value instanceof Uint8Array)) {\n\t\t\t\tthrow invalid('The message stream must give Uint8Array chunks');\n\t\t\t}\n\t\t\tsize += value.length;\n\t\t\tif (size > max) throw tooBig(max);\n\t\t\tchunks.push(value);\n\t\t}\n\t} catch (error) {\n\t\tawait reader.cancel().catch(() => {});\n\t\tthrow error;\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\tconst bytes = new Uint8Array(size);\n\tlet at = 0;\n\tfor (const chunk of chunks) {\n\t\tbytes.set(chunk, at);\n\t\tat += chunk.length;\n\t}\n\treturn bytes;\n}\n",
|
|
6
|
-
"import type { Diagnostic } from '../contract/types';\n\n/** One recipient's outcome. */\nexport interface RecipientEvent {\n\t/** The item's id. */\n\treadonly id: string;\n\treadonly from: string;\n\treadonly recipient: string;\n\t/** What the other side said, or why nobody said anything. */\n\treadonly reply?: Diagnostic;\n\t/** The attempts made so far, this one included. */\n\treadonly attempts: number;\n\t/**\n\t * The route of this recipient's last session: `'mx'`, or `'smarthost'`\n\t * for a smarthost, a host of a route, or the fallback.\n\t */\n\treadonly route?: 'mx' | 'smarthost';\n\t/** `true` when that session was the fallback, after the one by MX failed. */\n\treadonly fallback?: true;\n\t/**\n\t * With `fallback`, what the MX side said (or why nobody said anything)\n\t * before the smarthost took over: `reply` is the smarthost's.\n\t */\n\treadonly mxReply?: Diagnostic;\n}\n\nexport interface DeferredEvent extends RecipientEvent {\n\t/** When the recipient is tried again, in milliseconds since the epoch. */\n\treadonly nextAttemptAt: number;\n}\n\n/** A DSN, enqueued back to the sender. */\nexport interface DsnEvent {\n\treadonly kind: 'delayed' | 'failed';\n\t/** The DSN's own item id. */\n\treadonly id: string;\n\t/** The id of the item it reports on. */\n\treadonly of: string;\n\t/** The original's sender, to whom it goes. */\n\treadonly to: string;\n\treadonly recipients: readonly string[];\n}\n\n/** A failure of the queue itself: the store, a DSN that could not be enqueued, a lease lost. */\nexport interface QueueErrorEvent {\n\treadonly error: unknown;\n\t/** The item it happened to, if any. */\n\treadonly id?: string;\n}\n\nexport interface QueueEvents {\n\tdelivered: RecipientEvent;\n\tdeferred: DeferredEvent;\n\tfailed: RecipientEvent;\n\tdsn: DsnEvent;\n\terror: QueueErrorEvent;\n}\n\nexport type QueueListener<E extends keyof QueueEvents> = (\n\tevent: QueueEvents[E],\n) => void;\n\n/** Listeners by event. One that throws is ignored: it never stops a delivery. */\nexport class Events {\n\treadonly #listeners = new Map<keyof QueueEvents, Set<(e: never) => void>>();\n\n\ton<E extends keyof QueueEvents>(\n\t\tevent: E,\n\t\tlistener: QueueListener<E>,\n\t): () => void {\n\t\tlet set = this.#listeners.get(event);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\tthis.#listeners.set(event, set);\n\t\t}\n\t\tset.add(listener as (e: never) => void);\n\t\treturn () => {\n\t\t\tset.delete(listener as (e: never) => void);\n\t\t};\n\t}\n\n\temit<E extends keyof QueueEvents>(event: E, payload: QueueEvents[E]): void {\n\t\tfor (const listener of this.#listeners.get(event) ?? []) {\n\t\t\ttry {\n\t\t\t\t(listener as QueueListener<E>)(payload);\n\t\t\t} catch {\n\t\t\t\t// A listener's failure is its own.\n\t\t\t}\n\t\t}\n\t}\n}\n",
|
|
6
|
+
"import type { Diagnostic } from '../contract/types';\n\n/** One recipient's outcome. */\nexport interface RecipientEvent {\n\t/** The item's id. */\n\treadonly id: string;\n\treadonly from: string;\n\treadonly recipient: string;\n\t/** What the other side said, or why nobody said anything. */\n\treadonly reply?: Diagnostic;\n\t/** The attempts made so far, this one included. */\n\treadonly attempts: number;\n\t/**\n\t * The route of this recipient's last session: `'mx'`, or `'smarthost'`\n\t * for a smarthost, a host of a route, or the fallback.\n\t */\n\treadonly route?: 'mx' | 'smarthost';\n\t/** `true` when that session was the fallback, after the one by MX failed. */\n\treadonly fallback?: true;\n\t/**\n\t * With `fallback`, what the MX side said (or why nobody said anything)\n\t * before the smarthost took over: `reply` is the smarthost's.\n\t */\n\treadonly mxReply?: Diagnostic;\n\t/**\n\t * Only on `deferred` and `failed`: `true` when a session by MX ended\n\t * after the final dot with no reply, so the MX may hold a copy and the\n\t * queue never fell back to a smarthost for this recipient on its own.\n\t */\n\treadonly mayHaveReachedMx?: true;\n}\n\nexport interface DeferredEvent extends RecipientEvent {\n\t/** When the recipient is tried again, in milliseconds since the epoch. */\n\treadonly nextAttemptAt: number;\n}\n\n/** A DSN, enqueued back to the sender. */\nexport interface DsnEvent {\n\treadonly kind: 'delayed' | 'failed';\n\t/** The DSN's own item id. */\n\treadonly id: string;\n\t/** The id of the item it reports on. */\n\treadonly of: string;\n\t/** The original's sender, to whom it goes. */\n\treadonly to: string;\n\treadonly recipients: readonly string[];\n}\n\n/** A failure of the queue itself: the store, a DSN that could not be enqueued, a lease lost. */\nexport interface QueueErrorEvent {\n\treadonly error: unknown;\n\t/** The item it happened to, if any. */\n\treadonly id?: string;\n}\n\nexport interface QueueEvents {\n\tdelivered: RecipientEvent;\n\tdeferred: DeferredEvent;\n\tfailed: RecipientEvent;\n\tdsn: DsnEvent;\n\terror: QueueErrorEvent;\n}\n\nexport type QueueListener<E extends keyof QueueEvents> = (\n\tevent: QueueEvents[E],\n) => void;\n\n/** Listeners by event. One that throws is ignored: it never stops a delivery. */\nexport class Events {\n\treadonly #listeners = new Map<keyof QueueEvents, Set<(e: never) => void>>();\n\n\ton<E extends keyof QueueEvents>(\n\t\tevent: E,\n\t\tlistener: QueueListener<E>,\n\t): () => void {\n\t\tlet set = this.#listeners.get(event);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\tthis.#listeners.set(event, set);\n\t\t}\n\t\tset.add(listener as (e: never) => void);\n\t\treturn () => {\n\t\t\tset.delete(listener as (e: never) => void);\n\t\t};\n\t}\n\n\temit<E extends keyof QueueEvents>(event: E, payload: QueueEvents[E]): void {\n\t\tfor (const listener of this.#listeners.get(event) ?? []) {\n\t\t\ttry {\n\t\t\t\t(listener as QueueListener<E>)(payload);\n\t\t\t} catch {\n\t\t\t\t// A listener's failure is its own.\n\t\t\t}\n\t\t}\n\t}\n}\n",
|
|
7
7
|
"import { sendMail } from '@bumail/smtp/client';\nimport { checkOwner } from '../../contract/checks';\nimport { invalid } from '../../errors';\nimport type { QueueOptions, Route, Sender } from '../options';\nimport { type DsnSettings, dsnOf } from './dsn';\nimport {\n\ttype LimitSettings,\n\tlimitsOf,\n\ttype RetrySettings,\n\tretryOf,\n} from './limits';\nimport { MAX_TIMER, MINUTE, numberOf } from './numbers';\nimport { checkRoutes } from './routes';\nimport { checkSessions } from './sessions';\n\nexport type { DsnSettings, LimitSettings, RetrySettings };\n\n/** Every option checked, with its default. */\nexport interface Settings {\n\treadonly options: QueueOptions;\n\treadonly hostname: string;\n\t/** The routes by domain, in lowercase. */\n\treadonly routes: ReadonlyMap<string, Route>;\n\treadonly retry: RetrySettings;\n\treadonly limits: LimitSettings;\n\treadonly dsn: DsnSettings;\n\treadonly concurrency: number;\n\treadonly perDomain: number;\n\treadonly leaseMs: number;\n\treadonly pollInterval: number;\n\treadonly owner: string;\n\treadonly now: () => number;\n\treadonly send: Sender;\n\treadonly random: () => number;\n}\n\nconst HOSTNAME =\n\t/^(?=.{1,253}$)[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*$/;\n\n/** The options, checked, with their defaults; `INVALID` names the first wrong one. */\nexport function settingsOf(options: QueueOptions): Settings {\n\tif (typeof options !== 'object' || options === null) {\n\t\tthrow invalid('createQueue() takes an options object');\n\t}\n\tif (typeof options.store?.claim !== 'function') {\n\t\tthrow invalid('store must be a QueueStore, such as MemoryQueueStore');\n\t}\n\tconst { hostname } = options;\n\tif (typeof hostname !== 'string' || !HOSTNAME.test(hostname)) {\n\t\tthrow invalid(\n\t\t\t`hostname must be this server's public host name, not ${hostname}`,\n\t\t);\n\t}\n\tcheckRoutes(options);\n\tcheckSessions(options);\n\tconst owner = checkOwner(options.owner ?? crypto.randomUUID());\n\tconst clock = options.clock;\n\treturn {\n\t\toptions,\n\t\thostname,\n\t\troutes: new Map(\n\t\t\tObject.entries(options.routes ?? {}).map(([d, r]) => [\n\t\t\t\td.toLowerCase(),\n\t\t\t\tr,\n\t\t\t]),\n\t\t),\n\t\tretry: retryOf(options),\n\t\tlimits: limitsOf(options),\n\t\tdsn: dsnOf(options, hostname),\n\t\tconcurrency: numberOf('concurrency', options.concurrency, 20, 1),\n\t\tperDomain: numberOf('perDomain', options.perDomain, 2, 1),\n\t\tleaseMs: numberOf(\n\t\t\t'leaseMs',\n\t\t\toptions.leaseMs,\n\t\t\t10 * MINUTE,\n\t\t\t1000,\n\t\t\t3 * MAX_TIMER,\n\t\t),\n\t\tpollInterval: numberOf(\n\t\t\t'pollInterval',\n\t\t\toptions.pollInterval,\n\t\t\t5000,\n\t\t\t1,\n\t\t\tMAX_TIMER,\n\t\t),\n\t\towner,\n\t\tnow: clock ? () => clock.now() : Date.now,\n\t\tsend: options.send ?? sendMail,\n\t\trandom: options.random ?? Math.random,\n\t};\n}\n",
|
|
8
8
|
"import { invalid } from '../../errors';\n\nexport const MINUTE = 60_000;\nexport const HOUR = 60 * MINUTE;\n/** The longest delay a timer takes: past it, Bun fires after 1 ms. */\nexport const MAX_TIMER = 2_147_483_647;\n\n/** A number in `[min, max]`, integer when asked, or its default. */\nexport function numberOf(\n\tname: string,\n\tvalue: unknown,\n\tfallback: number,\n\tmin: number,\n\tmax = Number.MAX_SAFE_INTEGER,\n\tinteger = true,\n): number {\n\tif (value === undefined) return fallback;\n\tconst ok =\n\t\ttypeof value === 'number' &&\n\t\t(integer ? Number.isInteger(value) : Number.isFinite(value)) &&\n\t\tvalue >= min &&\n\t\tvalue <= max;\n\tif (!ok) {\n\t\tconst kind = integer ? 'an integer' : 'a number';\n\t\tconst range =\n\t\t\tmax === Number.MAX_SAFE_INTEGER\n\t\t\t\t? `of at least ${min}`\n\t\t\t\t: `from ${min} to ${max}`;\n\t\tthrow invalid(`${name} must be ${kind} ${range}, not ${value}`);\n\t}\n\treturn value as number;\n}\n",
|
|
9
9
|
"import { invalid } from '../../errors';\nimport { checkAddress } from '../envelope';\nimport type { QueueOptions } from '../options';\nimport { HOUR, numberOf } from './numbers';\n\nexport interface DsnSettings {\n\treadonly from: string;\n\treadonly delayAfter: number | false;\n\treadonly returnContent: 'headers' | 'full';\n}\n\nexport function dsnOf(options: QueueOptions, hostname: string): DsnSettings {\n\tconst d = options.dsn ?? {};\n\tconst from = checkAddress('dsn.from', d.from ?? `postmaster@${hostname}`);\n\tconst delayAfter =\n\t\td.delayAfter === false\n\t\t\t? false\n\t\t\t: numberOf('dsn.delayAfter', d.delayAfter, 4 * HOUR, 0);\n\tconst returnContent = d.returnContent ?? 'headers';\n\tif (returnContent !== 'headers' && returnContent !== 'full') {\n\t\tthrow invalid(\n\t\t\t`dsn.returnContent must be 'headers' or 'full', not ${returnContent}`,\n\t\t);\n\t}\n\treturn { from, delayAfter, returnContent };\n}\n",
|
|
10
10
|
"import type { QueueOptions } from '../options';\nimport { HOUR, MINUTE, numberOf } from './numbers';\n\nexport interface RetrySettings {\n\treadonly first: number;\n\treadonly factor: number;\n\treadonly max: number;\n\treadonly jitter: number;\n\treadonly giveUpAfter: number;\n}\n\nexport interface LimitSettings {\n\treadonly maxMessageSize: number;\n\treadonly maxRecipients: number;\n\treadonly maxItems: number | undefined;\n\treadonly maxReplyText: number;\n\treadonly maxDsnReturn: number;\n}\n\nexport function retryOf(options: QueueOptions): RetrySettings {\n\tconst r = options.retry ?? {};\n\tconst first = numberOf('retry.first', r.first, 30 * MINUTE, 1);\n\treturn {\n\t\tfirst,\n\t\tfactor: numberOf('retry.factor', r.factor, 2, 1, 100, false),\n\t\tmax: numberOf('retry.max', r.max, Math.max(first, 4 * HOUR), first),\n\t\tjitter: numberOf('retry.jitter', r.jitter, 0.1, 0, 1, false),\n\t\tgiveUpAfter: numberOf('retry.giveUpAfter', r.giveUpAfter, 120 * HOUR, 0),\n\t};\n}\n\nexport function limitsOf(options: QueueOptions): LimitSettings {\n\tconst l = options.limits ?? {};\n\treturn {\n\t\tmaxMessageSize: numberOf(\n\t\t\t'limits.maxMessageSize',\n\t\t\tl.maxMessageSize,\n\t\t\t25 * 1024 * 1024,\n\t\t\t1,\n\t\t),\n\t\tmaxRecipients: numberOf('limits.maxRecipients', l.maxRecipients, 100, 1),\n\t\tmaxItems:\n\t\t\tl.maxItems === undefined\n\t\t\t\t? undefined\n\t\t\t\t: numberOf('limits.maxItems', l.maxItems, 0, 1),\n\t\tmaxReplyText: numberOf('limits.maxReplyText', l.maxReplyText, 512, 64, 900),\n\t\tmaxDsnReturn: numberOf('limits.maxDsnReturn', l.maxDsnReturn, 64 * 1024, 0),\n\t};\n}\n",
|
|
11
11
|
"import { invalid } from '../../errors';\nimport type { QueueOptions } from '../options';\nimport { MAX_TIMER, numberOf } from './numbers';\n\n/** The longest wait `sendMail` takes, in seconds: its timer's own limit. */\nconst MAX_SECONDS = Math.floor(MAX_TIMER / 1000);\n\nfunction checkSeconds(name: string, value: unknown): void {\n\tif (value === undefined) return;\n\tif (\n\t\ttypeof value !== 'number' ||\n\t\t!Number.isFinite(value) ||\n\t\tvalue <= 0 ||\n\t\tvalue > MAX_SECONDS\n\t) {\n\t\tthrow invalid(\n\t\t\t`${name} must be a number of seconds above 0 and at most ${MAX_SECONDS}, not ${value}`,\n\t\t);\n\t}\n}\n\nexport function checkTls(name: string, tls: unknown): void {\n\tif (\n\t\ttls !== undefined &&\n\t\ttls !== 'opportunistic' &&\n\t\ttls !== 'required' &&\n\t\ttls !== 'none'\n\t) {\n\t\tthrow invalid(\n\t\t\t`${name} must be 'opportunistic', 'required' or 'none', not ${tls}`,\n\t\t);\n\t}\n}\n\n/** What every session takes, whatever its route: the MX port and TLS, the timeouts. */\nexport function checkSessions(options: QueueOptions): void {\n\tnumberOf('mxPort', options.mxPort, 25, 1, 65535);\n\tcheckTls('mxTls', options.mxTls);\n\tconst timeouts = options.timeouts;\n\tif (timeouts !== undefined) {\n\t\tif (typeof timeouts !== 'object' || timeouts === null) {\n\t\t\tthrow invalid('timeouts must be an object of seconds');\n\t\t}\n\t\tfor (const [step, value] of Object.entries(timeouts)) {\n\t\t\tcheckSeconds(`timeouts.${step}`, value);\n\t\t}\n\t}\n\tcheckSeconds('deadline', options.deadline);\n}\n",
|
|
12
12
|
"import { invalid } from '../../errors';\nimport type { QueueOptions, Route, Smarthost } from '../options';\nimport { numberOf } from './numbers';\nimport { checkTls } from './sessions';\n\n/**\n * A smarthost `sendMail` will take, checked now rather than at each\n * delivery: a host, a port, a TLS mode, and credentials only over TLS\n * whose certificate is checked — `sendMail`'s own rule\n * (`@bumail/smtp`'s `client/settings.ts`), with no way out for a test.\n */\nfunction checkRoute(name: string, route: Route): void {\n\tif (route === 'mx') return;\n\tconst smarthost = route as Smarthost | undefined;\n\tconst host = smarthost?.host;\n\tif (typeof host !== 'string' || !/^[^\\s/]+$/.test(host)) {\n\t\tthrow invalid(`${name} must be 'mx' or a smarthost with a host`);\n\t}\n\tconst { port, secure, tls, auth } = smarthost as Smarthost;\n\tnumberOf(`${name}.port`, port, 25, 1, 65535);\n\tif (secure !== undefined && typeof secure !== 'boolean') {\n\t\tthrow invalid(`${name}.secure must be true or false, not ${secure}`);\n\t}\n\tcheckTls(`${name}.tls`, tls);\n\tif (tls === 'none' && secure) {\n\t\tthrow invalid(\n\t\t\t`${name}.secure is TLS from the first byte: it cannot go with tls: 'none'`,\n\t\t);\n\t}\n\tif (auth === undefined) return;\n\tif (typeof auth?.username !== 'string' || auth.username === '') {\n\t\tthrow invalid(`${name}.auth.username must be a non-empty string`);\n\t}\n\tif (typeof auth.password !== 'string' || auth.password === '') {\n\t\tthrow invalid(`${name}.auth.password must be a non-empty string`);\n\t}\n\tconst { mechanism } = auth;\n\tif (\n\t\tmechanism !== undefined &&\n\t\tmechanism !== 'PLAIN' &&\n\t\tmechanism !== 'LOGIN'\n\t) {\n\t\tthrow invalid(\n\t\t\t`${name}.auth.mechanism must be 'PLAIN' or 'LOGIN', not ${mechanism}`,\n\t\t);\n\t}\n\tif (tls !== undefined && tls !== 'required') {\n\t\tthrow invalid(\n\t\t\t`${name}.auth needs tls: 'required', the default with auth: with tls: '${tls}' the password would go to a server whose certificate is not checked`,\n\t\t);\n\t}\n}\n\nexport function checkRoutes(options: QueueOptions): void {\n\tif (options.fallback !== undefined) {\n\t\tconst fallback = options.fallback as Route | null;\n\t\tif (\n\t\t\ttypeof fallback !== 'object' ||\n\t\t\tfallback === null ||\n\t\t\ttypeof fallback.host !== 'string'\n\t\t) {\n\t\t\tthrow invalid(\n\t\t\t\t'fallback must be a smarthost with a host, not an mx route',\n\t\t\t);\n\t\t}\n\t\tcheckRoute('fallback', fallback);\n\t}\n\tcheckRoute('route', options.route ?? 'mx');\n\tconst routes = Object.entries(options.routes ?? {});\n\tfor (const [domain, route] of routes)\n\t\tcheckRoute(`routes[\"${domain}\"]`, route);\n\tconst usesMx =\n\t\t(options.route ?? 'mx') === 'mx' || routes.some(([, r]) => r === 'mx');\n\tif (usesMx && typeof options.resolver?.mx !== 'function') {\n\t\tthrow invalid(\n\t\t\t\"The 'mx' route needs a resolver, such as @bumail/dns's nodeResolver()\",\n\t\t);\n\t}\n}\n",
|
|
13
|
-
"import { isMailbox } from '@bumail/smtp/client';\nimport type { QueueItem, RecipientUpdate } from '../contract/types';\nimport { QueueError } from '../errors';\nimport { attemptGroup, type Used } from './attempt';\nimport { domainOf } from './envelope';\nimport type { Events } from './events';\nimport type { Lapse } from './lease';\nimport type { KeyedLimiter } from './limiter';\nimport { type NotifyContext, notify } from './notify';\nimport { type Settled, settle } from './settle';\n\nexport interface DeliveryContext extends NotifyContext {\n\treadonly domains: KeyedLimiter;\n\treadonly events: Events;\n\t/** The worker is stopping: a group not started yet is left for later. */\n\treadonly stopping: () => boolean;\n\t/** The outcome is recorded: the lease needs no more renewal. */\n\treadonly recorded: () => void;\n\t/**\n\t * Whether the lease could have passed to another worker by `now`: a\n\t * renewal found it taken, or its last expiry is past. `undefined` while\n\t * it surely held.\n\t */\n\treadonly leaseLapsed: (now: number) => Promise<Lapse | undefined>;\n}\n\n/**\n * Said when the item is gone at `complete` and the lease had lapsed. With\n * no record of who removed it, neither case can tell another worker that\n * finished it from a cancel, so each names both; either way what this\n * worker sent may have been sent again, and it reports no outcome.\n */\nconst goneAfter = (lapse: Lapse, id: string): QueueError =>\n\tnew QueueError(\n\t\t'LEASE_LOST',\n\t\tlapse === 'taken'\n\t\t\t? `The lease on ${id} was lost while it was delivered, and the item is gone: finished by the worker that took it, the message then sent twice, or cancelled`\n\t\t\t: `The lease on ${id} expired before its outcome was recorded, and the item is gone: lost to another worker that finished it, the message then sent twice, or cancelled`,\n\t);\n\n/** The recipients still to deliver, by domain. */\nfunction groupsOf(item: QueueItem): Map<string, string[]> {\n\tconst groups = new Map<string, string[]>();\n\tfor (const r of item.recipients) {\n\t\tif (r.status === 'delivered' || r.status === 'failed') continue;\n\t\tconst domain = domainOf(r.address);\n\t\tconst group = groups.get(domain);\n\t\tif (group) group.push(r.address);\n\t\telse groups.set(domain, [r.address]);\n\t}\n\treturn groups;\n}\n\n/**\n * Every recipient of an item whose sender `sendMail` would refuse — kept\n * by a store written to by other code, since `enqueue` refuses it — fails\n * at once, as X.1.7 (bad sender's mailbox address syntax), rather than be\n * deferred on every attempt until `retry.giveUpAfter`.\n */\nconst badSender = (address: string): RecipientUpdate => ({\n\taddress,\n\tstatus: 'failed',\n\treply: {\n\t\tstatus: '5.1.7',\n\t\ttext: \"The sender's address is not one SMTP can carry\",\n\t},\n});\n\n/**\n * A pending recipient of an item whose message the store no longer gives\n * — a Redis key evicted or deleted, a row removed by hand — fails at once,\n * as X.3.0 (mail system status): no session can send what cannot be read,\n * and an attempt left without an outcome would be claimed again at every\n * lease, forever, keeping its `maxItems` place.\n */\nconst unreadable = (address: string): RecipientUpdate => ({\n\taddress,\n\tstatus: 'failed',\n\treply: {\n\t\tstatus: '5.3.0',\n\t\ttext: 'Message unreadable: the queue store holds the item but not its message',\n\t},\n});\n\nconst unreadableError = (id: string): QueueError =>\n\tnew QueueError(\n\t\t'MESSAGE_UNREADABLE',\n\t\t`The message of ${id} is unreadable: the store holds the item but not its message, so every pending recipient failed`,\n\t);\n\n/** Tells the listeners each recipient's outcome. */\nfunction emitOutcomes(\n\tevents: Events,\n\titem: QueueItem,\n\tsettled: Settled,\n\tused: ReadonlyMap<string, Used>,\n): void {\n\tconst { attempts, nextAttemptAt } = settled.result;\n\tconst base = (u: RecipientUpdate) => ({\n\t\tid: item.id,\n\t\tfrom: item.from,\n\t\trecipient: u.address,\n\t\t...(u.reply ? { reply: u.reply } : {}),\n\t\tattempts,\n\t\t...used.get(u.address),\n\t});\n\tfor (const u of settled.delivered) events.emit('delivered', base(u));\n\tfor (const u of settled.deferred) {\n\t\tevents.emit('deferred', { ...base(u), nextAttemptAt });\n\t}\n\tfor (const u of settled.failed)
|
|
14
|
-
"import { isMailbox } from '@bumail/smtp/client';\nimport type { QueueItem, RecipientUpdate } from '../contract/types';\nimport type { DeliveryContext } from './deliver';\nimport type { RecipientEvent } from './events';\nimport { fallsBack } from './fallback';\nimport type { Route } from './options';\nimport {
|
|
15
|
-
"import type {\n\tReply,\n\tSendMailResult,\n\tSmtpError,\n\tSmtpErrorCode,\n} from '@bumail/smtp/client';\nimport type { Diagnostic, RecipientUpdate } from '../contract/types';\nimport { cleanText } from '../text';\n\n/**\n * An `SmtpError`, read by its `name`: a second copy of `@bumail/smtp` (a\n * different version installed for the app) throws errors of another\n * class, which `instanceof` would take for unknown ones.\n */\nexport const isSmtpError = (error: unknown): error is SmtpError =>\n\terror instanceof Error &&\n\terror.name === 'SmtpError' &&\n\ttypeof (error as { code?: unknown }).code === 'string';\n\n/**\n * `sendMail` refused its options: the route is misconfigured (a smarthost\n * it cannot use, a bad timeout), not the recipient. Retried, never bounced\n * at once: fixing the configuration and restarting delivers the message.\n */\nexport const isRouteError = (error: unknown): boolean =>\n\tisSmtpError(error) && error.code === 'INVALID_OPTION';\n\n/** An enhanced status code, `x.y.z` (RFC 3463 §2). */\nconst STATUS = /^[245]\\.\\d{1,3}\\.\\d{1,3}$/;\n\n/** What a reply says, bounded and cleaned. */\nexport function diagnosticOf(\n\treply: Reply,\n\tmax: number,\n\thost?: string,\n): Diagnostic {\n\tconst text =\n\t\ttypeof reply.text === 'string' ? reply.text : reply.text.join(' ');\n\treturn {\n\t\tcode: reply.code,\n\t\t...(reply.status && STATUS.test(reply.status)\n\t\t\t? { status: reply.status }\n\t\t\t: {}),\n\t\ttext: cleanText(text, max),\n\t\t...(host ? { host: cleanText(host, 255) } : {}),\n\t};\n}\n\n/**\n * The status code an error with no reply stands for (RFC 3463 §3): a null\n * MX is X.1.10 (RFC 7505 §4.2), a domain that cannot be found X.1.2, a\n * host that does not answer X.4.1, a connection lost or timed out X.4.2,\n * TLS X.7.0 (security).\n */\nconst ERROR_STATUS: Partial<Record<SmtpErrorCode, string>> = {\n\tNULL_MX: '1.10',\n\tDNS_FAILED: '1.2',\n\tCONNECTION_FAILED: '4.1',\n\tCONNECTION_LOST: '4.2',\n\tTIMEOUT: '4.2',\n\tTLS_UNAVAILABLE: '7.10',\n\tTLS_FAILED: '7.0',\n\tAUTH_UNAVAILABLE: '7.0',\n\tINVALID_OPTION: '3.5',\n};\n\n
|
|
16
|
-
"import type { Diagnostic } from '../contract/types';\nimport { isSmtpError } from './outcome';\n\n/** Words a refusal uses when it names a blocklist or a reputation, for a server that gives no enhanced code. */\nconst REPUTATION =\n\t/\\b(?:block ?list(?:ed)?|black ?list(?:ed)?|deny ?list(?:ed)?|spamhaus|rbl|dnsbl|reputation|banned)\\b|\\bblocked\\b|\\blisted (?:in|on|at)\\b/i;\n\n/** A greylisting: a `4.7.x` that asks to come back, which a smarthost would not change. */\nconst GREYLIST = /gr[ae]y ?list/i;\n\n/**\n * Whether what the other side said (or why nobody said anything) is a\n * reason to try the fallback smarthost rather than wait: a connection\n * that failed or timed out (X.4.1, X.4.2, no reply at all), or a refusal\n * read as a matter of policy or reputation, a `4.7.x` or `5.7.x` (RFC\n * 3463 §3.8, security or policy status) or, with no enhanced code, text\n * that names a blocklist or a reputation.\n *\n * It is not a reason when the message may already be at the MX: an\n * `SmtpError` marked `afterData` (the final dot was written and no reply\n * came, a timeout or a lost connection that reads as 4.4.2) would be one\n * more copy by the smarthost, so the recipient is deferred for the MX retry\n * (RFC 5321 §4.1.5). An `@bumail/smtp` without the field behaves as before.\n *\n * It is not a reason when the smarthost would be refused alike: an\n * unknown or full mailbox (`5.1.x`, `x.2.x`), a domain that does not\n * exist, a null MX, a route that is misconfigured, or a TLS failure of\n * the MX (an `SmtpError` coded `TLS_*`, even one that carries a reply such\n * as a refused STARTTLS `454 4.7.0`), which the operator's TLS policy meant\n * to refuse, or a greylisting (`4.7.x` whose text says so), which the MX\n * retry settles.\n */\nexport function fallsBack(\n\treply: Diagnostic | undefined,\n\terror?: unknown,\n): boolean {\n\tif (!reply) return false;\n\tif (isSmtpError(error) && error.afterData) return false;\n\tif (isSmtpError(error) && error.code.startsWith('TLS_')) return false;\n\tif (GREYLIST.test(reply.text)) return false;\n\tif (reply.code === undefined) {\n\t\treturn reply.status === '4.4.1' || reply.status === '4.4.2';\n\t}\n\tif (reply.code < 400) return false;\n\tif (reply.status !== undefined) {\n\t\treturn /^[45]\\.7\\.\\d+$/.test(reply.status);\n\t}\n\treturn REPUTATION.test(reply.text);\n}\n",
|
|
13
|
+
"import { isMailbox } from '@bumail/smtp/client';\nimport type { QueueItem, RecipientUpdate } from '../contract/types';\nimport { QueueError } from '../errors';\nimport { attemptGroup, type Used } from './attempt';\nimport { domainOf } from './envelope';\nimport type { Events } from './events';\nimport type { Lapse } from './lease';\nimport type { KeyedLimiter } from './limiter';\nimport { type NotifyContext, notify } from './notify';\nimport { type Settled, settle } from './settle';\n\nexport interface DeliveryContext extends NotifyContext {\n\treadonly domains: KeyedLimiter;\n\treadonly events: Events;\n\t/** The worker is stopping: a group not started yet is left for later. */\n\treadonly stopping: () => boolean;\n\t/** The outcome is recorded: the lease needs no more renewal. */\n\treadonly recorded: () => void;\n\t/**\n\t * Whether the lease could have passed to another worker by `now`: a\n\t * renewal found it taken, or its last expiry is past. `undefined` while\n\t * it surely held.\n\t */\n\treadonly leaseLapsed: (now: number) => Promise<Lapse | undefined>;\n}\n\n/**\n * Said when the item is gone at `complete` and the lease had lapsed. With\n * no record of who removed it, neither case can tell another worker that\n * finished it from a cancel, so each names both; either way what this\n * worker sent may have been sent again, and it reports no outcome.\n */\nconst goneAfter = (lapse: Lapse, id: string): QueueError =>\n\tnew QueueError(\n\t\t'LEASE_LOST',\n\t\tlapse === 'taken'\n\t\t\t? `The lease on ${id} was lost while it was delivered, and the item is gone: finished by the worker that took it, the message then sent twice, or cancelled`\n\t\t\t: `The lease on ${id} expired before its outcome was recorded, and the item is gone: lost to another worker that finished it, the message then sent twice, or cancelled`,\n\t);\n\n/** The recipients still to deliver, by domain. */\nfunction groupsOf(item: QueueItem): Map<string, string[]> {\n\tconst groups = new Map<string, string[]>();\n\tfor (const r of item.recipients) {\n\t\tif (r.status === 'delivered' || r.status === 'failed') continue;\n\t\tconst domain = domainOf(r.address);\n\t\tconst group = groups.get(domain);\n\t\tif (group) group.push(r.address);\n\t\telse groups.set(domain, [r.address]);\n\t}\n\treturn groups;\n}\n\n/**\n * Every recipient of an item whose sender `sendMail` would refuse — kept\n * by a store written to by other code, since `enqueue` refuses it — fails\n * at once, as X.1.7 (bad sender's mailbox address syntax), rather than be\n * deferred on every attempt until `retry.giveUpAfter`.\n */\nconst badSender = (address: string): RecipientUpdate => ({\n\taddress,\n\tstatus: 'failed',\n\treply: {\n\t\tstatus: '5.1.7',\n\t\ttext: \"The sender's address is not one SMTP can carry\",\n\t},\n});\n\n/**\n * A pending recipient of an item whose message the store no longer gives\n * — a Redis key evicted or deleted, a row removed by hand — fails at once,\n * as X.3.0 (mail system status): no session can send what cannot be read,\n * and an attempt left without an outcome would be claimed again at every\n * lease, forever, keeping its `maxItems` place.\n */\nconst unreadable = (address: string): RecipientUpdate => ({\n\taddress,\n\tstatus: 'failed',\n\treply: {\n\t\tstatus: '5.3.0',\n\t\ttext: 'Message unreadable: the queue store holds the item but not its message',\n\t},\n});\n\nconst unreadableError = (id: string): QueueError =>\n\tnew QueueError(\n\t\t'MESSAGE_UNREADABLE',\n\t\t`The message of ${id} is unreadable: the store holds the item but not its message, so every pending recipient failed`,\n\t);\n\n/** Tells the listeners each recipient's outcome. */\nfunction emitOutcomes(\n\tevents: Events,\n\titem: QueueItem,\n\tsettled: Settled,\n\tused: ReadonlyMap<string, Used>,\n): void {\n\tconst { attempts, nextAttemptAt } = settled.result;\n\tconst base = (u: RecipientUpdate) => ({\n\t\tid: item.id,\n\t\tfrom: item.from,\n\t\trecipient: u.address,\n\t\t...(u.reply ? { reply: u.reply } : {}),\n\t\tattempts,\n\t\t...used.get(u.address),\n\t});\n\tconst marked = (u: RecipientUpdate) =>\n\t\tu.mayHaveReachedMx ? { mayHaveReachedMx: true as const } : {};\n\tfor (const u of settled.delivered) events.emit('delivered', base(u));\n\tfor (const u of settled.deferred) {\n\t\tevents.emit('deferred', { ...base(u), ...marked(u), nextAttemptAt });\n\t}\n\tfor (const u of settled.failed) {\n\t\tevents.emit('failed', { ...base(u), ...marked(u) });\n\t}\n}\n\n/**\n * Delivers a claimed item: one session per recipient domain, at most\n * `perDomain` at once to each — none, and no slot taken, when its sender\n * is one `sendMail` would refuse — then the outcome recorded — which lets go\n * of the lease — then the events and the DSNs. An item whose message the\n * store no longer gives fails every pending recipient, said on the `error`\n * event, its DSN without the original.\n */\nexport async function deliverItem(\n\tctx: DeliveryContext,\n\titem: QueueItem,\n): Promise<void> {\n\tconst { store } = ctx;\n\tconst message = await store.readMessage(item.id);\n\tif (!message) {\n\t\t// Gone with its message: cancelled, or finished by another worker.\n\t\tif ((await store.get(item.id)) === undefined) return;\n\t\tconst failed = [...groupsOf(item).values()].flat().map(unreadable);\n\t\tawait record(ctx, item, failed, false, undefined, new Map());\n\t\treturn;\n\t}\n\tconst groups = groupsOf(item);\n\tlet skipped = false;\n\tconst used = new Map<string, Used>();\n\t// A sender sendMail would refuse: no session, no slot, every recipient at once.\n\tconst outcomes =\n\t\titem.from !== '' && !isMailbox(item.from)\n\t\t\t? [[...groups.values()].flat().map(badSender)]\n\t\t\t: await Promise.all(\n\t\t\t\t\t[...groups].map(async ([domain, group]) => {\n\t\t\t\t\t\tconst release = await ctx.domains.acquire(domain);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (ctx.stopping()) {\n\t\t\t\t\t\t\t\tskipped = true;\n\t\t\t\t\t\t\t\treturn [];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn await attemptGroup(\n\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t\tdomain,\n\t\t\t\t\t\t\t\tgroup,\n\t\t\t\t\t\t\t\tused,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\trelease();\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t);\n\tawait record(ctx, item, outcomes.flat(), skipped, message, used);\n}\n\n/**\n * Records an attempt's outcomes — which lets go of the lease — then tells\n * the events and sends the DSNs, the original returned when there is one.\n * With no `message` (the store lost it), the `MESSAGE_UNREADABLE` error\n * comes first of the events, and only once the failures are recorded: a\n * lease lost meanwhile, or a `complete` that throws, says nothing of them,\n * and an item cancelled meanwhile tells nothing at all.\n */\nasync function record(\n\tctx: DeliveryContext,\n\titem: QueueItem,\n\tupdates: readonly RecipientUpdate[],\n\tskipped: boolean,\n\tmessage: Uint8Array | undefined,\n\tused: ReadonlyMap<string, Used>,\n): Promise<void> {\n\tconst { settings, store, events } = ctx;\n\tconst now = settings.now();\n\tconst settled = settle(item, updates, skipped, now, settings);\n\tconst after = await store.complete(item.id, settings.owner, settled.result);\n\tctx.recorded();\n\tif (!after && (await store.get(item.id)) === undefined) {\n\t\tconst lapse = await ctx.leaseLapsed(now);\n\t\tif (lapse) {\n\t\t\t// Lost or cancelled: no outcome told, as when the item is still there.\n\t\t\tevents.emit('error', { error: goneAfter(lapse, item.id), id: item.id });\n\t\t\treturn;\n\t\t}\n\t\t// Cancelled under a lease that held, with no session for a lost\n\t\t// message: nothing happened, and nothing was recorded, so nothing is told.\n\t\tif (!message) return;\n\t\t// Otherwise what the sessions did still happened; no DSN.\n\t\temitOutcomes(events, item, settled, used);\n\t\treturn;\n\t}\n\tif (!after) {\n\t\tconst error = new QueueError(\n\t\t\t'LEASE_LOST',\n\t\t\t`The lease on ${item.id} was lost before its outcome was recorded; another worker will try it again`,\n\t\t);\n\t\tevents.emit('error', { error, id: item.id });\n\t\treturn;\n\t}\n\tif (!message) {\n\t\tevents.emit('error', { error: unreadableError(item.id), id: item.id });\n\t}\n\temitOutcomes(events, item, settled, used);\n\tawait notify(ctx, item, message, 'failed', settled.failed, now);\n\tif (settled.delayDsn) {\n\t\tawait notify(ctx, item, message, 'delayed', settled.deferred, now);\n\t}\n}\n",
|
|
14
|
+
"import { isMailbox } from '@bumail/smtp/client';\nimport type { QueueItem, RecipientUpdate } from '../contract/types';\nimport type { DeliveryContext } from './deliver';\nimport type { RecipientEvent } from './events';\nimport { fallsBack } from './fallback';\nimport type { Route } from './options';\nimport {\n\tisRouteError,\n\tisSmtpError,\n\toutcomesOf,\n\toutcomesOfError,\n} from './outcome';\nimport { hostOf, routeOf, sendOptionsOf } from './route';\n\n/**\n * A recipient `sendMail` would refuse — kept by a store written to by\n * other code, since `enqueue` refuses it — fails alone, as X.1.3 (bad\n * destination mailbox address syntax), so the session for its domain\n * still goes ahead for the others.\n */\nconst badAddress = (address: string): RecipientUpdate => ({\n\taddress,\n\tstatus: 'failed',\n\treply: {\n\t\tstatus: '5.1.3',\n\t\ttext: 'The address is not one SMTP can carry',\n\t},\n});\n\n/** A deferred or failed outcome, marked: the MX may hold the message. */\nconst marked = (u: RecipientUpdate): RecipientUpdate =>\n\tu.status === 'delivered' ? u : { ...u, mayHaveReachedMx: true };\n\n/** The route a recipient's last session took, as its events tell it. */\nexport type Used = Pick<RecipientEvent, 'route' | 'fallback' | 'mxReply'>;\n\n/** One session's outcomes, and the error that ended it, if any. */\ninterface Attempt {\n\treadonly updates: RecipientUpdate[];\n\treadonly error?: unknown;\n}\n\n/** One session, by `route` (the domain's own when none is given): each recipient's outcome, whatever happened. */\nasync function session(\n\tctx: DeliveryContext,\n\titem: QueueItem,\n\tmessage: Uint8Array,\n\tdomain: string,\n\tgroup: readonly string[],\n\troute: Route,\n\toverride?: Route,\n): Promise<Attempt> {\n\tconst { settings } = ctx;\n\tconst max = settings.limits.maxReplyText;\n\ttry {\n\t\tconst options = sendOptionsOf(settings, domain, item.from, group, override);\n\t\tconst result = await settings.send(message, options);\n\t\treturn { updates: outcomesOf(result, group, max) };\n\t} catch (error) {\n\t\t// A route sendMail cannot use is the operator's to fix: said, and retried.\n\t\tif (isRouteError(error)) ctx.events.emit('error', { error, id: item.id });\n\t\tconst updates = outcomesOfError(error, group, max, hostOf(route));\n\t\t// The final dot was written and no reply came: the MX may hold a copy.\n\t\tconst doubt = route === 'mx' && isSmtpError(error) && error.afterData;\n\t\treturn { updates: doubt ? updates.map(marked) : updates, error };\n\t}\n}\n\n/**\n * What a recipient becomes once the fallback answered for its MX outcome.\n * The fallback decides when it delivered, or when the MX refused for good\n * (a `5.7.x`). A smarthost that refuses what the MX only deferred (a bad\n * password, a sender it does not allow) leaves the recipient deferred, with\n * the smarthost's reply as the diagnostic: no DSN, tried again later.\n */\nfunction merged(mx: RecipientUpdate, fb: RecipientUpdate): RecipientUpdate {\n\tif (mx.status === 'deferred' && fb.status === 'failed') {\n\t\treturn { ...fb, status: 'deferred' };\n\t}\n\treturn fb;\n}\n\n/**\n * One delivery for one domain's recipients: each one's outcome, whatever\n * happened, and in `used` the route each took. By MX with a `fallback`,\n * the recipients whose outcome is a connection failure, a timeout or a\n * reputation refusal (`fallsBack`) go at once to the fallback smarthost,\n * in a session of their own, and its outcome replaces the first (`merged`).\n */\nexport async function attemptGroup(\n\tctx: DeliveryContext,\n\titem: QueueItem,\n\tmessage: Uint8Array,\n\tdomain: string,\n\trecipients: readonly string[],\n\tused: Map<string, Used>,\n): Promise<RecipientUpdate[]> {\n\tconst { settings } = ctx;\n\tconst bad = recipients.filter((address) => !isMailbox(address));\n\tconst group = recipients.filter(isMailbox);\n\tif (group.length === 0) return bad.map(badAddress);\n\tconst route = routeOf(settings, domain);\n\tconst label = route === 'mx' ? 'mx' : 'smarthost';\n\tfor (const address of group) used.set(address, { route: label });\n\tconst first = await session(ctx, item, message, domain, group, route);\n\tlet updates = first.updates;\n\tconst { fallback } = settings.options;\n\t// Recorded by an earlier attempt: the MX may hold a copy, so no automatic fallback.\n\tconst doubtful = new Set(\n\t\titem.recipients.filter((r) => r.mayHaveReachedMx).map((r) => r.address),\n\t);\n\tif (fallback !== undefined && route === 'mx') {\n\t\tconst mx = new Map(\n\t\t\tupdates\n\t\t\t\t.filter(\n\t\t\t\t\t(u) =>\n\t\t\t\t\t\tu.status !== 'delivered' &&\n\t\t\t\t\t\t!u.mayHaveReachedMx &&\n\t\t\t\t\t\t!doubtful.has(u.address) &&\n\t\t\t\t\t\tfallsBack(u.reply, first.error),\n\t\t\t\t)\n\t\t\t\t.map((u) => [u.address, u]),\n\t\t);\n\t\tif (mx.size > 0) {\n\t\t\tconst again = [...mx.keys()];\n\t\t\tconst second = await session(\n\t\t\t\tctx,\n\t\t\t\titem,\n\t\t\t\tmessage,\n\t\t\t\tdomain,\n\t\t\t\tagain,\n\t\t\t\tfallback,\n\t\t\t\tfallback,\n\t\t\t);\n\t\t\tfor (const [address, u] of mx) {\n\t\t\t\tused.set(address, {\n\t\t\t\t\troute: 'smarthost',\n\t\t\t\t\tfallback: true,\n\t\t\t\t\t...(u.reply ? { mxReply: u.reply } : {}),\n\t\t\t\t});\n\t\t\t}\n\t\t\tupdates = [\n\t\t\t\t...updates.filter((u) => !mx.has(u.address)),\n\t\t\t\t...second.updates.map((u) => {\n\t\t\t\t\tconst was = mx.get(u.address);\n\t\t\t\t\treturn was ? merged(was, u) : u;\n\t\t\t\t}),\n\t\t\t];\n\t\t}\n\t}\n\treturn [...updates, ...bad.map(badAddress)];\n}\n",
|
|
15
|
+
"import type {\n\tReply,\n\tSendMailResult,\n\tSmtpError,\n\tSmtpErrorCode,\n} from '@bumail/smtp/client';\nimport type { Diagnostic, RecipientUpdate } from '../contract/types';\nimport { cleanText } from '../text';\n\n/**\n * An `SmtpError`, read by its `name`: a second copy of `@bumail/smtp` (a\n * different version installed for the app) throws errors of another\n * class, which `instanceof` would take for unknown ones.\n */\nexport const isSmtpError = (error: unknown): error is SmtpError =>\n\terror instanceof Error &&\n\terror.name === 'SmtpError' &&\n\ttypeof (error as { code?: unknown }).code === 'string';\n\n/**\n * `sendMail` refused its options: the route is misconfigured (a smarthost\n * it cannot use, a bad timeout), not the recipient. Retried, never bounced\n * at once: fixing the configuration and restarting delivers the message.\n */\nexport const isRouteError = (error: unknown): boolean =>\n\tisSmtpError(error) && error.code === 'INVALID_OPTION';\n\n/** An enhanced status code, `x.y.z` (RFC 3463 §2). */\nconst STATUS = /^[245]\\.\\d{1,3}\\.\\d{1,3}$/;\n\n/** What a reply says, bounded and cleaned. */\nexport function diagnosticOf(\n\treply: Reply,\n\tmax: number,\n\thost?: string,\n): Diagnostic {\n\tconst text =\n\t\ttypeof reply.text === 'string' ? reply.text : reply.text.join(' ');\n\treturn {\n\t\tcode: reply.code,\n\t\t...(reply.status && STATUS.test(reply.status)\n\t\t\t? { status: reply.status }\n\t\t\t: {}),\n\t\ttext: cleanText(text, max),\n\t\t...(host ? { host: cleanText(host, 255) } : {}),\n\t};\n}\n\n/**\n * The status code an error with no reply stands for (RFC 3463 §3): a null\n * MX is X.1.10 (RFC 7505 §4.2), a domain that cannot be found X.1.2, a\n * host that does not answer X.4.1, a connection lost or timed out X.4.2,\n * TLS X.7.0 (security).\n */\nconst ERROR_STATUS: Partial<Record<SmtpErrorCode, string>> = {\n\tNULL_MX: '1.10',\n\tDNS_FAILED: '1.2',\n\tCONNECTION_FAILED: '4.1',\n\tCONNECTION_LOST: '4.2',\n\tTIMEOUT: '4.2',\n\tTLS_UNAVAILABLE: '7.10',\n\tTLS_FAILED: '7.0',\n\tAUTH_UNAVAILABLE: '7.0',\n\tINVALID_OPTION: '3.5',\n};\n\n/**\n * A failure that never got a reply. Whether the MX may nonetheless hold a\n * copy (`SmtpError.afterData`) is not said here: `attemptGroup` marks the\n * outcomes `mayHaveReachedMx` from the error.\n */\nfunction diagnosticOfError(\n\terror: unknown,\n\ttemporary: boolean,\n\tmax: number,\n\thost?: string,\n): Diagnostic {\n\tconst text = error instanceof Error ? error.message : String(error);\n\tconst detail = isSmtpError(error)\n\t\t? (ERROR_STATUS[error.code] ?? '0.0')\n\t\t: '0.0';\n\treturn {\n\t\tstatus: `${temporary ? 4 : 5}.${detail}`,\n\t\ttext: cleanText(text, max),\n\t\t...(host ? { host: cleanText(host, 255) } : {}),\n\t};\n}\n\n/** Each recipient of a delivery `sendMail` resolved: taken, or refused one by one. */\nexport function outcomesOf(\n\tresult: SendMailResult,\n\tgroup: readonly string[],\n\tmax: number,\n): RecipientUpdate[] {\n\tconst host = result.host;\n\tconst updates = new Map<string, RecipientUpdate>();\n\tfor (const { recipient } of result.accepted) {\n\t\tupdates.set(recipient, {\n\t\t\taddress: recipient,\n\t\t\tstatus: 'delivered',\n\t\t\treply: diagnosticOf(result.reply, max, host),\n\t\t});\n\t}\n\tfor (const { recipient, reply } of result.rejected) {\n\t\tupdates.set(recipient, {\n\t\t\taddress: recipient,\n\t\t\tstatus: reply.code >= 500 ? 'failed' : 'deferred',\n\t\t\treply: diagnosticOf(reply, max, host),\n\t\t});\n\t}\n\t// sendMail names every recipient it was given; a fake may not.\n\treturn group.map(\n\t\t(address) =>\n\t\t\tupdates.get(address) ?? {\n\t\t\t\taddress,\n\t\t\t\tstatus: 'deferred',\n\t\t\t\treply: {\n\t\t\t\t\ttext: 'The delivery said nothing of this recipient',\n\t\t\t\t\t...(host ? { host: cleanText(host, 255) } : {}),\n\t\t\t\t},\n\t\t\t},\n\t);\n}\n\n/**\n * Each recipient of a delivery `sendMail` rejected: by its own reply when\n * the server refused every one, else all alike — deferred when the error\n * is temporary (a 4xx, the network, a timeout) or the route's own\n * (`INVALID_OPTION`, X.3.5), failed otherwise.\n */\nexport function outcomesOfError(\n\terror: unknown,\n\tgroup: readonly string[],\n\tmax: number,\n\thost?: string,\n): RecipientUpdate[] {\n\tconst rejected = new Map(\n\t\tisSmtpError(error)\n\t\t\t? (error.rejected ?? []).map((r) => [r.recipient, r.reply])\n\t\t\t: [],\n\t);\n\tconst temporary =\n\t\t!isSmtpError(error) || error.temporary || isRouteError(error);\n\treturn group.map((address): RecipientUpdate => {\n\t\tconst own = rejected.get(address);\n\t\tif (own) {\n\t\t\treturn {\n\t\t\t\taddress,\n\t\t\t\tstatus: own.code >= 500 ? 'failed' : 'deferred',\n\t\t\t\treply: diagnosticOf(own, max, host),\n\t\t\t};\n\t\t}\n\t\tconst reply =\n\t\t\tisSmtpError(error) && error.reply\n\t\t\t\t? diagnosticOf(error.reply, max, host)\n\t\t\t\t: diagnosticOfError(error, temporary, max, host);\n\t\treturn { address, status: temporary ? 'deferred' : 'failed', reply };\n\t});\n}\n",
|
|
16
|
+
"import type { Diagnostic } from '../contract/types';\nimport { isSmtpError } from './outcome';\n\n/** Words a refusal uses when it names a blocklist or a reputation, for a server that gives no enhanced code. */\nconst REPUTATION =\n\t/\\b(?:block ?list(?:ed)?|black ?list(?:ed)?|deny ?list(?:ed)?|spamhaus|rbl|dnsbl|reputation|banned)\\b|\\bblocked\\b|\\blisted (?:in|on|at)\\b/i;\n\n/** A greylisting: a `4.7.x` that asks to come back, which a smarthost would not change. */\nconst GREYLIST = /gr[ae]y ?list/i;\n\n/**\n * Whether what the other side said (or why nobody said anything) is a\n * reason to try the fallback smarthost rather than wait: a connection\n * that failed or timed out (X.4.1, X.4.2, no reply at all), or a refusal\n * read as a matter of policy or reputation, a `4.7.x` or `5.7.x` (RFC\n * 3463 §3.8, security or policy status) or, with no enhanced code, text\n * that names a blocklist or a reputation.\n *\n * It is not a reason when the message may already be at the MX: an\n * `SmtpError` marked `afterData` (the final dot was written and no reply\n * came, a timeout or a lost connection that reads as 4.4.2) would be one\n * more copy by the smarthost, so the recipient is deferred for the MX retry\n * (RFC 5321 §4.1.5) and marked `mayHaveReachedMx`, which keeps every later\n * attempt from falling back on its own (`attemptGroup`). An `@bumail/smtp` without the field behaves as before.\n *\n * It is not a reason when the smarthost would be refused alike: an\n * unknown or full mailbox (`5.1.x`, `x.2.x`), a domain that does not\n * exist, a null MX, a route that is misconfigured, or a TLS failure of\n * the MX (an `SmtpError` coded `TLS_*`, even one that carries a reply such\n * as a refused STARTTLS `454 4.7.0`), which the operator's TLS policy meant\n * to refuse, or a greylisting (`4.7.x` whose text says so), which the MX\n * retry settles.\n */\nexport function fallsBack(\n\treply: Diagnostic | undefined,\n\terror?: unknown,\n): boolean {\n\tif (!reply) return false;\n\tif (isSmtpError(error) && error.afterData) return false;\n\tif (isSmtpError(error) && error.code.startsWith('TLS_')) return false;\n\tif (GREYLIST.test(reply.text)) return false;\n\tif (reply.code === undefined) {\n\t\treturn reply.status === '4.4.1' || reply.status === '4.4.2';\n\t}\n\tif (reply.code < 400) return false;\n\tif (reply.status !== undefined) {\n\t\treturn /^[45]\\.7\\.\\d+$/.test(reply.status);\n\t}\n\treturn REPUTATION.test(reply.text);\n}\n",
|
|
17
17
|
"import type { SendMailOptions } from '@bumail/smtp/client';\nimport type { Route } from './options';\nimport type { Settings } from './settings';\n\n/** The route for a recipient domain: its own, else the default. */\nexport function routeOf(settings: Settings, domain: string): Route {\n\treturn settings.routes.get(domain) ?? settings.options.route ?? 'mx';\n}\n\n/** The host an attempt goes to, as far as the route says: the smarthost, or nothing for MX. */\nexport function hostOf(route: Route): string | undefined {\n\treturn route === 'mx' ? undefined : route.host;\n}\n\n/** What `sendMail` takes to send one domain's recipients of a message. */\nexport function sendOptionsOf(\n\tsettings: Settings,\n\tdomain: string,\n\tfrom: string,\n\tto: readonly string[],\n\toverride?: Route,\n): SendMailOptions {\n\tconst { options, hostname } = settings;\n\tconst common = {\n\t\tfrom,\n\t\tto,\n\t\thelo: hostname,\n\t\t...(options.timeouts ? { timeouts: options.timeouts } : {}),\n\t\t...(options.deadline !== undefined ? { deadline: options.deadline } : {}),\n\t};\n\tconst route = override ?? routeOf(settings, domain);\n\tif (route === 'mx') {\n\t\tconst resolver = options.resolver;\n\t\tif (!resolver) throw new Error('unreachable: settings check the resolver');\n\t\treturn {\n\t\t\t...common,\n\t\t\tdomain,\n\t\t\tresolver,\n\t\t\t...(options.mxPort !== undefined ? { port: options.mxPort } : {}),\n\t\t\t...(options.mxTls ? { tls: options.mxTls } : {}),\n\t\t};\n\t}\n\treturn {\n\t\t...common,\n\t\thost: route.host,\n\t\t...(route.port !== undefined ? { port: route.port } : {}),\n\t\t...(route.secure !== undefined ? { secure: route.secure } : {}),\n\t\t...(route.tls ? { tls: route.tls } : {}),\n\t\t...(route.auth ? { auth: route.auth } : {}),\n\t\t...(route.ca ? { ca: route.ca } : {}),\n\t};\n}\n",
|
|
18
18
|
"import {\n\tencodeHeaderValue,\n\tencodeQuotedPrintable,\n\tfoldHeader,\n\tformatDate,\n} from '@bumail/mime';\nimport { cleanText, replaceControls } from '../text';\nimport { returned } from './content';\nimport {\n\ttype DsnKind,\n\ttype DsnRecipient,\n\tdeliveryStatus,\n\tstatusOf,\n} from './fields';\n\nexport type { DsnKind, DsnRecipient } from './fields';\n\n/** What a DSN says, about which message, to whom. */\nexport interface DsnInput {\n\treadonly kind: DsnKind;\n\t/** This server's public name: the Reporting-MTA, and the Message-ID's domain. */\n\treadonly reportingMta: string;\n\t/** The DSN's From: the postmaster's address. */\n\treadonly from: string;\n\t/** The original's sender, to whom the DSN goes. */\n\treadonly to: string;\n\t/** When the original was enqueued. */\n\treadonly arrival: Date;\n\t/** When the DSN is written. */\n\treadonly date: Date;\n\treadonly recipients: readonly DsnRecipient[];\n\t/** With `delayed`: when the queue gives up. */\n\treadonly willRetryUntil?: Date;\n\t/**\n\t * The original message, as enqueued; absent when it could not be read,\n\t * and the DSN then has no third part (RFC 6522 §3 makes it optional).\n\t */\n\treadonly original?: Uint8Array;\n\treadonly returnContent: 'headers' | 'full';\n\t/** The most bytes of the original returned. */\n\treadonly maxReturn: number;\n}\n\nconst encoder = new TextEncoder();\nconst strip = (text: string) =>\n\treplaceControls(text, '').replace(/[\\s<>]/g, '');\n\n/** The text a person reads first: what happened, to whom, and why (RFC 3464 §2's first part). */\nfunction humanText(input: DsnInput): string {\n\tconst failed = input.kind === 'failed';\n\tconst lines = failed\n\t\t? [\n\t\t\t\t`This is the mail system at ${input.reportingMta}.`,\n\t\t\t\t'',\n\t\t\t\t'Your message could not be delivered to the recipients below.',\n\t\t\t\t'This is a permanent failure: the message will not be retried.',\n\t\t\t]\n\t\t: [\n\t\t\t\t`This is the mail system at ${input.reportingMta}.`,\n\t\t\t\t'',\n\t\t\t\t'Your message has not been delivered yet to the recipients below.',\n\t\t\t\t'This is a warning only: the message is still being retried',\n\t\t\t\t...(input.willRetryUntil\n\t\t\t\t\t? [`until ${formatDate(input.willRetryUntil)}.`]\n\t\t\t\t\t: []),\n\t\t\t\t'You do not need to send it again.',\n\t\t\t];\n\tif (!input.original) {\n\t\tlines.push(\n\t\t\t'',\n\t\t\t'Your message could not be read from the queue, so it is not returned.',\n\t\t);\n\t}\n\tlines.push('');\n\tfor (const r of input.recipients) {\n\t\tconst said = r.reply\n\t\t\t? `${r.reply.code ?? ''} ${cleanText(r.reply.text, 900)}`.trim()\n\t\t\t: statusOf(input.kind);\n\t\tconst why =\n\t\t\tr.reply?.status === '4.4.7'\n\t\t\t\t? `delivery time expired, still failing: ${said}`\n\t\t\t\t: said;\n\t\tlines.push(`<${cleanText(r.address, 254)}>: ${why}`);\n\t}\n\treturn `${lines.join('\\r\\n')}\\r\\n`;\n}\n\n/** The header fields of the DSN, every value cleaned and folded. */\nfunction headerFields(input: DsnInput, boundary: string): string[] {\n\tconst subject =\n\t\tinput.kind === 'failed'\n\t\t\t? 'Undelivered Mail Returned to Sender'\n\t\t\t: 'Delayed Mail (still being retried)';\n\tconst domain = strip(input.reportingMta);\n\treturn [\n\t\tfoldHeader('Date', formatDate(input.date)),\n\t\tfoldHeader('From', `Mail Delivery System <${strip(input.from)}>`),\n\t\tfoldHeader('To', `<${strip(input.to)}>`),\n\t\tfoldHeader('Subject', encodeHeaderValue(subject)),\n\t\tfoldHeader('Message-ID', `<${crypto.randomUUID()}@${domain}>`),\n\t\t// RFC 3834 §5: an automatic answer, which no one answers automatically.\n\t\tfoldHeader('Auto-Submitted', 'auto-replied'),\n\t\tfoldHeader('MIME-Version', '1.0'),\n\t\tfoldHeader(\n\t\t\t'Content-Type',\n\t\t\t`multipart/report; report-type=delivery-status; boundary=\"${boundary}\"`,\n\t\t),\n\t];\n}\n\nconst concat = (parts: readonly Uint8Array[]): Uint8Array => {\n\tconst out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));\n\tlet at = 0;\n\tfor (const part of parts) {\n\t\tout.set(part, at);\n\t\tat += part.length;\n\t}\n\treturn out;\n};\n\n/** A boundary that occurs nowhere in what it separates. */\nfunction boundaryFor(content: Uint8Array): string {\n\tconst text = new TextDecoder('latin1').decode(content);\n\tfor (;;) {\n\t\tconst boundary = `=_dsn_${crypto.randomUUID()}`;\n\t\tif (!text.includes(boundary)) return boundary;\n\t}\n}\n\n/**\n * A delivery status notification (RFC 3464): a `multipart/report`\n * (RFC 6522) of `report-type=delivery-status` holding the text a person\n * reads, the `message/delivery-status` fields a program reads, and the\n * original's header fields (or the whole original, when asked and small\n * enough), bounded by `maxReturn` — or, with no `original`, no third\n * part at all. Nothing from the remote server or the\n * envelope reaches a header field raw: control characters, CR and LF are\n * taken out first.\n */\nexport function buildDsn(input: DsnInput): Uint8Array {\n\tconst original = input.original\n\t\t? returned(input.original, input.returnContent, input.maxReturn)\n\t\t: undefined;\n\tconst boundary = boundaryFor(original?.body ?? new Uint8Array());\n\tconst text = encodeQuotedPrintable(humanText(input));\n\tconst status = deliveryStatus({\n\t\tkind: input.kind,\n\t\treportingMta: input.reportingMta,\n\t\tarrival: input.arrival,\n\t\trecipients: input.recipients,\n\t\t...(input.willRetryUntil ? { willRetryUntil: input.willRetryUntil } : {}),\n\t});\n\tconst parts = [\n\t\t...headerFields(input, boundary),\n\t\t'',\n\t\t'This is a MIME-formatted delivery status notification.',\n\t\t'',\n\t\t`--${boundary}`,\n\t\t'Content-Type: text/plain; charset=utf-8',\n\t\t'Content-Transfer-Encoding: quoted-printable',\n\t\t'',\n\t\ttext,\n\t\t`--${boundary}`,\n\t\t'Content-Type: message/delivery-status',\n\t\t'',\n\t\tstatus,\n\t];\n\tconst end = `--${boundary}--\\r\\n`;\n\tif (!original) return encoder.encode(`${parts.join('\\r\\n')}\\r\\n${end}`);\n\tconst head = [\n\t\t...parts,\n\t\t`--${boundary}`,\n\t\t`Content-Type: ${original.type}`,\n\t\t...(original.eightBit ? ['Content-Transfer-Encoding: 8bit'] : []),\n\t\t'',\n\t\t'',\n\t].join('\\r\\n');\n\treturn concat([\n\t\tencoder.encode(head),\n\t\toriginal.body,\n\t\tencoder.encode(`\\r\\n${end}`),\n\t]);\n}\n",
|
|
19
19
|
"/** The part of a DSN that returns the original message (RFC 3464 §2, RFC 6522 §3). */\n\nconst CR = 13;\nconst LF = 10;\n\n/** RFC 5322 §2.1.1: a line is at most 998 characters, its CRLF aside. */\nexport const MAX_LINE = 998;\n\nconst isContinuation = (byte: number | undefined) =>\n\tbyte !== undefined && byte >= 0x80 && byte < 0xc0;\n\n/**\n * Every bare CR or LF as CRLF, and every line cut at 998 bytes, never in\n * the middle of a UTF-8 character: a DSN is sent as lines, whatever the\n * original held, and a longer one would get the DSN itself refused.\n */\nfunction crlf(bytes: Uint8Array): Uint8Array {\n\tconst out: number[] = [];\n\tlet column = 0;\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tconst byte = bytes[i] as number;\n\t\tif (byte === CR || byte === LF) {\n\t\t\tout.push(CR, LF);\n\t\t\tcolumn = 0;\n\t\t\tif (byte === CR && bytes[i + 1] === LF) i++;\n\t\t} else if (column < MAX_LINE) {\n\t\t\tout.push(byte);\n\t\t\tcolumn++;\n\t\t} else if (column === MAX_LINE) {\n\t\t\t// The first byte cut: drop a character it would leave half written.\n\t\t\tif (isContinuation(byte)) {\n\t\t\t\twhile (isContinuation(out.at(-1))) {\n\t\t\t\t\tout.pop();\n\t\t\t\t}\n\t\t\t\tif ((out.at(-1) ?? 0) >= 0xc0) out.pop();\n\t\t\t}\n\t\t\tcolumn++;\n\t\t}\n\t}\n\treturn Uint8Array.from(out);\n}\n\n/** Where the header block ends: past the blank line, or the whole message when it has none. */\nfunction headerEnd(bytes: Uint8Array): number {\n\tfor (let i = 0; i + 3 < bytes.length; i++) {\n\t\tif (\n\t\t\tbytes[i] === CR &&\n\t\t\tbytes[i + 1] === LF &&\n\t\t\tbytes[i + 2] === CR &&\n\t\t\tbytes[i + 3] === LF\n\t\t) {\n\t\t\treturn i + 2;\n\t\t}\n\t}\n\treturn bytes.length;\n}\n\n/** The first `max` bytes at most, cut after the last whole line. */\nfunction wholeLines(bytes: Uint8Array, max: number): Uint8Array {\n\tif (bytes.length <= max) return bytes;\n\tconst cut = bytes.subarray(0, max).lastIndexOf(LF);\n\treturn bytes.subarray(0, cut + 1);\n}\n\nexport interface Returned {\n\t/** `text/rfc822-headers` or `message/rfc822`. */\n\treadonly type: string;\n\t/** Lines ending in CRLF, the last one included. */\n\treadonly body: Uint8Array;\n\t/** It holds a byte past ASCII: the part says `8bit`. */\n\treadonly eightBit: boolean;\n}\n\n/**\n * The original as a DSN returns it: the whole message when asked and it\n * fits `max` bytes, else its header fields, cut after the last whole line\n * that fits. Never more than `max` bytes.\n */\nexport function returned(\n\toriginal: Uint8Array,\n\tmode: 'headers' | 'full',\n\tmax: number,\n): Returned {\n\tconst message = crlf(original.subarray(0, max * 2 + 2));\n\tconst whole = original.length <= max && message.length <= max;\n\tconst body =\n\t\twhole && mode === 'full'\n\t\t\t? message\n\t\t\t: wholeLines(message.subarray(0, headerEnd(message)), max);\n\treturn {\n\t\ttype: whole && mode === 'full' ? 'message/rfc822' : 'text/rfc822-headers',\n\t\tbody,\n\t\teightBit: body.some((byte) => byte > 0x7f),\n\t};\n}\n",
|
|
20
20
|
"import { foldHeader, formatDate } from '@bumail/mime';\nimport type { Diagnostic } from '../contract/types';\nimport { asciiText, replaceControls } from '../text';\n\n/** One recipient a DSN reports on. */\nexport interface DsnRecipient {\n\treadonly address: string;\n\treadonly reply?: Diagnostic;\n\t/** When it was last tried. */\n\treadonly lastAttempt: Date;\n}\n\nexport type DsnKind = 'delayed' | 'failed';\n\n/** What a delivery-status part reports: who reports, on what, and each recipient. */\nexport interface StatusReport {\n\treadonly kind: DsnKind;\n\t/** This server's name. */\n\treadonly reportingMta: string;\n\t/** When the message was enqueued. */\n\treadonly arrival: Date;\n\treadonly recipients: readonly DsnRecipient[];\n\t/** With `delayed`: when the queue gives up. */\n\treadonly willRetryUntil?: Date;\n}\n\n/** Control characters out, CR and LF first: nothing from outside starts a field of its own. */\nconst strip = (text: string) => replaceControls(text, '');\n\n/** The longest escaped address: with its field name, within 998 characters a line. */\nconst MAX_ESCAPED = 900;\n\n/**\n * An address as a delivery-status field types it: `rfc822; addr` when it\n * is ASCII; otherwise `utf-8;` with each non-ASCII character as\n * `\\x{HEX}` (RFC 6533 §3, utf-8-addr-xtext), so the part stays 7-bit,\n * cut at 900 characters so it always fits a header line.\n */\nexport function typedAddress(address: string): string {\n\tconst clean = strip(address).replace(/[\\s\\\\]/g, '');\n\tif (/^[\\x21-\\x7e]*$/.test(clean)) return `rfc822; ${clean}`;\n\tlet escaped = '';\n\tfor (const c of clean) {\n\t\tconst piece = /[\\x21-\\x7e]/.test(c)\n\t\t\t? c\n\t\t\t: `\\\\x{${(c.codePointAt(0) ?? 0).toString(16).toUpperCase()}}`;\n\t\t// One word, so it must fit a line (RFC 5322 §2.1.1): cut, never lost.\n\t\tif (escaped.length + piece.length > MAX_ESCAPED) break;\n\t\tescaped += piece;\n\t}\n\treturn `utf-8; ${escaped}`;\n}\n\n/** A host name as `dns; host`, or nothing when it is not one. */\nconst remoteMta = (host: string | undefined) =>\n\thost && /^[A-Za-z0-9.:[\\]-]{1,255}$/.test(host) ? `dns; ${host}` : undefined;\n\n/**\n * The status (RFC 3463) of a recipient: the reply's enhanced code; else\n * its class from the reply code; else, with nothing at all, the kind's.\n */\nexport function statusOf(kind: DsnKind, reply?: Diagnostic): string {\n\tif (reply?.status) return reply.status;\n\tif (reply?.code !== undefined) {\n\t\treturn reply.code >= 500 ? '5.0.0' : '4.0.0';\n\t}\n\treturn kind === 'failed' ? '5.0.0' : '4.0.0';\n}\n\n/** The fields of one recipient (RFC 3464 §2.3), folded, no line from outside. */\nfunction recipientFields(\n\treport: StatusReport,\n\trecipient: DsnRecipient,\n): string[] {\n\tconst { reply } = recipient;\n\tconst fields: [string, string][] = [\n\t\t['Final-Recipient', typedAddress(recipient.address)],\n\t\t['Action', report.kind],\n\t\t['Status', statusOf(report.kind, reply)],\n\t];\n\tconst remote = remoteMta(reply?.host);\n\tif (remote) fields.push(['Remote-MTA', remote]);\n\tif (reply) {\n\t\tconst text = asciiText(reply.text, 900);\n\t\tfields.push(\n\t\t\treply.code === undefined\n\t\t\t\t? ['Diagnostic-Code', `X-Bumail; ${text}`]\n\t\t\t\t: ['Diagnostic-Code', `smtp; ${reply.code} ${text}`],\n\t\t);\n\t}\n\tfields.push(['Last-Attempt-Date', formatDate(recipient.lastAttempt)]);\n\tif (report.kind === 'delayed' && report.willRetryUntil) {\n\t\tfields.push(['Will-Retry-Until', formatDate(report.willRetryUntil)]);\n\t}\n\treturn fields.map(([name, value]) => foldHeader(name, value));\n}\n\n/**\n * The body of a `message/delivery-status` part (RFC 3464 §2.1): the\n * per-message fields, then each recipient's, a blank line between, CRLF.\n */\nexport function deliveryStatus(report: StatusReport): string {\n\tconst message = [\n\t\tfoldHeader('Reporting-MTA', `dns; ${strip(report.reportingMta)}`),\n\t\tfoldHeader('Arrival-Date', formatDate(report.arrival)),\n\t].join('\\r\\n');\n\tconst blocks = report.recipients.map((r) =>\n\t\trecipientFields(report, r).join('\\r\\n'),\n\t);\n\treturn `${[message, ...blocks].join('\\r\\n\\r\\n')}\\r\\n`;\n}\n",
|
|
21
21
|
"import type { RetrySettings } from './settings';\n\n/**\n * The wait after the `attempts`-th attempt failed for now: `first`, then\n * `factor` times the wait before, at most `max`, plus up to `jitter` of\n * itself — never less, so RFC 5321 §4.5.4.1's 30 minutes stay a floor.\n */\nexport function retryDelay(\n\tattempts: number,\n\tretry: RetrySettings,\n\trandom: () => number,\n): number {\n\tconst exponent = Math.max(0, attempts - 1);\n\tconst delay = Math.min(retry.first * retry.factor ** exponent, retry.max);\n\treturn delay + delay * retry.jitter * Math.min(1, Math.max(0, random()));\n}\n\n/** When a message's deferred recipients give up: `giveUpAfter` after it was enqueued. */\nexport const giveUpAt = (createdAt: number, retry: RetrySettings) =>\n\tcreatedAt + retry.giveUpAfter;\n\n/**\n * The next attempt after the `attempts`-th, at `now`: the back-off, but no\n * later than the moment of giving up, so the last try falls on it.\n * `undefined` when that moment has come: what is still deferred fails.\n */\nexport function nextAttemptAt(\n\tcreatedAt: number,\n\tnow: number,\n\tattempts: number,\n\tretry: RetrySettings,\n\trandom: () => number,\n): number | undefined {\n\tconst end = giveUpAt(createdAt, retry);\n\tif (now >= end) return undefined;\n\treturn Math.min(now + retryDelay(attempts, retry, random), end);\n}\n",
|
|
22
|
-
"import type { QueueStore } from '../contract/queue-store';\nimport type { QueueItem, RecipientUpdate } from '../contract/types';\nimport { buildDsn, type DsnKind } from '../dsn/build';\nimport type { Events } from './events';\nimport { giveUpAt } from './retry';\nimport type { Settings } from './settings';\n\nexport interface NotifyContext {\n\treadonly settings: Settings;\n\treadonly store: QueueStore;\n\treadonly events: Events;\n}\n\n/**\n * Enqueues a DSN (RFC 3464) back to the item's sender for these\n * recipients, from the null sender, so it never causes one of its own.\n * Nothing for an item from the null sender (RFC 5321 §4.5.5, RFC 3464\n * §2: a DSN is never sent about a DSN). It bypasses `maxItems`: a full\n * queue loses no bounce. A failure goes to the `error` event. With no\n * `message` — the store lost it — the DSN returns nothing of it.\n */\nexport async function notify(\n\tctx: NotifyContext,\n\titem: QueueItem,\n\tmessage: Uint8Array | undefined,\n\tkind: DsnKind,\n\trecipients: readonly RecipientUpdate[],\n\tnow: number,\n): Promise<void> {\n\tif (item.from === '' || recipients.length === 0) return;\n\tconst { settings, store, events } = ctx;\n\ttry {\n\t\tconst lastAttempt = new Date(now);\n\t\tconst dsn = buildDsn({\n\t\t\tkind,\n\t\t\treportingMta: settings.hostname,\n\t\t\tfrom: settings.dsn.from,\n\t\t\tto: item.from,\n\t\t\tarrival: new Date(item.createdAt),\n\t\t\tdate: lastAttempt,\n\t\t\trecipients: recipients.map((r) =>
|
|
23
|
-
"import type {\n\tAttemptResult,\n\tQueueItem,\n\tRecipientUpdate,\n} from '../contract/types';\nimport { nextAttemptAt } from './retry';\nimport type { Settings } from './settings';\n\n/** An attempt's outcomes, sorted, and what to record and send for them. */\nexport interface Settled {\n\treadonly result: AttemptResult;\n\treadonly delivered: readonly RecipientUpdate[];\n\t/** Failed in this attempt: a 5xx, or given up. */\n\treadonly failed: readonly RecipientUpdate[];\n\t/** Still deferred, to try again at `result.nextAttemptAt`. */\n\treadonly deferred: readonly RecipientUpdate[];\n\t/** A \"delayed\" DSN is due for the deferred recipients. */\n\treadonly delayDsn: boolean;\n}\n\n/**\n * A deferred recipient past the moment of giving up: failed, as X.4.7\n * (RFC 3463 §3.5, delivery time expired), the remote reply's code and text\n * kept as they were said.\n */\nfunction expired(update: RecipientUpdate): RecipientUpdate {\n\treturn {\n\t\taddress: update.address,\n\t\tstatus: 'failed',\n\t\treply: { text: '', ...update.reply, status: '4.4.7' },\n\t};\n}\n\n/**\n * What an attempt comes to: the count, the next attempt (RFC 5321\n * §4.5.4.1's back-off, or now when some recipients were left out because\n * the worker is stopping), the deferred recipients that gave up, and\n * whether the \"delayed\" DSN is due — once, for a sender that is not null.\n */\nexport function settle(\n\titem: QueueItem,\n\tupdates: readonly RecipientUpdate[],\n\tskipped: boolean,\n\tnow: number,\n\tsettings: Settings,\n): Settled {\n\tconst attempts = item.attempts + (updates.length > 0 ? 1 : 0);\n\tconst next = nextAttemptAt(\n\t\titem.createdAt,\n\t\tnow,\n\t\tattempts,\n\t\tsettings.retry,\n\t\tsettings.random,\n\t);\n\tconst all = updates.map((u) =>\n\t\tu.status === 'deferred' && next === undefined ? expired(u) : u,\n\t);\n\tconst deferred = all.filter((u) => u.status === 'deferred');\n\tconst { delayAfter } = settings.dsn;\n\tconst delayDsn =\n\t\t!item.delayNotified &&\n\t\titem.from !== '' &&\n\t\tdelayAfter !== false &&\n\t\tdeferred.length > 0 &&\n\t\tnow - item.createdAt >= delayAfter;\n\treturn {\n\t\tresult: {\n\t\t\tnow,\n\t\t\trecipients: all,\n\t\t\t// Left out by a stop with nothing deferred: due at once. Otherwise the\n\t\t\t// back-off holds for the whole item, the left-out domains included.\n\t\t\tnextAttemptAt:\n\t\t\t\tnext === undefined || (skipped && deferred.length === 0) ? now : next,\n\t\t\tattempts,\n\t\t\tdelayNotified: item.delayNotified || delayDsn,\n\t\t},\n\t\tdelivered: all.filter((u) => u.status === 'delivered'),\n\t\tfailed: all.filter((u) => u.status === 'failed'),\n\t\tdeferred,\n\t\tdelayDsn,\n\t};\n}\n",
|
|
22
|
+
"import type { QueueStore } from '../contract/queue-store';\nimport type { Diagnostic, QueueItem, RecipientUpdate } from '../contract/types';\nimport { buildDsn, type DsnKind } from '../dsn/build';\nimport type { Events } from './events';\nimport { giveUpAt } from './retry';\nimport type { Settings } from './settings';\n\nexport interface NotifyContext {\n\treadonly settings: Settings;\n\treadonly store: QueueStore;\n\treadonly events: Events;\n}\n\n/** Said in a failed DSN of a recipient whose message the MX may hold. */\nconst MAY_HAVE_REACHED =\n\t'An earlier attempt may have reached the receiving server, so the message may have been delivered.';\n\n/** The reply a DSN reports: a failed recipient's, with a sentence more when the MX may hold the message. */\nfunction reported(r: RecipientUpdate, kind: DsnKind): Diagnostic | undefined {\n\tif (kind !== 'failed' || !r.mayHaveReachedMx) return r.reply;\n\tconst reply: Diagnostic = r.reply ?? { text: '' };\n\treturn {\n\t\t...reply,\n\t\ttext:\n\t\t\treply.text === ''\n\t\t\t\t? MAY_HAVE_REACHED\n\t\t\t\t: `${reply.text} ${MAY_HAVE_REACHED}`,\n\t};\n}\n\n/**\n * Enqueues a DSN (RFC 3464) back to the item's sender for these\n * recipients, from the null sender, so it never causes one of its own.\n * Nothing for an item from the null sender (RFC 5321 §4.5.5, RFC 3464\n * §2: a DSN is never sent about a DSN). It bypasses `maxItems`: a full\n * queue loses no bounce. A failure goes to the `error` event. With no\n * `message` — the store lost it — the DSN returns nothing of it.\n */\nexport async function notify(\n\tctx: NotifyContext,\n\titem: QueueItem,\n\tmessage: Uint8Array | undefined,\n\tkind: DsnKind,\n\trecipients: readonly RecipientUpdate[],\n\tnow: number,\n): Promise<void> {\n\tif (item.from === '' || recipients.length === 0) return;\n\tconst { settings, store, events } = ctx;\n\ttry {\n\t\tconst lastAttempt = new Date(now);\n\t\tconst dsn = buildDsn({\n\t\t\tkind,\n\t\t\treportingMta: settings.hostname,\n\t\t\tfrom: settings.dsn.from,\n\t\t\tto: item.from,\n\t\t\tarrival: new Date(item.createdAt),\n\t\t\tdate: lastAttempt,\n\t\t\trecipients: recipients.map((r) => {\n\t\t\t\tconst reply = reported(r, kind);\n\t\t\t\treturn { address: r.address, ...(reply ? { reply } : {}), lastAttempt };\n\t\t\t}),\n\t\t\t...(kind === 'delayed'\n\t\t\t\t? { willRetryUntil: new Date(giveUpAt(item.createdAt, settings.retry)) }\n\t\t\t\t: {}),\n\t\t\t...(message ? { original: message } : {}),\n\t\t\treturnContent: settings.dsn.returnContent,\n\t\t\tmaxReturn: settings.limits.maxDsnReturn,\n\t\t});\n\t\tconst added = await store.add({\n\t\t\tfrom: '',\n\t\t\tto: [item.from],\n\t\t\tmessage: dsn,\n\t\t\tcreatedAt: now,\n\t\t});\n\t\tevents.emit('dsn', {\n\t\t\tkind,\n\t\t\tid: added.id,\n\t\t\tof: item.id,\n\t\t\tto: item.from,\n\t\t\trecipients: recipients.map((r) => r.address),\n\t\t});\n\t} catch (error) {\n\t\tevents.emit('error', { error, id: item.id });\n\t}\n}\n",
|
|
23
|
+
"import type {\n\tAttemptResult,\n\tQueueItem,\n\tRecipientUpdate,\n} from '../contract/types';\nimport { nextAttemptAt } from './retry';\nimport type { Settings } from './settings';\n\n/** An attempt's outcomes, sorted, and what to record and send for them. */\nexport interface Settled {\n\treadonly result: AttemptResult;\n\treadonly delivered: readonly RecipientUpdate[];\n\t/** Failed in this attempt: a 5xx, or given up. */\n\treadonly failed: readonly RecipientUpdate[];\n\t/** Still deferred, to try again at `result.nextAttemptAt`. */\n\treadonly deferred: readonly RecipientUpdate[];\n\t/** A \"delayed\" DSN is due for the deferred recipients. */\n\treadonly delayDsn: boolean;\n}\n\n/**\n * A deferred recipient past the moment of giving up: failed, as X.4.7\n * (RFC 3463 §3.5, delivery time expired), the remote reply's code and text\n * kept as they were said.\n */\nfunction expired(update: RecipientUpdate): RecipientUpdate {\n\treturn {\n\t\taddress: update.address,\n\t\tstatus: 'failed',\n\t\treply: { text: '', ...update.reply, status: '4.4.7' },\n\t\t...(update.mayHaveReachedMx ? { mayHaveReachedMx: true as const } : {}),\n\t};\n}\n\n/**\n * What an attempt comes to: the count, the next attempt (RFC 5321\n * §4.5.4.1's back-off, or now when some recipients were left out because\n * the worker is stopping), the deferred recipients that gave up, and\n * whether the \"delayed\" DSN is due — once, for a sender that is not null.\n */\nexport function settle(\n\titem: QueueItem,\n\tupdates: readonly RecipientUpdate[],\n\tskipped: boolean,\n\tnow: number,\n\tsettings: Settings,\n): Settled {\n\tconst attempts = item.attempts + (updates.length > 0 ? 1 : 0);\n\tconst next = nextAttemptAt(\n\t\titem.createdAt,\n\t\tnow,\n\t\tattempts,\n\t\tsettings.retry,\n\t\tsettings.random,\n\t);\n\t// A recipient the MX may hold keeps its mark in what is recorded and told, whatever route or path made this outcome.\n\tconst doubtful = new Set(\n\t\titem.recipients.filter((r) => r.mayHaveReachedMx).map((r) => r.address),\n\t);\n\tconst all = updates\n\t\t.map(\n\t\t\t(u): RecipientUpdate =>\n\t\t\t\tdoubtful.has(u.address) && u.status !== 'delivered'\n\t\t\t\t\t? { ...u, mayHaveReachedMx: true }\n\t\t\t\t\t: u,\n\t\t)\n\t\t.map((u) =>\n\t\t\tu.status === 'deferred' && next === undefined ? expired(u) : u,\n\t\t);\n\tconst deferred = all.filter((u) => u.status === 'deferred');\n\tconst { delayAfter } = settings.dsn;\n\tconst delayDsn =\n\t\t!item.delayNotified &&\n\t\titem.from !== '' &&\n\t\tdelayAfter !== false &&\n\t\tdeferred.length > 0 &&\n\t\tnow - item.createdAt >= delayAfter;\n\treturn {\n\t\tresult: {\n\t\t\tnow,\n\t\t\trecipients: all,\n\t\t\t// Left out by a stop with nothing deferred: due at once. Otherwise the\n\t\t\t// back-off holds for the whole item, the left-out domains included.\n\t\t\tnextAttemptAt:\n\t\t\t\tnext === undefined || (skipped && deferred.length === 0) ? now : next,\n\t\t\tattempts,\n\t\t\tdelayNotified: item.delayNotified || delayDsn,\n\t\t},\n\t\tdelivered: all.filter((u) => u.status === 'delivered'),\n\t\tfailed: all.filter((u) => u.status === 'failed'),\n\t\tdeferred,\n\t\tdelayDsn,\n\t};\n}\n",
|
|
24
24
|
"import type { QueueItem } from '../contract/types';\nimport { QueueError } from '../errors';\nimport type { NotifyContext } from './notify';\n\n/**\n * How a lease was lost. `taken`: a renewal found the item still in the\n * store, held by another worker or by none. `expired`: the lease's last\n * expiry passed, so another worker could claim it.\n */\nexport type Lapse = 'taken' | 'expired';\n\n/** What a worker knows of its lease on an item it delivers. */\nexport interface LeaseState {\n\treadonly item: QueueItem;\n\t/** The outcome is recorded, or a renewal was refused: no more renewals count. */\n\tdone: boolean;\n\t/** The lease's last expiry this worker set: the claim's, then each renewal's. */\n\texpiresAt: number;\n\t/** A renewal was refused while the item was still in the store. */\n\ttaken: boolean;\n\t/** The look a refused renewal takes at the item. */\n\tlooking: Promise<void>;\n}\n\nexport function leaseOf(ctx: NotifyContext, item: QueueItem): LeaseState {\n\tconst { settings } = ctx;\n\treturn {\n\t\titem,\n\t\tdone: false,\n\t\texpiresAt: item.lease?.expiresAt ?? settings.now() + settings.leaseMs,\n\t\ttaken: false,\n\t\tlooking: Promise.resolve(),\n\t};\n}\n\n/** After a refused renewal: an item still there was taken, and is said so; a gone one is left to `lapsed`. */\nasync function lookAfterRefusal(\n\tctx: NotifyContext,\n\tlease: LeaseState,\n): Promise<void> {\n\tconst { id } = lease.item;\n\tif ((await ctx.store.get(id)) === undefined) return;\n\tlease.taken = true;\n\tconst error = new QueueError(\n\t\t'LEASE_LOST',\n\t\t`The lease on ${id} was lost while it was delivered`,\n\t);\n\tctx.events.emit('error', { error, id });\n}\n\n/**\n * One renewal. A renewal that is held keeps its expiry, even one that\n * lands after the outcome is recorded. One refused while the item is\n * still there — held by another worker or by none — says so once, and\n * ends the renewals; one refused for an item gone says nothing and ends\n * them: a cancel, or another worker that finished it, which `lapsed` tells\n * apart by the expiry. One that fails (the store busy, unreachable) says\n * so, and the next one tries again: the lease may still be held.\n * Resolves `false` once no more renewals are wanted.\n */\nexport async function renew(\n\tctx: NotifyContext,\n\tlease: LeaseState,\n): Promise<boolean> {\n\tconst { settings, store, events } = ctx;\n\tconst { id } = lease.item;\n\tconst next = settings.now() + settings.leaseMs;\n\tlet held: boolean;\n\ttry {\n\t\theld = await store.renew(id, settings.owner, next);\n\t} catch (error) {\n\t\tif (!lease.done) events.emit('error', { error, id });\n\t\treturn !lease.done;\n\t}\n\tif (held) lease.expiresAt = Math.max(lease.expiresAt, next);\n\tif (lease.done) return false;\n\tif (held) return true;\n\tlease.done = true;\n\tlease.looking = lookAfterRefusal(ctx, lease).catch((error: unknown) => {\n\t\tevents.emit('error', { error, id });\n\t});\n\treturn false;\n}\n\n/**\n * Whether the lease could have passed to another worker by `now`: a\n * renewal found it taken, or its last expiry is past. `undefined` while\n * it surely held, by this worker's clock.\n */\nexport async function lapsed(\n\tlease: LeaseState,\n\tnow: number,\n): Promise<Lapse | undefined> {\n\tawait lease.looking;\n\tif (lease.taken) return 'taken';\n\treturn lease.expiresAt <= now ? 'expired' : undefined;\n}\n\n/** Resolves once the look a refused renewal took at the item is over. */\nexport const settled = (lease: LeaseState): Promise<void> => lease.looking;\n",
|
|
25
25
|
"/** A count of slots: who asks past it waits, first come first served. */\nexport class Limiter {\n\treadonly #size: number;\n\t#used = 0;\n\treadonly #waiting: (() => void)[] = [];\n\n\tconstructor(size: number) {\n\t\tthis.#size = size;\n\t}\n\n\t/** A slot, once one is free; call what it resolves to, once, to give it back. */\n\tasync acquire(): Promise<() => void> {\n\t\tif (this.#used >= this.#size) {\n\t\t\tawait new Promise<void>((resolve) => this.#waiting.push(resolve));\n\t\t} else {\n\t\t\tthis.#used++;\n\t\t}\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tconst next = this.#waiting.shift();\n\t\t\t// The slot passes to the next in line without being freed in between.\n\t\t\tif (next) next();\n\t\t\telse this.#used--;\n\t\t};\n\t}\n}\n\n/** One `Limiter` per key, made when first asked for and dropped once idle. */\nexport class KeyedLimiter {\n\treadonly #size: number;\n\treadonly #limiters = new Map<string, { limiter: Limiter; users: number }>();\n\n\tconstructor(size: number) {\n\t\tthis.#size = size;\n\t}\n\n\tasync acquire(key: string): Promise<() => void> {\n\t\tlet entry = this.#limiters.get(key);\n\t\tif (!entry) {\n\t\t\tentry = { limiter: new Limiter(this.#size), users: 0 };\n\t\t\tthis.#limiters.set(key, entry);\n\t\t}\n\t\tentry.users++;\n\t\tconst release = await entry.limiter.acquire();\n\t\tconst held = entry;\n\t\treturn () => {\n\t\t\trelease();\n\t\t\tif (--held.users === 0) this.#limiters.delete(key);\n\t\t};\n\t}\n}\n",
|
|
26
26
|
"import type { QueueItem } from '../contract/types';\nimport { deliverItem } from './deliver';\nimport { type LeaseState, lapsed, leaseOf, renew, settled } from './lease';\nimport { KeyedLimiter, Limiter } from './limiter';\nimport type { NotifyContext } from './notify';\n\n/**\n * Claims due items and delivers them, at most `concurrency` at once,\n * renewing each lease while its item is delivered. `start()` runs passes\n * every `pollInterval`, or at once when woken; `stop()` lets every\n * delivery under way finish and gives back what it had not started.\n */\nexport class Worker {\n\treadonly #ctx: NotifyContext;\n\treadonly #slots: Limiter;\n\treadonly #domains: KeyedLimiter;\n\treadonly #inFlight = new Set<Promise<void>>();\n\t#stopping = false;\n\t/** `start()` was called while a `stop()` was under way: start again once it ends. */\n\t#restart = false;\n\t#loop: Promise<void> | undefined;\n\t#wake: (() => void) | undefined;\n\t/** A wake came while no sleep was under way: the next sleep is skipped. */\n\t#woken = false;\n\n\tconstructor(ctx: NotifyContext) {\n\t\tthis.#ctx = ctx;\n\t\tthis.#slots = new Limiter(ctx.settings.concurrency);\n\t\tthis.#domains = new KeyedLimiter(ctx.settings.perDomain);\n\t}\n\n\t/** Renews the lease every third of it until the outcome is recorded, or a renewal ends them. */\n\t#renewing(lease: LeaseState): () => void {\n\t\tconst timer = setInterval(() => {\n\t\t\tvoid renew(this.#ctx, lease).then((more) => {\n\t\t\t\tif (!more) clearInterval(timer);\n\t\t\t});\n\t\t}, this.#ctx.settings.leaseMs / 3);\n\t\ttimer.unref?.();\n\t\treturn () => {\n\t\t\tlease.done = true;\n\t\t\tclearInterval(timer);\n\t\t};\n\t}\n\n\tasync #deliver(item: QueueItem): Promise<void> {\n\t\tconst lease = leaseOf(this.#ctx, item);\n\t\tconst stop = this.#renewing(lease);\n\t\ttry {\n\t\t\tawait deliverItem(\n\t\t\t\t{\n\t\t\t\t\t...this.#ctx,\n\t\t\t\t\tdomains: this.#domains,\n\t\t\t\t\tstopping: () => this.#stopping,\n\t\t\t\t\trecorded: stop,\n\t\t\t\t\tleaseLapsed: (now) => lapsed(lease, now),\n\t\t\t\t},\n\t\t\t\titem,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.#ctx.events.emit('error', { error, id: item.id });\n\t\t} finally {\n\t\t\tstop();\n\t\t\t// A refused renewal's look at the item ends with the delivery.\n\t\t\tawait settled(lease);\n\t\t}\n\t}\n\n\t/** The next due item, or `undefined` when nothing is, or the worker is stopping. */\n\t#claim(): Promise<QueueItem | undefined> {\n\t\tconst { settings, store } = this.#ctx;\n\t\tif (this.#stopping) return Promise.resolve(undefined);\n\t\treturn store.claim({\n\t\t\towner: settings.owner,\n\t\t\tnow: settings.now(),\n\t\t\tleaseMs: settings.leaseMs,\n\t\t});\n\t}\n\n\t/**\n\t * One pass: claims and delivers every item due, `concurrency` at a time,\n\t * claiming again as each one ends — so a DSN enqueued meanwhile goes in\n\t * the same pass. Resolves once all are done, with how many it claimed.\n\t */\n\tasync deliverDue(): Promise<number> {\n\t\tconst mine = new Set<Promise<void>>();\n\t\tlet claimed = 0;\n\t\twhile (!this.#stopping) {\n\t\t\tconst release = await this.#slots.acquire();\n\t\t\tlet item: QueueItem | undefined;\n\t\t\ttry {\n\t\t\t\titem = await this.#claim();\n\t\t\t} catch (error) {\n\t\t\t\trelease();\n\t\t\t\tawait Promise.all(mine);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (!item) {\n\t\t\t\trelease();\n\t\t\t\tif (mine.size === 0) break;\n\t\t\t\tawait Promise.race(mine);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tclaimed++;\n\t\t\tconst delivery: Promise<void> = this.#deliver(item).finally(() => {\n\t\t\t\trelease();\n\t\t\t\tmine.delete(delivery);\n\t\t\t\tthis.#inFlight.delete(delivery);\n\t\t\t});\n\t\t\tmine.add(delivery);\n\t\t\tthis.#inFlight.add(delivery);\n\t\t}\n\t\tawait Promise.all(mine);\n\t\treturn claimed;\n\t}\n\n\t/** Wakes a sleeping `start()` loop, or spares it its next sleep: something was enqueued. */\n\twake(): void {\n\t\tif (this.#wake) this.#wake();\n\t\telse this.#woken = true;\n\t}\n\n\tstart(): void {\n\t\tif (this.#stopping) {\n\t\t\tthis.#restart = true;\n\t\t\treturn;\n\t\t}\n\t\tif (this.#loop) return;\n\t\tthis.#loop = this.#run();\n\t}\n\n\tasync #sleep(): Promise<void> {\n\t\tif (this.#woken) {\n\t\t\tthis.#woken = false;\n\t\t\treturn;\n\t\t}\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst timer = setTimeout(resolve, this.#ctx.settings.pollInterval);\n\t\t\tthis.#wake = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t});\n\t\tthis.#wake = undefined;\n\t}\n\n\tasync #run(): Promise<void> {\n\t\twhile (!this.#stopping) {\n\t\t\tthis.#woken = false;\n\t\t\ttry {\n\t\t\t\tawait this.deliverDue();\n\t\t\t} catch (error) {\n\t\t\t\tthis.#ctx.events.emit('error', { error });\n\t\t\t}\n\t\t\tif (this.#stopping) break;\n\t\t\tawait this.#sleep();\n\t\t}\n\t}\n\n\t/**\n\t * Claims nothing more, lets every delivery under way end, and gives back\n\t * what was claimed but not started, due at once for the next worker. A\n\t * `start()` called meanwhile starts again once this ends.\n\t */\n\tasync stop(): Promise<void> {\n\t\tthis.#restart = false;\n\t\tthis.#stopping = true;\n\t\tthis.#wake?.();\n\t\tawait this.#loop;\n\t\tawait Promise.all(this.#inFlight);\n\t\tthis.#loop = undefined;\n\t\tthis.#stopping = false;\n\t\tif (this.#restart) {\n\t\t\tthis.#restart = false;\n\t\t\tthis.start();\n\t\t}\n\t}\n}\n",
|
|
27
27
|
"import type { QueueItem, QueueListOptions } from '../contract/types';\nimport {\n\tcheckEnvelope,\n\tcheckLineEnds,\n\ttype MessageSource,\n\ttype QueueEnvelope,\n\treadMessage,\n} from './envelope';\nimport { Events, type QueueEvents, type QueueListener } from './events';\nimport type { QueueOptions } from './options';\nimport { settingsOf } from './settings';\nimport { Worker } from './worker';\n\n/** The outbound queue: what the app enqueues, delivered across restarts. */\nexport interface Queue {\n\t/** This worker's name on its leases. */\n\treadonly owner: string;\n\t/**\n\t * Takes a message to send — already signed, as it will leave — with its\n\t * envelope, and keeps it in the store, every recipient pending, due at\n\t * once. Refuses with `INVALID`, `MESSAGE_TOO_BIG`,\n\t * `TOO_MANY_RECIPIENTS` or `QUEUE_FULL`. The queue sends whatever it is\n\t * given: authenticate the submitter before you enqueue.\n\t */\n\tenqueue(message: MessageSource, envelope: QueueEnvelope): Promise<QueueItem>;\n\t/** One pass by hand: delivers every item due now; resolves with how many it claimed. */\n\tdeliverDue(): Promise<number>;\n\t/** Delivers in the background: a pass every `pollInterval`, and at once after `enqueue`. */\n\tstart(): void;\n\t/** Claims nothing more, lets the deliveries under way end, and gives back the rest. */\n\tstop(): Promise<void>;\n\t/** Listens to an event; returns what stops listening. */\n\ton<E extends keyof QueueEvents>(\n\t\tevent: E,\n\t\tlistener: QueueListener<E>,\n\t): () => void;\n\t/** The items in the queue, the next due first. */\n\tlist(options?: QueueListOptions): Promise<QueueItem[]>;\n\tget(id: string): Promise<QueueItem | undefined>;\n\t/**\n\t * Makes an item due now, and wakes the worker. False when there is no\n\t * such item, or when a worker is delivering it: its outcome sets the\n\t * next attempt, so asking now would change nothing.\n\t */\n\tretryNow(id: string): Promise<boolean>;\n\t/** Drops an item, its message and its recipients, with no DSN; the item as it stood, or `undefined`. */\n\tcancel(id: string): Promise<QueueItem | undefined>;\n}\n\n/**\n * Creates the queue over a store. Nothing is delivered until `start()`,\n * or `deliverDue()` by hand. Several queues — in one process or several —\n * may share a store: each claims items under its own `owner`.\n */\nexport function createQueue(options: QueueOptions): Queue {\n\tconst settings = settingsOf(options);\n\tconst store = options.store;\n\tconst events = new Events();\n\tconst worker = new Worker({ settings, store, events });\n\tconst { limits } = settings;\n\treturn {\n\t\towner: settings.owner,\n\t\tasync enqueue(message, envelope) {\n\t\t\tconst { from, to } = checkEnvelope(envelope, limits.maxRecipients);\n\t\t\tconst bytes = await readMessage(message, limits.maxMessageSize);\n\t\t\tcheckLineEnds(bytes);\n\t\t\tconst item = await store.add(\n\t\t\t\t{ from, to, message: bytes, createdAt: settings.now() },\n\t\t\t\tlimits.maxItems === undefined ? {} : { maxItems: limits.maxItems },\n\t\t\t);\n\t\t\tworker.wake();\n\t\t\treturn item;\n\t\t},\n\t\tdeliverDue: () => worker.deliverDue(),\n\t\tstart: () => worker.start(),\n\t\tstop: () => worker.stop(),\n\t\ton: (event, listener) => events.on(event, listener),\n\t\tlist: (listOptions) => store.list(listOptions),\n\t\tget: (id) => store.get(id),\n\t\tasync retryNow(id) {\n\t\t\tconst now = settings.now();\n\t\t\tconst lease = (await store.get(id))?.lease;\n\t\t\tif (lease && lease.expiresAt > now) return false;\n\t\t\tconst moved = await store.reschedule(id, now);\n\t\t\tif (moved) worker.wake();\n\t\t\treturn moved;\n\t\t},\n\t\tcancel: (id) => store.cancel(id),\n\t};\n}\n"
|
|
28
28
|
],
|
|
29
|
-
"mappings": "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",
|
|
30
|
-
"debugId": "
|
|
29
|
+
"mappings": "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",
|
|
30
|
+
"debugId": "CD3446FD48B7ED9C64756E2164756E21",
|
|
31
31
|
"names": []
|
|
32
32
|
}
|
package/dist/memory/index.js
CHANGED
package/dist/postgres/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attempt.d.ts","sourceRoot":"","sources":["../../src/queue/attempt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"attempt.d.ts","sourceRoot":"","sources":["../../src/queue/attempt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA8B/C,wEAAwE;AACxE,MAAM,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC;AAgD1E;;;;;;GAMG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GACrB,OAAO,CAAC,eAAe,EAAE,CAAC,CAuD5B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/queue/deliver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAIpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,UAAU,CAAC;AAGtD,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACrD,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;IACjC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;CAClE;
|
|
1
|
+
{"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/queue/deliver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAIpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,UAAU,CAAC;AAGtD,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACrD,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;IACjC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;CAClE;AA6FD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,CAuCf"}
|
package/dist/queue/events.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface RecipientEvent {
|
|
|
21
21
|
* before the smarthost took over: `reply` is the smarthost's.
|
|
22
22
|
*/
|
|
23
23
|
readonly mxReply?: Diagnostic;
|
|
24
|
+
/**
|
|
25
|
+
* Only on `deferred` and `failed`: `true` when a session by MX ended
|
|
26
|
+
* after the final dot with no reply, so the MX may hold a copy and the
|
|
27
|
+
* queue never fell back to a smarthost for this recipient on its own.
|
|
28
|
+
*/
|
|
29
|
+
readonly mayHaveReachedMx?: true;
|
|
24
30
|
}
|
|
25
31
|
export interface DeferredEvent extends RecipientEvent {
|
|
26
32
|
/** When the recipient is tried again, in milliseconds since the epoch. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/queue/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC9B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/queue/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC9B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACpD,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AAED,0CAA0C;AAC1C,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IACpC,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,gGAAgG;AAChG,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,eAAe,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,WAAW,IAAI,CACxD,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KACjB,IAAI,CAAC;AAEV,iFAAiF;AACjF,qBAAa,MAAM;;IAGlB,EAAE,CAAC,CAAC,SAAS,MAAM,WAAW,EAC7B,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GACxB,MAAM,IAAI;IAYb,IAAI,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;CAS1E"}
|
package/dist/queue/fallback.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ import type { Diagnostic } from '../contract/types';
|
|
|
11
11
|
* `SmtpError` marked `afterData` (the final dot was written and no reply
|
|
12
12
|
* came, a timeout or a lost connection that reads as 4.4.2) would be one
|
|
13
13
|
* more copy by the smarthost, so the recipient is deferred for the MX retry
|
|
14
|
-
* (RFC 5321 §4.1.5)
|
|
14
|
+
* (RFC 5321 §4.1.5) and marked `mayHaveReachedMx`, which keeps every later
|
|
15
|
+
* attempt from falling back on its own (`attemptGroup`). An `@bumail/smtp` without the field behaves as before.
|
|
15
16
|
*
|
|
16
17
|
* It is not a reason when the smarthost would be refused alike: an
|
|
17
18
|
* unknown or full mailbox (`5.1.x`, `x.2.x`), a domain that does not
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../../src/queue/fallback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAUpD
|
|
1
|
+
{"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../../src/queue/fallback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAUpD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CACxB,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,KAAK,CAAC,EAAE,OAAO,GACb,OAAO,CAaT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/queue/notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/queue/notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAc,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAmBD;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAuCf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../../src/queue/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EACL,cAAc,EACd,SAAS,EAET,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGrE;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,SAGC,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,OACQ,CAAC;AAKvD,8CAA8C;AAC9C,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GACX,UAAU,CAWZ;
|
|
1
|
+
{"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../../src/queue/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EACL,cAAc,EACd,SAAS,EAET,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGrE;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,SAGC,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,OACQ,CAAC;AAKvD,8CAA8C;AAC9C,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GACX,UAAU,CAWZ;AA0CD,sFAAsF;AACtF,wBAAgB,UAAU,CACzB,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,GAAG,EAAE,MAAM,GACT,eAAe,EAAE,CA6BnB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GACX,eAAe,EAAE,CAuBnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settle.d.ts","sourceRoot":"","sources":["../../src/queue/settle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EACT,eAAe,EACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,2EAA2E;AAC3E,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;IAC/C,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;IAC5C,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"settle.d.ts","sourceRoot":"","sources":["../../src/queue/settle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EACT,eAAe,EACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,2EAA2E;AAC3E,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;IAC/C,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;IAC5C,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC3B;AAgBD;;;;;GAKG;AACH,wBAAgB,MAAM,CACrB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,GAChB,OAAO,CA+CT"}
|
package/dist/redis/index.js
CHANGED
package/dist/sqlite/index.js
CHANGED
package/docs/guide.md
CHANGED
|
@@ -163,13 +163,35 @@ domains whose route is `'mx'` can fall back.
|
|
|
163
163
|
A connection lost or a timeout *after* the final dot of `DATA` does not
|
|
164
164
|
fall back either, though it reads as `4.4.2`: the MX may already have taken
|
|
165
165
|
the message (RFC 5321 §4.1.5), and the smarthost would send it a second
|
|
166
|
-
time. `@bumail/smtp` marks that error `afterData`; the
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
time. `@bumail/smtp` marks that error `afterData`; the queue then records
|
|
167
|
+
`mayHaveReachedMx: true` on the recipient (`RecipientState`, read by `get`
|
|
168
|
+
and `list`), which the store keeps once the attempt is recorded
|
|
169
|
+
(`complete`): a worker that crashes or loses its lease before that
|
|
170
|
+
records nothing, so the mark is not there ([a crashed
|
|
171
|
+
worker](#several-workers-leases-and-stopping)). The recipient is deferred and
|
|
172
|
+
every later attempt goes to the MX only, with the normal back-off, even
|
|
173
|
+
when it cannot reach the MX (a connection failure that would otherwise
|
|
174
|
+
fall back): the mark blocks the *automatic* fallback, for that recipient
|
|
175
|
+
alone. A duplicate is still possible on a retry to the MX, as it is for
|
|
176
|
+
any sender that did not see the reply. If the MX stays unreachable until
|
|
177
|
+
`retry.giveUpAfter`, the recipient fails as `4.4.7` with the usual failed
|
|
178
|
+
DSN, whose diagnostic adds that an earlier attempt may have reached the
|
|
179
|
+
receiving server, so the message may have been delivered. The `deferred`
|
|
180
|
+
and `failed` events of a marked recipient carry `mayHaveReachedMx: true`.
|
|
181
|
+
A recipient the MX refused at `RCPT` in a session that then failed after
|
|
182
|
+
the final dot is marked too, until
|
|
183
|
+
[#149](https://github.com/softistx/bumail/issues/149).
|
|
184
|
+
An `@bumail/smtp` older than the field behaves as before.
|
|
185
|
+
|
|
186
|
+
An explicit route is still followed: if the operator sets a smarthost for
|
|
187
|
+
the domain (`route` or `routes`), a marked recipient is sent there at the
|
|
188
|
+
next attempt. Only the automatic fallback is blocked.
|
|
189
|
+
|
|
190
|
+
Two things to know when upgrading from 0.6. A recipient deferred under
|
|
191
|
+
0.6 after the final dot carries no mark and is not backfilled: it may
|
|
192
|
+
still fall back once, as it did. And all the workers on one store are
|
|
193
|
+
upgraded together, since a 0.6 worker that completes an attempt drops the
|
|
194
|
+
mark it does not know.
|
|
173
195
|
|
|
174
196
|
Another risk to know: a `5.7.1` the MX gave and the smarthost accepted may
|
|
175
197
|
still bounce later from the provider, as a DSN to the sender, since the
|
|
@@ -398,8 +420,8 @@ off(); // stops listening
|
|
|
398
420
|
| event | payload |
|
|
399
421
|
| --- | --- |
|
|
400
422
|
| `delivered` | `{ id, from, recipient, reply?, attempts, route?, fallback?, mxReply? }`: `route` is `'mx'` or `'smarthost'`, `fallback` is `true` after the [fallback](#falling-back-to-a-smarthost), `mxReply` the MX's reply that led to it |
|
|
401
|
-
| `deferred` | the same, and `nextAttemptAt` |
|
|
402
|
-
| `failed` | the same as `delivered` |
|
|
423
|
+
| `deferred` | the same, and `nextAttemptAt`, and `mayHaveReachedMx: true` when the MX may hold a copy ([why](#falling-back-to-a-smarthost)) |
|
|
424
|
+
| `failed` | the same as `delivered`, and `mayHaveReachedMx: true` as for `deferred` |
|
|
403
425
|
| `dsn` | `{ kind: 'delayed' \| 'failed', id, of, to, recipients }`: `id` is the DSN's own item, `of` the item it reports on |
|
|
404
426
|
| `error` | `{ error, id? }`: a store that failed (a lease renewal included), a DSN that could not be enqueued, a lease lost (`LEASE_LOST`), a message the store lost (`MESSAGE_UNREADABLE`), a route `sendMail` refused (`INVALID_OPTION`) |
|
|
405
427
|
|
|
@@ -853,6 +875,13 @@ codes, and keeps its promises:
|
|
|
853
875
|
of the lease, in one step and only for the lease's owner; a final
|
|
854
876
|
status is never changed; an item whose every recipient is final is
|
|
855
877
|
dropped with its message.
|
|
878
|
+
- `complete` records a recipient's `mayHaveReachedMx: true` (on its
|
|
879
|
+
`RecipientUpdate`) and keeps it: `get`, `list` and `claim` return it on
|
|
880
|
+
the `RecipientState`, a later outcome without it never clears it, and
|
|
881
|
+
the store never writes `false`. Without it the queue falls back to a
|
|
882
|
+
smarthost for a recipient the MX may already hold. A 0.6 worker drops
|
|
883
|
+
the mark when it completes an attempt, so upgrade every worker on a
|
|
884
|
+
store together.
|
|
856
885
|
- Times are given by the caller; the store keeps no clock.
|
|
857
886
|
- Nothing it returns is shared with what it keeps.
|
|
858
887
|
- `reschedule` with an owner refuses an empty owner as `INVALID`, even
|
package/docs/roadmap.md
CHANGED
|
@@ -20,6 +20,10 @@ Nothing in progress.
|
|
|
20
20
|
connections.
|
|
21
21
|
- **The contract's specs, exported**, so a store written outside this
|
|
22
22
|
package can hold itself to them.
|
|
23
|
+
- **The reverse doubt** — a recipient whose session by the smarthost
|
|
24
|
+
ended after the final dot with no reply is not yet marked either: the
|
|
25
|
+
queue could keep that doubt too, and not send it again by MX (issue
|
|
26
|
+
#144).
|
|
23
27
|
- **A DSN that cannot be lost on a crash** — today a crash between
|
|
24
28
|
recording a failure and enqueuing its DSN loses that DSN; the store
|
|
25
29
|
will take both in one step.
|
|
@@ -51,6 +55,14 @@ Nothing in progress.
|
|
|
51
55
|
|
|
52
56
|
## Shipped
|
|
53
57
|
|
|
58
|
+
### Unreleased
|
|
59
|
+
|
|
60
|
+
- **The MX's doubt is remembered** — a recipient whose session by MX ended
|
|
61
|
+
after the final dot with no reply is marked `mayHaveReachedMx`, kept by
|
|
62
|
+
every store: no later attempt falls back to the smarthost on its own, it
|
|
63
|
+
stays on the MX until `retry.giveUpAfter` (a `4.4.7` DSN that says so),
|
|
64
|
+
and the `deferred` and `failed` events carry the mark.
|
|
65
|
+
|
|
54
66
|
### 0.5.0
|
|
55
67
|
|
|
56
68
|
- **A fallback smarthost** — `fallback`: a recipient
|
package/docs/troubleshooting.md
CHANGED
|
@@ -371,7 +371,9 @@ own that refuses its options. It is the route's fault, not the
|
|
|
371
371
|
recipient's: the recipients are deferred as `4.3.5` (system incorrectly
|
|
372
372
|
configured), not failed, so no DSN goes out for it until
|
|
373
373
|
`retry.giveUpAfter` (5 days by default), when they fail as `4.4.7` with a
|
|
374
|
-
DSN like any deferred recipient
|
|
374
|
+
DSN like any deferred recipient (for a recipient marked `mayHaveReachedMx`,
|
|
375
|
+
the failed DSN's diagnostic adds that the message may have been delivered;
|
|
376
|
+
see [a recipient stays `deferred` with `4.4.1` or `4.4.2`](#a-recipient-stays-deferred-with-441-or-442)).
|
|
375
377
|
**Fix:** read the message, fix the option, restart: the deferred items
|
|
376
378
|
go out on their next attempt, or at once with `retryNow`.
|
|
377
379
|
|
|
@@ -730,9 +732,15 @@ cloud provider.
|
|
|
730
732
|
A `4.4.2` from a connection lost or a timeout after the final dot of
|
|
731
733
|
`DATA` is different: the MX may have taken the message, so the recipient
|
|
732
734
|
is deferred for the MX retry, not sent by the `fallback` smarthost in the
|
|
733
|
-
same delivery
|
|
734
|
-
|
|
735
|
-
|
|
735
|
+
same delivery, and marked `mayHaveReachedMx: true` (on the `deferred` event
|
|
736
|
+
and on `RecipientState`): no later attempt falls back on its own, even when
|
|
737
|
+
the MX cannot be reached, until `retry.giveUpAfter` fails it as `4.4.7`; that failed DSN's diagnostic
|
|
738
|
+
adds that an earlier attempt may have reached the receiving server, so the
|
|
739
|
+
message may have been delivered.
|
|
740
|
+
A `4.4.x` that never falls back to the smarthost you configured is that
|
|
741
|
+
mark. Wait for the MX, or cancel the item; to send it by the smarthost
|
|
742
|
+
anyway, accepting a possible second copy, route the domain to it
|
|
743
|
+
explicitly (`routes`).
|
|
736
744
|
**Fix:** route through a smarthost on port 587 or 465:
|
|
737
745
|
|
|
738
746
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bumail/queue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "The outbound mail queue of a mail server: every recipient's state, retries with back-off, delivery status notifications (RFC 3464), leases for several workers, and a memory, a bun:sqlite, a PostgreSQL (Bun.sql) and a Redis (Bun.redis) store, delivering through @bumail/smtp/client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/errors.ts", "../src/text.ts", "../src/contract/checks.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/**\n * Why the queue or a store refused a call. `INVALID`: an option or an\n * argument it cannot take. `MESSAGE_TOO_BIG`, `TOO_MANY_RECIPIENTS` and\n * `QUEUE_FULL`: a limit `enqueue` enforces. `CLOSED`: a store used after\n * `close()`. `LEASE_LOST`: given to the `error` event when another worker\n * took an item before its outcome was recorded — or, once the lease's\n * expiry passed, when the item is gone: lost or cancelled.\n * `MESSAGE_UNREADABLE`: given to the `error` event when the store holds an\n * item but not its message, whose pending recipients then fail.\n */\nexport type QueueErrorCode =\n\t| 'INVALID'\n\t| 'MESSAGE_TOO_BIG'\n\t| 'TOO_MANY_RECIPIENTS'\n\t| 'QUEUE_FULL'\n\t| 'CLOSED'\n\t| 'LEASE_LOST'\n\t| 'MESSAGE_UNREADABLE';\n\n/** Thrown by the queue and by every store, whichever answers the contract, with the same codes. */\nexport class QueueError extends Error {\n\toverride readonly name = 'QueueError';\n\treadonly code: QueueErrorCode;\n\n\tconstructor(code: QueueErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n}\n\n/** `INVALID`, for an option or an argument. */\nexport const invalid = (message: string) => new QueueError('INVALID', message);\n",
|
|
6
|
-
"/** Text from the other side, made safe to keep and to write in a header field. */\n\n/** C0, DEL and C1: every control character, CR, LF and TAB included. */\nconst isControl = (code: number) =>\n\tcode < 0x20 || (code >= 0x7f && code <= 0x9f);\n\n/** Whether the text holds a control character. */\nexport function hasControl(text: string): boolean {\n\tfor (let i = 0; i < text.length; i++) {\n\t\tif (isControl(text.charCodeAt(i))) return true;\n\t}\n\treturn false;\n}\n\n/** Each control character replaced by `by`. */\nexport function replaceControls(text: string, by: string): string {\n\tlet out = '';\n\tfor (let i = 0; i < text.length; i++) {\n\t\tout += isControl(text.charCodeAt(i)) ? by : (text[i] as string);\n\t}\n\treturn out;\n}\n\n/**\n * Every control character (CR and LF included) as a space, a lone\n * surrogate as U+FFFD, runs of space as one, cut at `max` characters with\n * `...`, never inside a surrogate pair: what a reply leaves in an item,\n * an event and a DSN.\n */\nexport function cleanText(text: string, max: number): string {\n\tconst clean = replaceControls(text.toWellFormed(), ' ')\n\t\t.replace(/ {2,}/g, ' ')\n\t\t.trim();\n\treturn clean.length > max ? `${cut(clean, max - 3)}...` : clean;\n}\n\n/**\n * The first `length` UTF-16 units, never ending inside a surrogate pair:\n * a lone surrogate is text no store can keep (PostgreSQL's `jsonb` refuses\n * it), nor any UTF-8 encode.\n */\nfunction cut(text: string, length: number): string {\n\tconst head = text.slice(0, length);\n\tconst last = head.charCodeAt(head.length - 1);\n\treturn last >= 0xd800 && last <= 0xdbff ? head.slice(0, -1) : head;\n}\n\n/**\n * Text every store can keep: no NUL (PostgreSQL's `text` and `jsonb` hold\n * none) and no lone surrogate. `cleanText`'s output always is.\n */\nexport const isStorable = (text: string): boolean =>\n\ttext.isWellFormed() && !text.includes('\\0');\n\n/** `cleanText`, then anything not printable ASCII as `?`: for a `message/delivery-status` field. */\nexport const asciiText = (text: string, max: number): string =>\n\tcleanText(text, max).replace(/[^ -~]/g, '?');\n",
|
|
7
|
-
"import { invalid } from '../errors';\nimport { isStorable } from '../text';\nimport type {\n\tAttemptResult,\n\tClaimRequest,\n\tDiagnostic,\n\tNewQueueItem,\n\tQueueItem,\n\tQueueListOptions,\n\tRecipientState,\n\tRecipientUpdate,\n} from './types';\n\n/** What every store checks the same way, so each refuses the same input with the same error. */\n\nconst isTime = (value: unknown): value is number =>\n\ttypeof value === 'number' && Number.isFinite(value);\n\n/** A time in milliseconds since the epoch, or `INVALID` naming it. */\nexport function checkTime(name: string, value: unknown): number {\n\tif (!isTime(value)) throw invalid(`${name} must be a finite number`);\n\treturn value;\n}\n\n/**\n * Text a store keeps: refused, the same way by every store, when it holds\n * a NUL or a lone surrogate, which PostgreSQL cannot keep and no UTF-8\n * encode can carry.\n */\nexport function checkStorable(name: string, text: string): void {\n\tif (!isStorable(text)) {\n\t\tthrow invalid(\n\t\t\t`${name} holds a NUL or a lone surrogate, which a store cannot keep`,\n\t\t);\n\t}\n}\n\n/** A lease owner: a non-empty string. */\nexport function checkOwner(owner: unknown): string {\n\tif (typeof owner !== 'string' || owner === '') {\n\t\tthrow invalid('owner must be a non-empty string');\n\t}\n\tcheckStorable('owner', owner);\n\treturn owner;\n}\n\n/** Every text of a recipient's outcome. */\nfunction checkUpdate(update: RecipientUpdate): void {\n\tcheckStorable('A recipient', update.address);\n\tconst reply = update.reply as Partial<Diagnostic> | undefined;\n\tif (reply === undefined) return;\n\tif (\n\t\ttypeof reply !== 'object' ||\n\t\treply === null ||\n\t\ttypeof reply.text !== 'string'\n\t) {\n\t\tthrow invalid('A reply is an object with a text');\n\t}\n\tcheckStorable('reply.text', reply.text);\n\tfor (const name of ['status', 'host'] as const) {\n\t\tconst value = reply[name];\n\t\tif (value === undefined) continue;\n\t\tif (typeof value !== 'string')\n\t\t\tthrow invalid(`reply.${name} must be a string`);\n\t\tcheckStorable(`reply.${name}`, value);\n\t}\n}\n\nexport function checkNewItem(item: NewQueueItem): void {\n\tif (typeof item !== 'object' || item === null) {\n\t\tthrow invalid('A new item is an object');\n\t}\n\tif (typeof item.from !== 'string') throw invalid('from must be a string');\n\tcheckStorable('from', item.from);\n\tconst to = item.to as unknown;\n\tif (\n\t\t!Array.isArray(to) ||\n\t\tto.length === 0 ||\n\t\t!to.every((a) => typeof a === 'string' && a !== '')\n\t) {\n\t\tthrow invalid('to must be a non-empty array of addresses');\n\t}\n\tfor (const address of to as string[]) checkStorable('A recipient', address);\n\tif (!(item.message instanceof Uint8Array)) {\n\t\tthrow invalid('message must be a Uint8Array');\n\t}\n\tcheckTime('createdAt', item.createdAt);\n}\n\n/** `maxItems`: a positive integer, or nothing. */\nexport function checkMaxItems(max: unknown): number | undefined {\n\tif (max === undefined) return undefined;\n\tif (typeof max !== 'number' || !Number.isInteger(max) || max < 1) {\n\t\tthrow invalid(`maxItems must be an integer of at least 1, not ${max}`);\n\t}\n\treturn max;\n}\n\nexport function checkClaim(request: ClaimRequest): void {\n\tif (typeof request !== 'object' || request === null) {\n\t\tthrow invalid('A claim is an object');\n\t}\n\tcheckOwner(request.owner);\n\tcheckTime('now', request.now);\n\tif (!isTime(request.leaseMs) || request.leaseMs <= 0) {\n\t\tthrow invalid('leaseMs must be a positive number');\n\t}\n}\n\nexport function checkResult(result: AttemptResult): void {\n\tif (typeof result !== 'object' || result === null) {\n\t\tthrow invalid('An attempt result is an object');\n\t}\n\tcheckTime('now', result.now);\n\tcheckTime('nextAttemptAt', result.nextAttemptAt);\n\tif (!Number.isInteger(result.attempts) || result.attempts < 0) {\n\t\tthrow invalid('attempts must be an integer of at least 0');\n\t}\n\tif (typeof result.delayNotified !== 'boolean') {\n\t\tthrow invalid('delayNotified must be true or false');\n\t}\n\tconst statuses = ['delivered', 'deferred', 'failed'];\n\tif (\n\t\t!Array.isArray(result.recipients) ||\n\t\t!result.recipients.every(\n\t\t\t(u) => typeof u?.address === 'string' && statuses.includes(u.status),\n\t\t)\n\t) {\n\t\tthrow invalid(\n\t\t\t'recipients must be an array of { address, status: delivered, deferred or failed }',\n\t\t);\n\t}\n\tfor (const update of result.recipients) checkUpdate(update);\n}\n\n/** The offset and limit of a list: integers, the limit 1 to 1000. */\nexport function checkList(options: QueueListOptions = {}): {\n\toffset: number;\n\tlimit: number;\n} {\n\tconst offset = options.offset ?? 0;\n\tconst limit = options.limit ?? 100;\n\tif (!Number.isInteger(offset) || offset < 0) {\n\t\tthrow invalid(`offset must be an integer of at least 0, not ${offset}`);\n\t}\n\tif (!Number.isInteger(limit) || limit < 1 || limit > 1000) {\n\t\tthrow invalid(`limit must be an integer from 1 to 1000, not ${limit}`);\n\t}\n\treturn { offset, limit };\n}\n\n/** Every recipient is `delivered` or `failed`. */\nexport const isDone = (item: Pick<QueueItem, 'recipients'>): boolean =>\n\titem.recipients.every(\n\t\t(r) => r.status === 'delivered' || r.status === 'failed',\n\t);\n\n/**\n * The item once an attempt is recorded: its recipients' outcomes, a final\n * state never changed again, the schedule, and no lease.\n */\nexport function applyAttempt(\n\titem: QueueItem,\n\tresult: AttemptResult,\n): QueueItem {\n\tconst updates = new Map(result.recipients.map((u) => [u.address, u]));\n\tconst recipients = item.recipients.map((r): RecipientState => {\n\t\tconst update = updates.get(r.address);\n\t\tif (!update || r.status === 'delivered' || r.status === 'failed') return r;\n\t\treturn {\n\t\t\taddress: r.address,\n\t\t\tstatus: update.status,\n\t\t\t...(update.reply ? { reply: update.reply } : {}),\n\t\t\tupdatedAt: result.now,\n\t\t};\n\t});\n\tconst { lease: _, ...rest } = item;\n\treturn {\n\t\t...rest,\n\t\trecipients,\n\t\tnextAttemptAt: result.nextAttemptAt,\n\t\tattempts: result.attempts,\n\t\tdelayNotified: result.delayNotified,\n\t};\n}\n\n/** A new item as a store first keeps it. */\nexport function newItem(id: string, item: NewQueueItem): QueueItem {\n\treturn {\n\t\tid,\n\t\tfrom: item.from,\n\t\trecipients: item.to.map((address) => ({ address, status: 'pending' })),\n\t\tsize: item.message.length,\n\t\tcreatedAt: item.createdAt,\n\t\tnextAttemptAt: item.createdAt,\n\t\tattempts: 0,\n\t\tdelayNotified: false,\n\t};\n}\n\n/** Whether a lease, if any, leaves the item free to claim at `now`. */\nexport const claimable = (item: QueueItem, now: number): boolean =>\n\titem.nextAttemptAt <= now &&\n\t(item.lease === undefined || item.lease.expiresAt <= now);\n"
|
|
8
|
-
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "81614FFC0DB6330C64756E2164756E21",
|
|
11
|
-
"names": []
|
|
12
|
-
}
|