@bumail/queue 0.7.2 → 0.9.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 +27 -3
- package/dist/chunks/{index-3pt7rc59.js → index-9yp15arf.js} +98 -25
- package/dist/chunks/index-9yp15arf.js.map +14 -0
- package/dist/chunks/index-r8wb840a.js +24 -0
- package/dist/chunks/index-r8wb840a.js.map +10 -0
- package/dist/contract/checks.d.ts +2 -6
- package/dist/contract/checks.d.ts.map +1 -1
- package/dist/contract/dsn-checks.d.ts +4 -0
- package/dist/contract/dsn-checks.d.ts.map +1 -0
- package/dist/contract/dsn-column.d.ts +12 -0
- package/dist/contract/dsn-column.d.ts.map +1 -0
- package/dist/contract/queue-store.d.ts +2 -1
- package/dist/contract/queue-store.d.ts.map +1 -1
- package/dist/contract/storable.d.ts +7 -0
- package/dist/contract/storable.d.ts.map +1 -0
- package/dist/contract/types.d.ts +52 -0
- package/dist/contract/types.d.ts.map +1 -1
- package/dist/dsn/build.d.ts +2 -0
- package/dist/dsn/build.d.ts.map +1 -1
- package/dist/dsn/delivered.d.ts +39 -0
- package/dist/dsn/delivered.d.ts.map +1 -0
- package/dist/dsn/fields.d.ts +11 -2
- package/dist/dsn/fields.d.ts.map +1 -1
- package/dist/dsn/human.d.ts +7 -0
- package/dist/dsn/human.d.ts.map +1 -0
- package/dist/dsn/policy.d.ts +17 -0
- package/dist/dsn/policy.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +474 -300
- package/dist/index.js.map +20 -15
- package/dist/memory/index.js +1 -1
- package/dist/memory/index.js.map +1 -1
- package/dist/postgres/index.js +17 -9
- package/dist/postgres/index.js.map +6 -6
- package/dist/postgres/rows.d.ts +6 -1
- package/dist/postgres/rows.d.ts.map +1 -1
- package/dist/postgres/schema.d.ts.map +1 -1
- package/dist/postgres/statements.d.ts +9 -8
- package/dist/postgres/statements.d.ts.map +1 -1
- package/dist/postgres/store.d.ts.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/envelope.d.ts +24 -4
- package/dist/queue/envelope.d.ts.map +1 -1
- package/dist/queue/events.d.ts +8 -1
- 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 +6 -3
- package/dist/queue/notify.d.ts.map +1 -1
- package/dist/queue/outcome.d.ts.map +1 -1
- package/dist/queue/queue.d.ts.map +1 -1
- package/dist/queue/route.d.ts +7 -0
- package/dist/queue/route.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 +26 -13
- package/dist/redis/index.js.map +5 -5
- package/dist/redis/items.d.ts +2 -0
- package/dist/redis/items.d.ts.map +1 -1
- package/dist/redis/scripts.d.ts +1 -1
- package/dist/redis/scripts.d.ts.map +1 -1
- package/dist/redis/store.d.ts.map +1 -1
- package/dist/sqlite/index.js +15 -8
- package/dist/sqlite/index.js.map +5 -5
- package/dist/sqlite/rows.d.ts +2 -1
- package/dist/sqlite/rows.d.ts.map +1 -1
- package/dist/sqlite/schema.d.ts.map +1 -1
- package/dist/sqlite/store.d.ts.map +1 -1
- package/docs/guide.md +97 -7
- package/docs/roadmap.md +14 -7
- package/docs/troubleshooting.md +52 -1
- package/package.json +3 -3
- package/dist/chunks/index-3pt7rc59.js.map +0 -12
package/README.md
CHANGED
|
@@ -92,6 +92,29 @@ with the original's header fields; a recipient still deferred after
|
|
|
92
92
|
`delayAfter` gets one "delayed" warning. A DSN is enqueued from the null
|
|
93
93
|
sender `<>`, and a message from `<>` never causes one.
|
|
94
94
|
|
|
95
|
+
The envelope can carry the sender's DSN parameters (RFC 3461), which the
|
|
96
|
+
SMTP server hands over as they are and the queue passes on to the next
|
|
97
|
+
hop:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
await queue.enqueue(message, {
|
|
101
|
+
from: 'mary@example.net',
|
|
102
|
+
to: ['joe@example.com'],
|
|
103
|
+
ret: 'HDRS', // what a DSN returns: the headers only (FULL: the whole message)
|
|
104
|
+
envid: 'QQ314159', // echoed as Original-Envelope-Id
|
|
105
|
+
recipients: [
|
|
106
|
+
{ address: 'joe@example.com', notify: ['SUCCESS', 'FAILURE'], orcpt: { type: 'rfc822', address: 'joe@old.example.org' } },
|
|
107
|
+
],
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`notify: 'NEVER'` sends no DSN; absent, failure and delay as always; a
|
|
112
|
+
list, only those events. Upgrading a shared store: stop every old worker
|
|
113
|
+
before starting a new one (an old worker that keeps running ignores the
|
|
114
|
+
DSN parameters and drops them from the items it completes). `SUCCESS` with a next hop that does not offer DSN
|
|
115
|
+
sends a `relayed` DSN. For a message the application delivered itself,
|
|
116
|
+
`deliveredDsn()` writes the `delivered` one.
|
|
117
|
+
|
|
95
118
|
## Routing
|
|
96
119
|
|
|
97
120
|
```ts
|
|
@@ -126,7 +149,7 @@ deferred recipient.
|
|
|
126
149
|
|
|
127
150
|
With `fallback` (a smarthost), a recipient whose session by MX failed by a
|
|
128
151
|
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).
|
|
152
|
+
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
153
|
|
|
131
154
|
## Several workers
|
|
132
155
|
|
|
@@ -296,8 +319,9 @@ control character in it.
|
|
|
296
319
|
| --- | --- |
|
|
297
320
|
| `createQueue(options)`, `Queue` | the queue: `enqueue`, `deliverDue`, `start`, `stop`, `on`, `list`, `get`, `retryNow`, `cancel`, `owner` |
|
|
298
321
|
| `QueueOptions` (`route`, `routes`, `fallback`), `Route`, `Smarthost`, `RetrySchedule`, `DsnOptions`, `QueueLimits`, `Clock`, `Sender` | what `createQueue` takes |
|
|
299
|
-
| `MessageSource`, `QueueEnvelope` | what `enqueue` takes |
|
|
300
|
-
| `
|
|
322
|
+
| `MessageSource`, `QueueEnvelope` (`ret`, `envid`, `recipients`), `RecipientDsn`, `RecipientNotify`, `NotifyEvent`, `OriginalRecipient`, `RetMode` | what `enqueue` takes, with the DSN parameters |
|
|
323
|
+
| `deliveredDsn(input)`, `DeliveredDsnInput`, `DeliveredRecipient` | the `delivered` DSN for a local delivery: the bytes to enqueue, or `undefined` when no recipient asked for `SUCCESS` |
|
|
324
|
+
| `QueueEvents`, `QueueListener`, `RecipientEvent` (`route`, `fallback`, `mxReply`, `mayHaveReachedMx`, `mayHaveReachedFallback`), `DeferredEvent`, `DsnEvent`, `QueueErrorEvent` | the events |
|
|
301
325
|
| `QueueStore` | the contract a store answers: `add`, `get`, `list`, `count`, `readMessage`, `claim`, `renew`, `complete`, `reschedule`, `cancel` |
|
|
302
326
|
| `QueueItem`, `RecipientState`, `RecipientStatus`, `FinalStatus`, `Diagnostic`, `Lease` | an item, and where each recipient stands |
|
|
303
327
|
| `NewQueueItem`, `AddOptions`, `ClaimRequest`, `AttemptResult`, `RecipientUpdate`, `QueueListOptions` | what a store takes |
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
// src/errors.ts
|
|
2
|
-
class QueueError2 extends Error {
|
|
3
|
-
name = "QueueError";
|
|
4
|
-
code;
|
|
5
|
-
constructor(code, message) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.code = code;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
var invalid = (message) => new QueueError2("INVALID", message);
|
|
11
|
-
|
|
12
1
|
// src/text.ts
|
|
13
2
|
var isControl = (code) => code < 32 || code >= 127 && code <= 159;
|
|
14
3
|
function hasControl(text) {
|
|
@@ -37,6 +26,78 @@ function cut(text, length) {
|
|
|
37
26
|
var isStorable = (text) => text.isWellFormed() && !text.includes("\x00");
|
|
38
27
|
var asciiText = (text, max) => cleanText(text, max).replace(/[^ -~]/g, "?");
|
|
39
28
|
|
|
29
|
+
// src/errors.ts
|
|
30
|
+
class QueueError2 extends Error {
|
|
31
|
+
name = "QueueError";
|
|
32
|
+
code;
|
|
33
|
+
constructor(code, message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.code = code;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
var invalid = (message) => new QueueError2("INVALID", message);
|
|
39
|
+
|
|
40
|
+
// src/contract/storable.ts
|
|
41
|
+
function checkStorable(name, text) {
|
|
42
|
+
if (!isStorable(text)) {
|
|
43
|
+
throw invalid(`${name} holds a NUL or a lone surrogate, which a store cannot keep`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/contract/dsn-checks.ts
|
|
48
|
+
var EVENTS = ["SUCCESS", "FAILURE", "DELAY"];
|
|
49
|
+
function xtextLength(text) {
|
|
50
|
+
let length = 0;
|
|
51
|
+
for (const byte of new TextEncoder().encode(text)) {
|
|
52
|
+
length += byte >= 33 && byte <= 126 && byte !== 43 && byte !== 61 ? 1 : 3;
|
|
53
|
+
}
|
|
54
|
+
return length;
|
|
55
|
+
}
|
|
56
|
+
function checkRecipientDsn(entry, to) {
|
|
57
|
+
const { address, notify, orcpt } = entry ?? {};
|
|
58
|
+
if (typeof address !== "string" || !to.includes(address)) {
|
|
59
|
+
throw invalid(`recipients names ${JSON.stringify(address)}, which is not in to`);
|
|
60
|
+
}
|
|
61
|
+
if (notify !== undefined && notify !== "NEVER") {
|
|
62
|
+
const events = Array.isArray(notify) ? notify : [];
|
|
63
|
+
if (events.length === 0 || events.some((e, i) => !EVENTS.includes(e) || events.indexOf(e) !== i)) {
|
|
64
|
+
throw invalid(`notify of ${address} must be 'NEVER' or a list of 'SUCCESS', 'FAILURE', 'DELAY', each once`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (orcpt === undefined)
|
|
68
|
+
return;
|
|
69
|
+
if (typeof orcpt !== "object" || orcpt === null || typeof orcpt.type !== "string" || !/^[A-Za-z0-9-]+$/.test(orcpt.type) || typeof orcpt.address !== "string" || orcpt.address === "") {
|
|
70
|
+
throw invalid(`orcpt of ${address} must be { type, address }`);
|
|
71
|
+
}
|
|
72
|
+
if (orcpt.type.length + 1 + xtextLength(orcpt.address) > 500) {
|
|
73
|
+
throw invalid(`orcpt of ${address} is over 500 characters once encoded`);
|
|
74
|
+
}
|
|
75
|
+
checkStorable("orcpt.type", orcpt.type);
|
|
76
|
+
checkStorable("orcpt.address", orcpt.address);
|
|
77
|
+
}
|
|
78
|
+
function checkDsnParams(item) {
|
|
79
|
+
const { ret, envid, recipients } = item;
|
|
80
|
+
if (ret !== undefined && ret !== "FULL" && ret !== "HDRS") {
|
|
81
|
+
throw invalid(`ret must be 'FULL' or 'HDRS', not ${String(ret)}`);
|
|
82
|
+
}
|
|
83
|
+
if (envid !== undefined && (typeof envid !== "string" || !/^[ -~]{1,100}$/.test(envid) || xtextLength(envid) > 100)) {
|
|
84
|
+
throw invalid("envid must be 1 to 100 printable ASCII characters, at most 100 once encoded as xtext");
|
|
85
|
+
}
|
|
86
|
+
if (recipients === undefined)
|
|
87
|
+
return;
|
|
88
|
+
if (!Array.isArray(recipients)) {
|
|
89
|
+
throw invalid("recipients must be an array of { address, notify, orcpt }");
|
|
90
|
+
}
|
|
91
|
+
const seen = new Set;
|
|
92
|
+
for (const entry of recipients) {
|
|
93
|
+
checkRecipientDsn(entry, item.to);
|
|
94
|
+
if (seen.has(entry.address)) {
|
|
95
|
+
throw invalid(`recipients names ${entry.address} twice`);
|
|
96
|
+
}
|
|
97
|
+
seen.add(entry.address);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
40
101
|
// src/contract/checks.ts
|
|
41
102
|
var isTime = (value) => typeof value === "number" && Number.isFinite(value);
|
|
42
103
|
function checkTime(name, value) {
|
|
@@ -44,11 +105,6 @@ function checkTime(name, value) {
|
|
|
44
105
|
throw invalid(`${name} must be a finite number`);
|
|
45
106
|
return value;
|
|
46
107
|
}
|
|
47
|
-
function checkStorable(name, text) {
|
|
48
|
-
if (!isStorable(text)) {
|
|
49
|
-
throw invalid(`${name} holds a NUL or a lone surrogate, which a store cannot keep`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
108
|
function checkOwner(owner) {
|
|
53
109
|
if (typeof owner !== "string" || owner === "") {
|
|
54
110
|
throw invalid("owner must be a non-empty string");
|
|
@@ -58,9 +114,11 @@ function checkOwner(owner) {
|
|
|
58
114
|
}
|
|
59
115
|
function checkUpdate(update) {
|
|
60
116
|
checkStorable("A recipient", update.address);
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
117
|
+
for (const key of ["mayHaveReachedMx", "mayHaveReachedFallback"]) {
|
|
118
|
+
const mark = update[key];
|
|
119
|
+
if (mark !== undefined && mark !== true) {
|
|
120
|
+
throw invalid(`${key} must be true or absent`);
|
|
121
|
+
}
|
|
64
122
|
}
|
|
65
123
|
const reply = update.reply;
|
|
66
124
|
if (reply === undefined)
|
|
@@ -95,6 +153,7 @@ function checkNewItem(item) {
|
|
|
95
153
|
throw invalid("message must be a Uint8Array");
|
|
96
154
|
}
|
|
97
155
|
checkTime("createdAt", item.createdAt);
|
|
156
|
+
checkDsnParams(item);
|
|
98
157
|
}
|
|
99
158
|
function checkMaxItems(max) {
|
|
100
159
|
if (max === undefined)
|
|
@@ -154,9 +213,12 @@ function applyAttempt(item, result) {
|
|
|
154
213
|
return {
|
|
155
214
|
address: r.address,
|
|
156
215
|
status: update.status,
|
|
216
|
+
...r.notify === undefined ? {} : { notify: r.notify },
|
|
217
|
+
...r.orcpt === undefined ? {} : { orcpt: r.orcpt },
|
|
157
218
|
...update.reply ? { reply: update.reply } : {},
|
|
158
219
|
updatedAt: result.now,
|
|
159
|
-
...r.mayHaveReachedMx || update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {}
|
|
220
|
+
...r.mayHaveReachedMx || update.mayHaveReachedMx ? { mayHaveReachedMx: true } : {},
|
|
221
|
+
...r.mayHaveReachedFallback || update.mayHaveReachedFallback ? { mayHaveReachedFallback: true } : {}
|
|
160
222
|
};
|
|
161
223
|
});
|
|
162
224
|
const { lease: _, ...rest } = item;
|
|
@@ -169,20 +231,31 @@ function applyAttempt(item, result) {
|
|
|
169
231
|
};
|
|
170
232
|
}
|
|
171
233
|
function newItem(id, item) {
|
|
234
|
+
const dsn = new Map(item.recipients?.map((r) => [r.address, r]));
|
|
172
235
|
return {
|
|
173
236
|
id,
|
|
174
237
|
from: item.from,
|
|
175
|
-
recipients: item.to.map((address) =>
|
|
238
|
+
recipients: item.to.map((address) => {
|
|
239
|
+
const { notify, orcpt } = dsn.get(address) ?? {};
|
|
240
|
+
return {
|
|
241
|
+
address,
|
|
242
|
+
status: "pending",
|
|
243
|
+
...notify === undefined ? {} : { notify: notify === "NEVER" ? notify : [...notify] },
|
|
244
|
+
...orcpt === undefined ? {} : { orcpt: { type: orcpt.type, address: orcpt.address } }
|
|
245
|
+
};
|
|
246
|
+
}),
|
|
176
247
|
size: item.message.length,
|
|
177
248
|
createdAt: item.createdAt,
|
|
178
249
|
nextAttemptAt: item.createdAt,
|
|
179
250
|
attempts: 0,
|
|
180
|
-
delayNotified: false
|
|
251
|
+
delayNotified: false,
|
|
252
|
+
...item.ret === undefined ? {} : { ret: item.ret },
|
|
253
|
+
...item.envid === undefined ? {} : { envid: item.envid }
|
|
181
254
|
};
|
|
182
255
|
}
|
|
183
256
|
var claimable = (item, now) => item.nextAttemptAt <= now && (item.lease === undefined || item.lease.expiresAt <= now);
|
|
184
257
|
|
|
185
|
-
export {
|
|
258
|
+
export { hasControl, replaceControls, cleanText, isStorable, asciiText, QueueError2, invalid, checkTime, checkOwner, checkNewItem, checkMaxItems, checkClaim, checkResult, checkList, isDone, applyAttempt, newItem, claimable };
|
|
186
259
|
|
|
187
|
-
//# debugId=
|
|
188
|
-
//# sourceMappingURL=index-
|
|
260
|
+
//# debugId=C41FD2A676DEB7AF64756E2164756E21
|
|
261
|
+
//# sourceMappingURL=index-9yp15arf.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/text.ts", "../src/errors.ts", "../src/contract/storable.ts", "../src/contract/dsn-checks.ts", "../src/contract/checks.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/** 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",
|
|
6
|
+
"/**\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",
|
|
7
|
+
"import { invalid } from '../errors';\nimport { isStorable } from '../text';\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",
|
|
8
|
+
"// The value rules repeat packages/smtp/src/server/dsn-params.ts, packages/smtp/src/client/dsn.ts and\n// packages/jmap/src/submission/dsn.ts (AGENTS.md, Deliberate duplications); this copy guards the contract.\nimport { invalid } from '../errors';\nimport { checkStorable } from './storable';\nimport type { NewQueueItem, RecipientDsn } from './types';\n\nconst EVENTS: readonly unknown[] = ['SUCCESS', 'FAILURE', 'DELAY'];\n\n/**\n * The length the xtext of `text` takes on the wire (RFC 3461 §4): one\n * character for each byte of its UTF-8 form in `!` to `~` but `+` and `=`,\n * three for any other.\n */\nfunction xtextLength(text: string): number {\n\tlet length = 0;\n\tfor (const byte of new TextEncoder().encode(text)) {\n\t\tlength +=\n\t\t\tbyte >= 33 && byte <= 126 && byte !== 0x2b && byte !== 0x3d ? 1 : 3;\n\t}\n\treturn length;\n}\n\n/** One recipient's `NOTIFY` (RFC 3461 §4.1) and `ORCPT` (§4.2). */\nfunction checkRecipientDsn(entry: RecipientDsn, to: readonly string[]): void {\n\tconst { address, notify, orcpt } = entry ?? {};\n\tif (typeof address !== 'string' || !to.includes(address)) {\n\t\tthrow invalid(\n\t\t\t`recipients names ${JSON.stringify(address)}, which is not in to`,\n\t\t);\n\t}\n\tif (notify !== undefined && notify !== 'NEVER') {\n\t\tconst events: readonly unknown[] = Array.isArray(notify) ? notify : [];\n\t\tif (\n\t\t\tevents.length === 0 ||\n\t\t\tevents.some((e, i) => !EVENTS.includes(e) || events.indexOf(e) !== i)\n\t\t) {\n\t\t\tthrow invalid(\n\t\t\t\t`notify of ${address} must be 'NEVER' or a list of 'SUCCESS', 'FAILURE', 'DELAY', each once`,\n\t\t\t);\n\t\t}\n\t}\n\tif (orcpt === undefined) return;\n\tif (\n\t\ttypeof orcpt !== 'object' ||\n\t\torcpt === null ||\n\t\ttypeof orcpt.type !== 'string' ||\n\t\t!/^[A-Za-z0-9-]+$/.test(orcpt.type) ||\n\t\ttypeof orcpt.address !== 'string' ||\n\t\torcpt.address === ''\n\t) {\n\t\tthrow invalid(`orcpt of ${address} must be { type, address }`);\n\t}\n\t// RFC 3461 §4.2: \"The entire ORCPT parameter MAY be up to 500 characters in length\", as sent.\n\tif (orcpt.type.length + 1 + xtextLength(orcpt.address) > 500) {\n\t\tthrow invalid(`orcpt of ${address} is over 500 characters once encoded`);\n\t}\n\tcheckStorable('orcpt.type', orcpt.type);\n\tcheckStorable('orcpt.address', orcpt.address);\n}\n\n/** `ret`, `envid` and `recipients` of a new item. */\nexport function checkDsnParams(item: NewQueueItem): void {\n\tconst { ret, envid, recipients } = item;\n\tif (ret !== undefined && ret !== 'FULL' && ret !== 'HDRS') {\n\t\tthrow invalid(`ret must be 'FULL' or 'HDRS', not ${String(ret)}`);\n\t}\n\tif (\n\t\tenvid !== undefined &&\n\t\t(typeof envid !== 'string' ||\n\t\t\t!/^[ -~]{1,100}$/.test(envid) ||\n\t\t\t// RFC 3461 §4.4: \"The ENVID parameter MAY be up to 100 characters in length\", as sent.\n\t\t\txtextLength(envid) > 100)\n\t) {\n\t\tthrow invalid(\n\t\t\t'envid must be 1 to 100 printable ASCII characters, at most 100 once encoded as xtext',\n\t\t);\n\t}\n\tif (recipients === undefined) return;\n\tif (!Array.isArray(recipients)) {\n\t\tthrow invalid('recipients must be an array of { address, notify, orcpt }');\n\t}\n\tconst seen = new Set<string>();\n\tfor (const entry of recipients) {\n\t\tcheckRecipientDsn(entry, item.to);\n\t\tif (seen.has(entry.address)) {\n\t\t\tthrow invalid(`recipients names ${entry.address} twice`);\n\t\t}\n\t\tseen.add(entry.address);\n\t}\n}\n",
|
|
9
|
+
"import { invalid } from '../errors';\nimport { checkDsnParams } from './dsn-checks';\nimport { checkStorable } from './storable';\n\nexport { checkStorable };\n\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/** 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\tcheckDsnParams(item);\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...(r.notify === undefined ? {} : { notify: r.notify }),\n\t\t\t...(r.orcpt === undefined ? {} : { orcpt: r.orcpt }),\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\tconst dsn = new Map(item.recipients?.map((r) => [r.address, r]));\n\treturn {\n\t\tid,\n\t\tfrom: item.from,\n\t\trecipients: item.to.map((address): RecipientState => {\n\t\t\tconst { notify, orcpt } = dsn.get(address) ?? {};\n\t\t\treturn {\n\t\t\t\taddress,\n\t\t\t\tstatus: 'pending',\n\t\t\t\t...(notify === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { notify: notify === 'NEVER' ? notify : [...notify] }),\n\t\t\t\t...(orcpt === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { orcpt: { type: orcpt.type, address: orcpt.address } }),\n\t\t\t};\n\t\t}),\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\t...(item.ret === undefined ? {} : { ret: item.ret }),\n\t\t...(item.envid === undefined ? {} : { envid: item.envid }),\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"
|
|
10
|
+
],
|
|
11
|
+
"mappings": "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",
|
|
12
|
+
"debugId": "C41FD2A676DEB7AF64756E2164756E21",
|
|
13
|
+
"names": []
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/contract/dsn-column.ts
|
|
2
|
+
function dsnColumn(item) {
|
|
3
|
+
if (item.ret === undefined && item.envid === undefined)
|
|
4
|
+
return null;
|
|
5
|
+
const params = {
|
|
6
|
+
...item.ret === undefined ? {} : { ret: item.ret },
|
|
7
|
+
...item.envid === undefined ? {} : { envid: item.envid }
|
|
8
|
+
};
|
|
9
|
+
return JSON.stringify(params);
|
|
10
|
+
}
|
|
11
|
+
function dsnParams(column) {
|
|
12
|
+
if (column === null || column === undefined)
|
|
13
|
+
return {};
|
|
14
|
+
const params = typeof column === "string" ? JSON.parse(column) : column;
|
|
15
|
+
return {
|
|
16
|
+
...params.ret === undefined ? {} : { ret: params.ret },
|
|
17
|
+
...params.envid === undefined ? {} : { envid: params.envid }
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { dsnColumn, dsnParams };
|
|
22
|
+
|
|
23
|
+
//# debugId=4C4AEC4A6A58C66564756E2164756E21
|
|
24
|
+
//# sourceMappingURL=index-r8wb840a.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/contract/dsn-column.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { QueueItem, RetMode } from './types';\n\n/** The item-level DSN parameters, as the SQL stores keep them in one JSON column. */\ninterface Params {\n\tret?: RetMode;\n\tenvid?: string;\n}\n\n/** The column's JSON text, or `null` when the item has no `RET` and no `ENVID`. */\nexport function dsnColumn(\n\titem: Pick<QueueItem, 'ret' | 'envid'>,\n): string | null {\n\tif (item.ret === undefined && item.envid === undefined) return null;\n\tconst params: Params = {\n\t\t...(item.ret === undefined ? {} : { ret: item.ret }),\n\t\t...(item.envid === undefined ? {} : { envid: item.envid }),\n\t};\n\treturn JSON.stringify(params);\n}\n\n/** `ret` and `envid` from the column: nothing for a row written before the column existed (`null`). */\nexport function dsnParams(\n\tcolumn: string | Params | null | undefined,\n): Pick<QueueItem, 'ret' | 'envid'> {\n\tif (column === null || column === undefined) return {};\n\tconst params: Params =\n\t\ttypeof column === 'string' ? (JSON.parse(column) as Params) : column;\n\treturn {\n\t\t...(params.ret === undefined ? {} : { ret: params.ret }),\n\t\t...(params.envid === undefined ? {} : { envid: params.envid }),\n\t};\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AASO,SAAS,SAAS,CACxB,MACgB;AAAA,EAChB,IAAI,KAAK,QAAQ,aAAa,KAAK,UAAU;AAAA,IAAW,OAAO;AAAA,EAC/D,MAAM,SAAiB;AAAA,OAClB,KAAK,QAAQ,YAAY,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI;AAAA,OAC9C,KAAK,UAAU,YAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,EACzD;AAAA,EACA,OAAO,KAAK,UAAU,MAAM;AAAA;AAItB,SAAS,SAAS,CACxB,QACmC;AAAA,EACnC,IAAI,WAAW,QAAQ,WAAW;AAAA,IAAW,OAAO,CAAC;AAAA,EACrD,MAAM,SACL,OAAO,WAAW,WAAY,KAAK,MAAM,MAAM,IAAe;AAAA,EAC/D,OAAO;AAAA,OACF,OAAO,QAAQ,YAAY,CAAC,IAAI,EAAE,KAAK,OAAO,IAAI;AAAA,OAClD,OAAO,UAAU,YAAY,CAAC,IAAI,EAAE,OAAO,OAAO,MAAM;AAAA,EAC7D;AAAA;",
|
|
8
|
+
"debugId": "4C4AEC4A6A58C66564756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
+
import { checkStorable } from './storable';
|
|
2
|
+
export { checkStorable };
|
|
1
3
|
import type { AttemptResult, ClaimRequest, NewQueueItem, QueueItem, QueueListOptions } from './types';
|
|
2
4
|
/** A time in milliseconds since the epoch, or `INVALID` naming it. */
|
|
3
5
|
export declare function checkTime(name: string, value: unknown): number;
|
|
4
|
-
/**
|
|
5
|
-
* Text a store keeps: refused, the same way by every store, when it holds
|
|
6
|
-
* a NUL or a lone surrogate, which PostgreSQL cannot keep and no UTF-8
|
|
7
|
-
* encode can carry.
|
|
8
|
-
*/
|
|
9
|
-
export declare function checkStorable(name: string, text: string): void;
|
|
10
6
|
/** A lease owner: a non-empty string. */
|
|
11
7
|
export declare function checkOwner(owner: unknown): string;
|
|
12
8
|
export declare function checkNewItem(item: NewQueueItem): void;
|
|
@@ -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
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/contract/checks.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,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,yCAAyC;AACzC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMjD;AA8BD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAoBrD;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,CA4BX;AAED,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,CA0BjE;AAED,uEAAuE;AACvE,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,EAAE,KAAK,MAAM,KAAG,OAEC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dsn-checks.d.ts","sourceRoot":"","sources":["../../src/contract/dsn-checks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,SAAS,CAAC;AAwD1D,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CA4BvD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { QueueItem, RetMode } from './types';
|
|
2
|
+
/** The item-level DSN parameters, as the SQL stores keep them in one JSON column. */
|
|
3
|
+
interface Params {
|
|
4
|
+
ret?: RetMode;
|
|
5
|
+
envid?: string;
|
|
6
|
+
}
|
|
7
|
+
/** The column's JSON text, or `null` when the item has no `RET` and no `ENVID`. */
|
|
8
|
+
export declare function dsnColumn(item: Pick<QueueItem, 'ret' | 'envid'>): string | null;
|
|
9
|
+
/** `ret` and `envid` from the column: nothing for a row written before the column existed (`null`). */
|
|
10
|
+
export declare function dsnParams(column: string | Params | null | undefined): Pick<QueueItem, 'ret' | 'envid'>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=dsn-column.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dsn-column.d.ts","sourceRoot":"","sources":["../../src/contract/dsn-column.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElD,qFAAqF;AACrF,UAAU,MAAM;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CACxB,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,OAAO,CAAC,GACpC,MAAM,GAAG,IAAI,CAOf;AAED,uGAAuG;AACvG,wBAAgB,SAAS,CACxB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACxC,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,OAAO,CAAC,CAQlC"}
|
|
@@ -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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text a store keeps: refused, the same way by every store, when it holds
|
|
3
|
+
* a NUL or a lone surrogate, which PostgreSQL cannot keep and no UTF-8
|
|
4
|
+
* encode can carry.
|
|
5
|
+
*/
|
|
6
|
+
export declare function checkStorable(name: string, text: string): void;
|
|
7
|
+
//# sourceMappingURL=storable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storable.d.ts","sourceRoot":"","sources":["../../src/contract/storable.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM9D"}
|
package/dist/contract/types.d.ts
CHANGED
|
@@ -21,10 +21,37 @@ export interface Diagnostic {
|
|
|
21
21
|
/** The host that answered, or that the attempt was for. */
|
|
22
22
|
readonly host?: string;
|
|
23
23
|
}
|
|
24
|
+
/** An event a sender may ask to be told of (RFC 3461 §4.1). */
|
|
25
|
+
export type NotifyEvent = 'SUCCESS' | 'FAILURE' | 'DELAY';
|
|
26
|
+
/**
|
|
27
|
+
* What a recipient's `NOTIFY` asked for (RFC 3461 §4.1): `'NEVER'`, or the
|
|
28
|
+
* events to be told of. Absent: failure and delay, the default.
|
|
29
|
+
*/
|
|
30
|
+
export type RecipientNotify = 'NEVER' | readonly NotifyEvent[];
|
|
31
|
+
/** The recipient as the sender first named it (`ORCPT`, RFC 3461 §4.2). */
|
|
32
|
+
export interface OriginalRecipient {
|
|
33
|
+
/** The address type, `rfc822` for an ordinary mailbox. */
|
|
34
|
+
readonly type: string;
|
|
35
|
+
/** The address, decoded. */
|
|
36
|
+
readonly address: string;
|
|
37
|
+
}
|
|
38
|
+
/** What `RET` asked an original message be returned as (RFC 3461 §4.3). */
|
|
39
|
+
export type RetMode = 'FULL' | 'HDRS';
|
|
40
|
+
/** The DSN parameters of one recipient, as `enqueue` takes them. */
|
|
41
|
+
export interface RecipientDsn {
|
|
42
|
+
/** `local@domain`, one of the envelope's `to`. */
|
|
43
|
+
readonly address: string;
|
|
44
|
+
readonly notify?: RecipientNotify;
|
|
45
|
+
readonly orcpt?: OriginalRecipient;
|
|
46
|
+
}
|
|
24
47
|
export interface RecipientState {
|
|
25
48
|
/** `local@domain`, as enqueued. */
|
|
26
49
|
readonly address: string;
|
|
27
50
|
readonly status: RecipientStatus;
|
|
51
|
+
/** `NOTIFY` as the sender asked; absent when it did not. Kept for the item's life. */
|
|
52
|
+
readonly notify?: RecipientNotify;
|
|
53
|
+
/** `ORCPT` as the sender gave it; absent when it did not. Kept for the item's life. */
|
|
54
|
+
readonly orcpt?: OriginalRecipient;
|
|
28
55
|
/** The last answer for this recipient. */
|
|
29
56
|
readonly reply?: Diagnostic;
|
|
30
57
|
/** When the status last changed, in milliseconds since the epoch. */
|
|
@@ -36,6 +63,14 @@ export interface RecipientState {
|
|
|
36
63
|
* recipient on its own; once recorded, the mark is kept.
|
|
37
64
|
*/
|
|
38
65
|
readonly mayHaveReachedMx?: true;
|
|
66
|
+
/**
|
|
67
|
+
* `true` once the fallback smarthost's session ended after the final dot
|
|
68
|
+
* with no reply: it may hold a copy. Absent while nothing says so, never
|
|
69
|
+
* `false`. Later attempts then skip the MX for this recipient and go to
|
|
70
|
+
* the fallback again (while one is configured); once recorded, the mark
|
|
71
|
+
* is kept.
|
|
72
|
+
*/
|
|
73
|
+
readonly mayHaveReachedFallback?: true;
|
|
39
74
|
}
|
|
40
75
|
/** Who is delivering an item, until when. */
|
|
41
76
|
export interface Lease {
|
|
@@ -59,6 +94,10 @@ export interface QueueItem {
|
|
|
59
94
|
readonly attempts: number;
|
|
60
95
|
/** The "delayed" DSN was sent for it. */
|
|
61
96
|
readonly delayNotified: boolean;
|
|
97
|
+
/** `RET` as the sender asked; absent when it did not. */
|
|
98
|
+
readonly ret?: RetMode;
|
|
99
|
+
/** `ENVID` as the sender gave it, decoded; absent when it did not. */
|
|
100
|
+
readonly envid?: string;
|
|
62
101
|
/** Present while a worker holds the item. */
|
|
63
102
|
readonly lease?: Lease;
|
|
64
103
|
}
|
|
@@ -71,6 +110,12 @@ export interface NewQueueItem {
|
|
|
71
110
|
readonly message: Uint8Array;
|
|
72
111
|
/** Milliseconds since the epoch; due at once. */
|
|
73
112
|
readonly createdAt: number;
|
|
113
|
+
/** `RET` (RFC 3461 §4.3). */
|
|
114
|
+
readonly ret?: RetMode;
|
|
115
|
+
/** `ENVID` (RFC 3461 §4.4): 1 to 100 printable ASCII characters. */
|
|
116
|
+
readonly envid?: string;
|
|
117
|
+
/** `NOTIFY` and `ORCPT` of the recipients that carry some, matched to `to` by address. */
|
|
118
|
+
readonly recipients?: readonly RecipientDsn[];
|
|
74
119
|
}
|
|
75
120
|
export interface AddOptions {
|
|
76
121
|
/** Refuse with `QUEUE_FULL` when the store already holds this many items. */
|
|
@@ -91,6 +136,13 @@ export interface RecipientUpdate {
|
|
|
91
136
|
readonly reply?: Diagnostic;
|
|
92
137
|
/** Marks the recipient `mayHaveReachedMx`; `true` or absent, any other value is `INVALID`. */
|
|
93
138
|
readonly mayHaveReachedMx?: true;
|
|
139
|
+
/** Marks the recipient `mayHaveReachedFallback`; `true` or absent, any other value is `INVALID`. */
|
|
140
|
+
readonly mayHaveReachedFallback?: true;
|
|
141
|
+
/**
|
|
142
|
+
* With `delivered`: whether the next hop listed DSN (`SendMailResult.dsnOffered`).
|
|
143
|
+
* Read by the queue to issue a `relayed` DSN; never stored.
|
|
144
|
+
*/
|
|
145
|
+
readonly dsnOffered?: boolean;
|
|
94
146
|
}
|
|
95
147
|
/** What `complete` records: the attempt's outcomes, and when to try again. */
|
|
96
148
|
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/dsn/build.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface DsnInput {
|
|
|
13
13
|
readonly arrival: Date;
|
|
14
14
|
/** When the DSN is written. */
|
|
15
15
|
readonly date: Date;
|
|
16
|
+
/** `ENVID` of the original, decoded: echoed as `Original-Envelope-Id`. */
|
|
17
|
+
readonly envid?: string;
|
|
16
18
|
readonly recipients: readonly DsnRecipient[];
|
|
17
19
|
/** With `delayed`: when the queue gives up. */
|
|
18
20
|
readonly willRetryUntil?: Date;
|
package/dist/dsn/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/dsn/build.ts"],"names":[],"mappings":"AAQA,OAAO,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/dsn/build.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,UAAU,CAAC;AAG3E,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEtD,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3C,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AA6CD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,CA4CpD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OriginalRecipient, RecipientNotify } from '../contract/types';
|
|
2
|
+
/** One recipient the application put in a local mailbox. */
|
|
3
|
+
export interface DeliveredRecipient {
|
|
4
|
+
/** `local@domain`, the mailbox it was delivered to. */
|
|
5
|
+
readonly address: string;
|
|
6
|
+
/** Its `NOTIFY`; a `delivered` DSN goes only when `SUCCESS` was asked (RFC 3461 §5.2.3). */
|
|
7
|
+
readonly notify?: RecipientNotify;
|
|
8
|
+
/** Its `ORCPT`, echoed as `Original-Recipient`. */
|
|
9
|
+
readonly orcpt?: OriginalRecipient;
|
|
10
|
+
}
|
|
11
|
+
/** What `deliveredDsn` takes. */
|
|
12
|
+
export interface DeliveredDsnInput {
|
|
13
|
+
/** This server's public name: the Reporting-MTA. */
|
|
14
|
+
readonly reportingMta: string;
|
|
15
|
+
/** The DSN's From: the postmaster's address. */
|
|
16
|
+
readonly from: string;
|
|
17
|
+
/** The original's reverse-path; `''` (the null sender) gets no DSN. */
|
|
18
|
+
readonly to: string;
|
|
19
|
+
/** When the original was received. */
|
|
20
|
+
readonly arrival: Date;
|
|
21
|
+
/** When it was delivered. Default: now. */
|
|
22
|
+
readonly date?: Date;
|
|
23
|
+
readonly recipients: readonly DeliveredRecipient[];
|
|
24
|
+
readonly envid?: string;
|
|
25
|
+
/** The original as received; without it the DSN returns nothing of it. */
|
|
26
|
+
readonly original?: Uint8Array;
|
|
27
|
+
/** The most bytes of the original returned. Default 64 KiB. */
|
|
28
|
+
readonly maxReturn?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The `delivered` DSN (RFC 3464 `Action: delivered`, RFC 3461 §5.2.3) for a
|
|
32
|
+
* message the application put in local mailboxes: the bytes to
|
|
33
|
+
* `enqueue` from the null sender to `to`, or `undefined` when there is
|
|
34
|
+
* nothing to send — the original came from the null sender, or no
|
|
35
|
+
* recipient asked for `SUCCESS`. Only the recipients that asked are
|
|
36
|
+
* listed.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deliveredDsn(input: DeliveredDsnInput): Uint8Array | undefined;
|
|
39
|
+
//# sourceMappingURL=delivered.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivered.d.ts","sourceRoot":"","sources":["../../src/dsn/delivered.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAI5E,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IAClC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4FAA4F;IAC5F,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;CACnC;AAED,iCAAiC;AACjC,MAAM,WAAW,iBAAiB;IACjC,oDAAoD;IACpD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,UAAU,GAAG,SAAS,CAsB7E"}
|
package/dist/dsn/fields.d.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import type { Diagnostic } from '../contract/types';
|
|
1
|
+
import type { Diagnostic, OriginalRecipient } from '../contract/types';
|
|
2
2
|
/** One recipient a DSN reports on. */
|
|
3
3
|
export interface DsnRecipient {
|
|
4
4
|
readonly address: string;
|
|
5
5
|
readonly reply?: Diagnostic;
|
|
6
6
|
/** When it was last tried. */
|
|
7
7
|
readonly lastAttempt: Date;
|
|
8
|
+
/** `ORCPT`: the recipient as the sender named it (RFC 3464 §2.3.1). */
|
|
9
|
+
readonly orcpt?: OriginalRecipient;
|
|
8
10
|
}
|
|
9
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The `Action` of the report (RFC 3464 §2.3.3): `failed` and `delayed` for
|
|
13
|
+
* what went wrong, `relayed` for a message handed to a next hop that sends
|
|
14
|
+
* no DSN (RFC 3461 §5.2.2), `delivered` for one put in a local mailbox.
|
|
15
|
+
*/
|
|
16
|
+
export type DsnKind = 'delayed' | 'failed' | 'relayed' | 'delivered';
|
|
10
17
|
/** What a delivery-status part reports: who reports, on what, and each recipient. */
|
|
11
18
|
export interface StatusReport {
|
|
12
19
|
readonly kind: DsnKind;
|
|
@@ -14,6 +21,8 @@ export interface StatusReport {
|
|
|
14
21
|
readonly reportingMta: string;
|
|
15
22
|
/** When the message was enqueued. */
|
|
16
23
|
readonly arrival: Date;
|
|
24
|
+
/** `ENVID` of the original, decoded (RFC 3464 §2.2.1). */
|
|
25
|
+
readonly envid?: string;
|
|
17
26
|
readonly recipients: readonly DsnRecipient[];
|
|
18
27
|
/** With `delayed`: when the queue gives up. */
|
|
19
28
|
readonly willRetryUntil?: Date;
|
package/dist/dsn/fields.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/dsn/fields.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/dsn/fields.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGvE,sCAAsC;AACtC,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,8BAA8B;IAC9B,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AAErE,qFAAqF;AACrF,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,0BAA0B;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC;CAC/B;AAQD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKpD;AAoBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAQlE;AA2DD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAW3D"}
|