@bumail/queue 0.7.2 → 0.8.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-3pt7rc59.js → index-e5wa9f3j.js} +9 -6
- package/dist/chunks/index-e5wa9f3j.js.map +12 -0
- package/dist/contract/checks.d.ts.map +1 -1
- package/dist/contract/queue-store.d.ts +2 -1
- package/dist/contract/queue-store.d.ts.map +1 -1
- package/dist/contract/types.d.ts +10 -0
- package/dist/contract/types.d.ts.map +1 -1
- package/dist/index.js +92 -48
- package/dist/index.js.map +11 -9
- package/dist/memory/index.js +1 -1
- package/dist/memory/index.js.map +1 -1
- package/dist/postgres/index.js +1 -1
- package/dist/postgres/index.js.map +1 -1
- package/dist/queue/attempt.d.ts +7 -7
- 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-session.d.ts +22 -0
- package/dist/queue/fallback-session.d.ts.map +1 -0
- package/dist/queue/notify.d.ts.map +1 -1
- package/dist/queue/outcome.d.ts.map +1 -1
- package/dist/queue/session.d.ts +14 -0
- package/dist/queue/session.d.ts.map +1 -0
- package/dist/queue/settle.d.ts.map +1 -1
- package/dist/redis/index.js +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/sqlite/index.js +1 -1
- package/dist/sqlite/index.js.map +1 -1
- package/docs/guide.md +25 -4
- package/docs/roadmap.md +6 -4
- package/docs/troubleshooting.md +11 -1
- package/package.json +1 -1
- package/dist/chunks/index-3pt7rc59.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: every recipient the MX did not refuse at `RCPT` is marked `mayHaveReachedMx` and never falls back on its own; a refused one may); 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: every recipient the MX did not refuse at `RCPT` is marked `mayHaveReachedMx` and never falls back on its own; a refused one may). If the smarthost's own session ends after the final dot, the recipient is marked `mayHaveReachedFallback` and later attempts go to the smarthost again, not to the MX; 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`, `mayHaveReachedMx`), `DeferredEvent`, `DsnEvent`, `QueueErrorEvent` | the events |
|
|
300
|
+
| `QueueEvents`, `QueueListener`, `RecipientEvent` (`route`, `fallback`, `mxReply`, `mayHaveReachedMx`, `mayHaveReachedFallback`), `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,9 +58,11 @@ function checkOwner(owner) {
|
|
|
58
58
|
}
|
|
59
59
|
function checkUpdate(update) {
|
|
60
60
|
checkStorable("A recipient", update.address);
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
for (const key of ["mayHaveReachedMx", "mayHaveReachedFallback"]) {
|
|
62
|
+
const mark = update[key];
|
|
63
|
+
if (mark !== undefined && mark !== true) {
|
|
64
|
+
throw invalid(`${key} must be true or absent`);
|
|
65
|
+
}
|
|
64
66
|
}
|
|
65
67
|
const reply = update.reply;
|
|
66
68
|
if (reply === undefined)
|
|
@@ -156,7 +158,8 @@ function applyAttempt(item, result) {
|
|
|
156
158
|
status: update.status,
|
|
157
159
|
...update.reply ? { reply: update.reply } : {},
|
|
158
160
|
updatedAt: result.now,
|
|
159
|
-
...r.mayHaveReachedMx || update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {}
|
|
161
|
+
...r.mayHaveReachedMx || update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {},
|
|
162
|
+
...r.mayHaveReachedFallback || update.mayHaveReachedFallback ? { mayHaveReachedFallback: true } : {}
|
|
160
163
|
};
|
|
161
164
|
});
|
|
162
165
|
const { lease: _, ...rest } = item;
|
|
@@ -184,5 +187,5 @@ var claimable = (item, now) => item.nextAttemptAt <= now && (item.lease === unde
|
|
|
184
187
|
|
|
185
188
|
export { QueueError2, invalid, hasControl, replaceControls, cleanText, isStorable, asciiText, checkTime, checkOwner, checkNewItem, checkMaxItems, checkClaim, checkResult, checkList, isDone, applyAttempt, newItem, claimable };
|
|
186
189
|
|
|
187
|
-
//# debugId=
|
|
188
|
-
//# sourceMappingURL=index-
|
|
190
|
+
//# debugId=16AF1EB72729D01E64756E2164756E21
|
|
191
|
+
//# sourceMappingURL=index-e5wa9f3j.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\tfor (const key of ['mayHaveReachedMx', 'mayHaveReachedFallback'] as const) {\n\t\tconst mark = update[key] as unknown;\n\t\tif (mark !== undefined && mark !== true) {\n\t\t\tthrow invalid(`${key} must be true or absent`);\n\t\t}\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\t...(r.mayHaveReachedFallback || update.mayHaveReachedFallback\n\t\t\t\t? { mayHaveReachedFallback: 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": "16AF1EB72729D01E64756E2164756E21",
|
|
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;AA8BD,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,CA0BX;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,7 +51,8 @@ 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`
|
|
54
|
+
* A recipient's `mayHaveReachedMx` and `mayHaveReachedFallback` marks, once
|
|
55
|
+
* recorded, are kept.
|
|
55
56
|
*/
|
|
56
57
|
complete(id: string, owner: string, result: AttemptResult): Promise<QueueItem | undefined>;
|
|
57
58
|
/**
|
|
@@ -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;;;;;;;OAOG;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
|
@@ -36,6 +36,14 @@ export interface RecipientState {
|
|
|
36
36
|
* recipient on its own; once recorded, the mark is kept.
|
|
37
37
|
*/
|
|
38
38
|
readonly mayHaveReachedMx?: true;
|
|
39
|
+
/**
|
|
40
|
+
* `true` once the fallback smarthost's session ended after the final dot
|
|
41
|
+
* with no reply: it may hold a copy. Absent while nothing says so, never
|
|
42
|
+
* `false`. Later attempts then skip the MX for this recipient and go to
|
|
43
|
+
* the fallback again (while one is configured); once recorded, the mark
|
|
44
|
+
* is kept.
|
|
45
|
+
*/
|
|
46
|
+
readonly mayHaveReachedFallback?: true;
|
|
39
47
|
}
|
|
40
48
|
/** Who is delivering an item, until when. */
|
|
41
49
|
export interface Lease {
|
|
@@ -91,6 +99,8 @@ export interface RecipientUpdate {
|
|
|
91
99
|
readonly reply?: Diagnostic;
|
|
92
100
|
/** Marks the recipient `mayHaveReachedMx`; `true` or absent, any other value is `INVALID`. */
|
|
93
101
|
readonly mayHaveReachedMx?: true;
|
|
102
|
+
/** Marks the recipient `mayHaveReachedFallback`; `true` or absent, any other value is `INVALID`. */
|
|
103
|
+
readonly mayHaveReachedFallback?: true;
|
|
94
104
|
}
|
|
95
105
|
/** What `complete` records: the attempt's outcomes, and when to try again. */
|
|
96
106
|
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;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,IAAI,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-e5wa9f3j.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;
|
|
@@ -436,22 +436,14 @@ function sendOptionsOf(settings, domain, from, to, override) {
|
|
|
436
436
|
};
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
// src/queue/
|
|
440
|
-
var
|
|
441
|
-
|
|
442
|
-
status: "failed",
|
|
443
|
-
reply: {
|
|
444
|
-
status: "5.1.3",
|
|
445
|
-
text: "The address is not one SMTP can carry"
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
var marked = (u) => u.status === "delivered" ? u : { ...u, mayHaveReachedMx: true };
|
|
449
|
-
function doubtful(updates, error) {
|
|
439
|
+
// src/queue/session.ts
|
|
440
|
+
var marked = (u, key) => u.status === "delivered" ? u : { ...u, [key]: true };
|
|
441
|
+
function doubtful(updates, error, key) {
|
|
450
442
|
if (!error.accepted)
|
|
451
|
-
return updates.map(marked);
|
|
443
|
+
return updates.map((u) => marked(u, key));
|
|
452
444
|
const taken = new Set(error.accepted.map((r) => r.recipient));
|
|
453
445
|
const refused = new Set((error.rejected ?? []).map((r) => r.recipient).filter((a) => !taken.has(a)));
|
|
454
|
-
return updates.map((u) => refused.has(u.address) ? u : marked(u));
|
|
446
|
+
return updates.map((u) => refused.has(u.address) ? u : marked(u, key));
|
|
455
447
|
}
|
|
456
448
|
async function session(ctx, item, message, domain, group, route, override) {
|
|
457
449
|
const { settings } = ctx;
|
|
@@ -464,16 +456,66 @@ async function session(ctx, item, message, domain, group, route, override) {
|
|
|
464
456
|
if (isRouteError(error))
|
|
465
457
|
ctx.events.emit("error", { error, id: item.id });
|
|
466
458
|
const updates = outcomesOfError(error, group, max, hostOf(route));
|
|
467
|
-
const
|
|
468
|
-
|
|
459
|
+
const key = route === "mx" ? "mayHaveReachedMx" : "mayHaveReachedFallback";
|
|
460
|
+
const doubt = (route === "mx" || override !== undefined) && isSmtpError(error) && error.afterData;
|
|
461
|
+
return { updates: doubt ? doubtful(updates, error, key) : updates, error };
|
|
469
462
|
}
|
|
470
463
|
}
|
|
464
|
+
|
|
465
|
+
// src/queue/fallback-session.ts
|
|
471
466
|
function merged(mx, fb) {
|
|
472
467
|
if (mx.status === "deferred" && fb.status === "failed") {
|
|
473
468
|
return { ...fb, status: "deferred" };
|
|
474
469
|
}
|
|
475
470
|
return fb;
|
|
476
471
|
}
|
|
472
|
+
var stillHeld = (u) => u.status === "failed" ? { ...u, status: "deferred" } : u;
|
|
473
|
+
async function fallBackAtOnce(ctx, item, message, domain, first, fallback, used) {
|
|
474
|
+
const mxHeld = new Set(item.recipients.filter((r) => r.mayHaveReachedMx).map((r) => r.address));
|
|
475
|
+
const mx = new Map(first.updates.filter((u) => u.status !== "delivered" && !u.mayHaveReachedMx && !mxHeld.has(u.address) && fallsBack(u.reply, first.error)).map((u) => [u.address, u]));
|
|
476
|
+
if (mx.size === 0)
|
|
477
|
+
return first.updates;
|
|
478
|
+
const second = await session(ctx, item, message, domain, [...mx.keys()], fallback, fallback);
|
|
479
|
+
for (const [address, u] of mx) {
|
|
480
|
+
used.set(address, {
|
|
481
|
+
route: "smarthost",
|
|
482
|
+
fallback: true,
|
|
483
|
+
...u.reply ? { mxReply: u.reply } : {}
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
return [
|
|
487
|
+
...first.updates.filter((u) => !mx.has(u.address)),
|
|
488
|
+
...second.updates.map((u) => {
|
|
489
|
+
const was = mx.get(u.address);
|
|
490
|
+
return was ? merged(was, u) : u;
|
|
491
|
+
})
|
|
492
|
+
];
|
|
493
|
+
}
|
|
494
|
+
function heldAtFallback(item, group, byMx, fallback) {
|
|
495
|
+
if (!byMx || fallback === undefined)
|
|
496
|
+
return [];
|
|
497
|
+
const held = new Set(item.recipients.filter((r) => r.mayHaveReachedFallback && !r.mayHaveReachedMx).map((r) => r.address));
|
|
498
|
+
return group.filter((address) => held.has(address));
|
|
499
|
+
}
|
|
500
|
+
async function deliverHeld(ctx, item, message, domain, held, fallback, used) {
|
|
501
|
+
if (held.length === 0)
|
|
502
|
+
return [];
|
|
503
|
+
for (const address of held) {
|
|
504
|
+
used.set(address, { route: "smarthost", fallback: true });
|
|
505
|
+
}
|
|
506
|
+
const second = await session(ctx, item, message, domain, held, fallback, fallback);
|
|
507
|
+
return second.updates.map(stillHeld);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/queue/attempt.ts
|
|
511
|
+
var badAddress = (address) => ({
|
|
512
|
+
address,
|
|
513
|
+
status: "failed",
|
|
514
|
+
reply: {
|
|
515
|
+
status: "5.1.3",
|
|
516
|
+
text: "The address is not one SMTP can carry"
|
|
517
|
+
}
|
|
518
|
+
});
|
|
477
519
|
async function attemptGroup(ctx, item, message, domain, recipients, used) {
|
|
478
520
|
const { settings } = ctx;
|
|
479
521
|
const bad = recipients.filter((address) => !isMailbox2(address));
|
|
@@ -484,32 +526,16 @@ async function attemptGroup(ctx, item, message, domain, recipients, used) {
|
|
|
484
526
|
const label = route === "mx" ? "mx" : "smarthost";
|
|
485
527
|
for (const address of group)
|
|
486
528
|
used.set(address, { route: label });
|
|
487
|
-
const first = await session(ctx, item, message, domain, group, route);
|
|
488
|
-
let updates = first.updates;
|
|
489
529
|
const { fallback } = settings.options;
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
fallback: true,
|
|
500
|
-
...u.reply ? { mxReply: u.reply } : {}
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
updates = [
|
|
504
|
-
...updates.filter((u) => !mx.has(u.address)),
|
|
505
|
-
...second.updates.map((u) => {
|
|
506
|
-
const was = mx.get(u.address);
|
|
507
|
-
return was ? merged(was, u) : u;
|
|
508
|
-
})
|
|
509
|
-
];
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
return [...updates, ...bad.map(badAddress)];
|
|
530
|
+
const held = heldAtFallback(item, group, route === "mx", fallback);
|
|
531
|
+
const kept = fallback === undefined ? [] : await deliverHeld(ctx, item, message, domain, held, fallback, used);
|
|
532
|
+
const viaMx = group.filter((address) => !held.includes(address));
|
|
533
|
+
let updates = [];
|
|
534
|
+
if (viaMx.length > 0) {
|
|
535
|
+
const first = await session(ctx, item, message, domain, viaMx, route);
|
|
536
|
+
updates = fallback !== undefined && route === "mx" ? await fallBackAtOnce(ctx, item, message, domain, first, fallback, used) : first.updates;
|
|
537
|
+
}
|
|
538
|
+
return [...kept, ...updates, ...bad.map(badAddress)];
|
|
513
539
|
}
|
|
514
540
|
|
|
515
541
|
// src/dsn/build.ts
|
|
@@ -763,13 +789,18 @@ function nextAttemptAt(createdAt, now, attempts, retry, random) {
|
|
|
763
789
|
|
|
764
790
|
// src/queue/notify.ts
|
|
765
791
|
var MAY_HAVE_REACHED = "An earlier attempt may have reached the receiving server, so the message may have been delivered.";
|
|
792
|
+
var MAY_HAVE_REACHED_FALLBACK = "An earlier attempt may have reached the fallback smarthost, so the message may have been delivered.";
|
|
766
793
|
function reported(r, kind) {
|
|
767
|
-
|
|
794
|
+
const said = [
|
|
795
|
+
...r.mayHaveReachedMx ? [MAY_HAVE_REACHED] : [],
|
|
796
|
+
...r.mayHaveReachedFallback ? [MAY_HAVE_REACHED_FALLBACK] : []
|
|
797
|
+
];
|
|
798
|
+
if (kind !== "failed" || said.length === 0)
|
|
768
799
|
return r.reply;
|
|
769
800
|
const reply = r.reply ?? { text: "" };
|
|
770
801
|
return {
|
|
771
802
|
...reply,
|
|
772
|
-
text: reply.text
|
|
803
|
+
text: [reply.text, ...said].filter((t) => t !== "").join(" ")
|
|
773
804
|
};
|
|
774
805
|
}
|
|
775
806
|
async function notify(ctx, item, message, kind, recipients, now) {
|
|
@@ -818,14 +849,24 @@ function expired(update) {
|
|
|
818
849
|
address: update.address,
|
|
819
850
|
status: "failed",
|
|
820
851
|
reply: { text: "", ...update.reply, status: "4.4.7" },
|
|
821
|
-
...update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {}
|
|
852
|
+
...update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {},
|
|
853
|
+
...update.mayHaveReachedFallback ? { mayHaveReachedFallback: true } : {}
|
|
822
854
|
};
|
|
823
855
|
}
|
|
824
856
|
function settle(item, updates, skipped, now, settings) {
|
|
825
857
|
const attempts = item.attempts + (updates.length > 0 ? 1 : 0);
|
|
826
858
|
const next = nextAttemptAt(item.createdAt, now, attempts, settings.retry, settings.random);
|
|
827
|
-
const
|
|
828
|
-
const all = updates.map((u) =>
|
|
859
|
+
const was = new Map(item.recipients.map((r) => [r.address, r]));
|
|
860
|
+
const all = updates.map((u) => {
|
|
861
|
+
const r = was.get(u.address);
|
|
862
|
+
if (!r || u.status === "delivered")
|
|
863
|
+
return u;
|
|
864
|
+
return {
|
|
865
|
+
...u,
|
|
866
|
+
...r.mayHaveReachedMx ? { mayHaveReachedMx: true } : {},
|
|
867
|
+
...r.mayHaveReachedFallback ? { mayHaveReachedFallback: true } : {}
|
|
868
|
+
};
|
|
869
|
+
}).map((u) => u.status === "deferred" && next === undefined ? expired(u) : u);
|
|
829
870
|
const deferred = all.filter((u) => u.status === "deferred");
|
|
830
871
|
const { delayAfter } = settings.dsn;
|
|
831
872
|
const delayDsn = !item.delayNotified && item.from !== "" && delayAfter !== false && deferred.length > 0 && now - item.createdAt >= delayAfter;
|
|
@@ -887,7 +928,10 @@ function emitOutcomes(events, item, settled, used) {
|
|
|
887
928
|
attempts,
|
|
888
929
|
...used.get(u.address)
|
|
889
930
|
});
|
|
890
|
-
const marked = (u) =>
|
|
931
|
+
const marked = (u) => ({
|
|
932
|
+
...u.mayHaveReachedMx ? { mayHaveReachedMx: true } : {},
|
|
933
|
+
...u.mayHaveReachedFallback ? { mayHaveReachedFallback: true } : {}
|
|
934
|
+
});
|
|
891
935
|
for (const u of settled.delivered)
|
|
892
936
|
events.emit("delivered", base(u));
|
|
893
937
|
for (const u of settled.deferred) {
|
|
@@ -1245,5 +1289,5 @@ export {
|
|
|
1245
1289
|
createQueue
|
|
1246
1290
|
};
|
|
1247
1291
|
|
|
1248
|
-
//# debugId=
|
|
1292
|
+
//# debugId=3E9664C55274145964756E2164756E21
|
|
1249
1293
|
//# sourceMappingURL=index.js.map
|