mail-time 5.1.0 → 5.2.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 +45 -14
- package/adapters/mongo.d.ts +1 -0
- package/adapters/mongo.js +34 -16
- package/adapters/postgres.d.ts +1 -0
- package/adapters/postgres.js +45 -24
- package/adapters/redis.d.ts +6 -2
- package/adapters/redis.js +153 -72
- package/index.cjs +805 -127
- package/index.d.cts +136 -14
- package/index.d.ts +136 -14
- package/index.js +270 -15
- package/package.json +10 -3
- package/recipient-policy-lease.js +90 -0
- package/recipient-policy.js +166 -0
- package/recipient-rejections.js +62 -0
- package/scripts/migrate-redis-queue-to-cluster.mjs +5 -1
package/index.d.cts
CHANGED
|
@@ -50,15 +50,103 @@ export type MailTimeScheduler = {
|
|
|
50
50
|
ping: () => Promise<MailTimePingResult>;
|
|
51
51
|
setInterval: (func: (...args: any[]) => unknown, delay: number, uid: string) => Promise<string>;
|
|
52
52
|
destroy: () => boolean;
|
|
53
|
+
shutdown: (opts?: {
|
|
54
|
+
timeout?: number;
|
|
55
|
+
}) => Promise<boolean>;
|
|
53
56
|
pause: (timerId?: string) => boolean;
|
|
54
57
|
resume: (timerId?: string) => boolean;
|
|
55
58
|
};
|
|
59
|
+
export type MailTimeMailbox = string | {
|
|
60
|
+
address: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
};
|
|
63
|
+
export type MailTimePolicyRecipient = {
|
|
64
|
+
address: string;
|
|
65
|
+
sources: Array<"envelope" | "to" | "cc" | "bcc">;
|
|
66
|
+
};
|
|
67
|
+
export type MailTimePolicyDecision = {
|
|
68
|
+
address: string;
|
|
69
|
+
status: "suppressed" | "rejected" | "retry";
|
|
70
|
+
reason: string;
|
|
71
|
+
};
|
|
72
|
+
export type MailTimePolicyResult = {
|
|
73
|
+
decisions?: MailTimePolicyDecision[];
|
|
74
|
+
};
|
|
75
|
+
export type MailTimePolicyTransport = {
|
|
76
|
+
index: number;
|
|
77
|
+
name?: string;
|
|
78
|
+
};
|
|
79
|
+
export type MailTimePolicyEnvelope = {
|
|
80
|
+
from?: string;
|
|
81
|
+
to: string[];
|
|
82
|
+
};
|
|
83
|
+
export type MailTimePolicyContext = {
|
|
84
|
+
task: MailTimeTask;
|
|
85
|
+
attempt: number;
|
|
86
|
+
transport: MailTimePolicyTransport;
|
|
87
|
+
envelope: MailTimePolicyEnvelope;
|
|
88
|
+
recipients: MailTimePolicyRecipient[];
|
|
89
|
+
};
|
|
90
|
+
export type MailTimeBeforeSendPolicyContext = MailTimePolicyContext;
|
|
91
|
+
export type MailTimeStructuredRejection = {
|
|
92
|
+
address: string | null;
|
|
93
|
+
command?: string;
|
|
94
|
+
responseCode?: number;
|
|
95
|
+
response?: string;
|
|
96
|
+
message?: string;
|
|
97
|
+
transportIndex: number;
|
|
98
|
+
transportName?: string;
|
|
99
|
+
};
|
|
100
|
+
export type MailTimeRejectionPolicyContext = MailTimePolicyContext & {
|
|
101
|
+
error?: unknown;
|
|
102
|
+
info?: unknown;
|
|
103
|
+
rejections: MailTimeStructuredRejection[];
|
|
104
|
+
};
|
|
105
|
+
export type MailTimeRecipientResult = {
|
|
106
|
+
address: string;
|
|
107
|
+
status: "sent" | "error" | "suppressed" | "rejected";
|
|
108
|
+
sources?: Array<"envelope" | "to" | "cc" | "bcc">;
|
|
109
|
+
reasons: Array<{
|
|
110
|
+
provider: string;
|
|
111
|
+
reason: string;
|
|
112
|
+
}>;
|
|
113
|
+
attempt: number;
|
|
114
|
+
transportIndex?: number;
|
|
115
|
+
transportName?: string;
|
|
116
|
+
command?: string;
|
|
117
|
+
responseCode?: number;
|
|
118
|
+
response?: string;
|
|
119
|
+
message?: string;
|
|
120
|
+
};
|
|
121
|
+
export type MailTimeRecipientAttemptContext = MailTimeRejectionPolicyContext & {
|
|
122
|
+
decisions: MailTimeRecipientResult[];
|
|
123
|
+
};
|
|
124
|
+
export type MailTimeRecipientSummary = {
|
|
125
|
+
uuid: string;
|
|
126
|
+
tries: number;
|
|
127
|
+
isSettled: boolean;
|
|
128
|
+
recipients: {
|
|
129
|
+
sent: MailTimeRecipientResult[];
|
|
130
|
+
error: MailTimeRecipientResult[];
|
|
131
|
+
suppressed: MailTimeRecipientResult[];
|
|
132
|
+
rejected: MailTimeRecipientResult[];
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
export type MailTimeRecipientPolicy = {
|
|
136
|
+
name: string;
|
|
137
|
+
failureMode?: "retry" | "continue";
|
|
138
|
+
beforeSend?: (context: MailTimeBeforeSendPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>;
|
|
139
|
+
classifyRejections?: (context: MailTimeRejectionPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>;
|
|
140
|
+
observeAttempt?: (context: MailTimeRecipientAttemptContext) => void | Promise<void>;
|
|
141
|
+
};
|
|
56
142
|
export type MailTimeTask = {
|
|
57
143
|
uuid: string;
|
|
58
|
-
to?:
|
|
144
|
+
to?: MailTimeMailbox | MailTimeMailbox[];
|
|
59
145
|
tries: number;
|
|
60
146
|
sendAt: number;
|
|
61
147
|
isSent: boolean;
|
|
148
|
+
isSettled?: boolean;
|
|
149
|
+
recipientResults?: MailTimeRecipientResult[];
|
|
62
150
|
isCancelled: boolean;
|
|
63
151
|
isFailed: boolean;
|
|
64
152
|
isSending?: boolean;
|
|
@@ -84,6 +172,7 @@ export type CustomQueue = {
|
|
|
84
172
|
}) => Promise<boolean>;
|
|
85
173
|
update: (email: MailTimeTask | object, updateObj: object) => Promise<boolean>;
|
|
86
174
|
ready?: () => Promise<void>;
|
|
175
|
+
supportsRecipientPolicies?: boolean;
|
|
87
176
|
};
|
|
88
177
|
export type MailTimeRejectedRecipient = {
|
|
89
178
|
address: string;
|
|
@@ -91,7 +180,9 @@ export type MailTimeRejectedRecipient = {
|
|
|
91
180
|
};
|
|
92
181
|
export type MailTimeMailOptions = {
|
|
93
182
|
[key: string]: any;
|
|
94
|
-
to:
|
|
183
|
+
to: MailTimeMailbox | MailTimeMailbox[];
|
|
184
|
+
cc?: MailTimeMailbox | MailTimeMailbox[];
|
|
185
|
+
bcc?: MailTimeMailbox | MailTimeMailbox[];
|
|
95
186
|
sendAt?: Date | number;
|
|
96
187
|
template?: string;
|
|
97
188
|
concatSubject?: string;
|
|
@@ -139,8 +230,11 @@ export type MailTimeOptions = {
|
|
|
139
230
|
prefix?: string;
|
|
140
231
|
debug?: boolean;
|
|
141
232
|
josk?: MailTimeJoSkOptions;
|
|
142
|
-
|
|
143
|
-
|
|
233
|
+
recipientPolicies?: MailTimeRecipientPolicy[];
|
|
234
|
+
onError?: (error: unknown, email: MailTimeTask | null, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
235
|
+
onSent?: (email: MailTimeTask, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
236
|
+
onSuppressed?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
237
|
+
onRejected?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
144
238
|
};
|
|
145
239
|
/**
|
|
146
240
|
* @typedef {import('./presets.js').MailTimePresetName} MailTimePresetName
|
|
@@ -167,22 +261,41 @@ export type MailTimeOptions = {
|
|
|
167
261
|
* @typedef {{ [key: string]: any, adapter: MailTimeJoSkAdapterOptions | object, debug?: boolean, autoClear?: boolean, zombieTime?: number, lockLeaseTime?: number, minRevolvingDelay?: number, maxRevolvingDelay?: number, execute?: 'batch' | 'one', concurrency?: number, lockOwnerId?: string, resetOnInit?: boolean, onError?: (title: string, details: object) => void, onExecuted?: (uid: string, details: object) => void }} MailTimeJoSkOptions
|
|
168
262
|
*/
|
|
169
263
|
/**
|
|
170
|
-
* @typedef {{ [key: string]: any, ping: () => Promise<MailTimePingResult>, setInterval: (func: (...args: any[]) => unknown, delay: number, uid: string) => Promise<string>, destroy: () => boolean, pause: (timerId?: string) => boolean, resume: (timerId?: string) => boolean }} MailTimeScheduler
|
|
264
|
+
* @typedef {{ [key: string]: any, ping: () => Promise<MailTimePingResult>, setInterval: (func: (...args: any[]) => unknown, delay: number, uid: string) => Promise<string>, destroy: () => boolean, shutdown: (opts?: { timeout?: number }) => Promise<boolean>, pause: (timerId?: string) => boolean, resume: (timerId?: string) => boolean }} MailTimeScheduler
|
|
265
|
+
*/
|
|
266
|
+
/**
|
|
267
|
+
* @typedef {string | { address: string, name?: string }} MailTimeMailbox
|
|
171
268
|
*/
|
|
172
269
|
/**
|
|
173
|
-
* @typedef {{
|
|
270
|
+
* @typedef {{ address: string, sources: Array<'envelope' | 'to' | 'cc' | 'bcc'> }} MailTimePolicyRecipient
|
|
271
|
+
* @typedef {{ address: string, status: 'suppressed' | 'rejected' | 'retry', reason: string }} MailTimePolicyDecision
|
|
272
|
+
* @typedef {{ decisions?: MailTimePolicyDecision[] }} MailTimePolicyResult
|
|
273
|
+
* @typedef {{ index: number, name?: string }} MailTimePolicyTransport
|
|
274
|
+
* @typedef {{ from?: string, to: string[] }} MailTimePolicyEnvelope
|
|
275
|
+
* @typedef {{ task: MailTimeTask, attempt: number, transport: MailTimePolicyTransport, envelope: MailTimePolicyEnvelope, recipients: MailTimePolicyRecipient[] }} MailTimePolicyContext
|
|
276
|
+
* @typedef {MailTimePolicyContext} MailTimeBeforeSendPolicyContext
|
|
277
|
+
* @typedef {{ address: string | null, command?: string, responseCode?: number, response?: string, message?: string, transportIndex: number, transportName?: string }} MailTimeStructuredRejection
|
|
278
|
+
* @typedef {MailTimePolicyContext & { error?: unknown, info?: unknown, rejections: MailTimeStructuredRejection[] }} MailTimeRejectionPolicyContext
|
|
279
|
+
* @typedef {{ address: string, status: 'sent' | 'error' | 'suppressed' | 'rejected', sources?: Array<'envelope' | 'to' | 'cc' | 'bcc'>, reasons: Array<{ provider: string, reason: string }>, attempt: number, transportIndex?: number, transportName?: string, command?: string, responseCode?: number, response?: string, message?: string }} MailTimeRecipientResult
|
|
280
|
+
* @typedef {MailTimeRejectionPolicyContext & { decisions: MailTimeRecipientResult[] }} MailTimeRecipientAttemptContext
|
|
281
|
+
* @typedef {{ uuid: string, tries: number, isSettled: boolean, recipients: { sent: MailTimeRecipientResult[], error: MailTimeRecipientResult[], suppressed: MailTimeRecipientResult[], rejected: MailTimeRecipientResult[] } }} MailTimeRecipientSummary
|
|
282
|
+
* @typedef {{ name: string, failureMode?: 'retry' | 'continue', beforeSend?: (context: MailTimeBeforeSendPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>, classifyRejections?: (context: MailTimeRejectionPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>, observeAttempt?: (context: MailTimeRecipientAttemptContext) => void | Promise<void> }} MailTimeRecipientPolicy
|
|
283
|
+
* @description Policy contexts are read-only by contract. Providers must bound their own I/O; renewal budgets do not limit hook duration.
|
|
284
|
+
*/
|
|
285
|
+
/**
|
|
286
|
+
* @typedef {{ uuid: string, to?: MailTimeMailbox | MailTimeMailbox[], tries: number, sendAt: number, isSent: boolean, isSettled?: boolean, recipientResults?: MailTimeRecipientResult[], isCancelled: boolean, isFailed: boolean, isSending?: boolean, sendingAt?: number, template?: string | false, transport: number, concatSubject?: string | false, mailOptions: MailTimeMailOptions[] }} MailTimeTask
|
|
174
287
|
*/
|
|
175
288
|
/**
|
|
176
289
|
* @typedef {{ limit?: number, sendingTimeout?: number }} MailTimeIterateOptions
|
|
177
290
|
*/
|
|
178
291
|
/**
|
|
179
|
-
* @typedef {{ ping: () => Promise<MailTimePingResult>, iterate: (opts?: MailTimeIterateOptions) => Promise<void> | void, getPendingTo: (to: string, sendAt: number) => Promise<MailTimeTask | object | null>, push: (email: MailTimeTask) => Promise<void> | void, cancel: (uuid: string) => Promise<boolean>, remove: (email: MailTimeTask | object, opts?: { leaseTries: number, leaseSendingAt: number }) => Promise<boolean>, update: (email: MailTimeTask | object, updateObj: object) => Promise<boolean>, ready?: () => Promise<void
|
|
292
|
+
* @typedef {{ ping: () => Promise<MailTimePingResult>, iterate: (opts?: MailTimeIterateOptions) => Promise<void> | void, getPendingTo: (to: string, sendAt: number) => Promise<MailTimeTask | object | null>, push: (email: MailTimeTask) => Promise<void> | void, cancel: (uuid: string) => Promise<boolean>, remove: (email: MailTimeTask | object, opts?: { leaseTries: number, leaseSendingAt: number }) => Promise<boolean>, update: (email: MailTimeTask | object, updateObj: object) => Promise<boolean>, ready?: () => Promise<void>, supportsRecipientPolicies?: boolean }} CustomQueue
|
|
180
293
|
*/
|
|
181
294
|
/**
|
|
182
295
|
* @typedef {{ address: string, error: string }} MailTimeRejectedRecipient
|
|
183
296
|
*/
|
|
184
297
|
/**
|
|
185
|
-
* @typedef {{ [key: string]: any, to:
|
|
298
|
+
* @typedef {{ [key: string]: any, to: MailTimeMailbox | MailTimeMailbox[], cc?: MailTimeMailbox | MailTimeMailbox[], bcc?: MailTimeMailbox | MailTimeMailbox[], sendAt?: Date | number, template?: string, concatSubject?: string, text?: string | false, html?: string | false, subject?: string, accepted?: string[], rejected?: MailTimeRejectedRecipient[] }} MailTimeMailOptions
|
|
186
299
|
*/
|
|
187
300
|
/**
|
|
188
301
|
* @typedef {{ subject?: string }} MailTimeConcatEmailsOptions
|
|
@@ -191,9 +304,15 @@ export type MailTimeOptions = {
|
|
|
191
304
|
* @typedef {{ index: number, from: string | undefined }} MailTimeFromDetails
|
|
192
305
|
*/
|
|
193
306
|
/**
|
|
194
|
-
* @typedef {{ queue: RedisQueue | MongoQueue | PostgresQueue | CustomQueue, type?: 'server' | 'client', from?: string | ((transport: MailTimeTransport, details: MailTimeFromDetails) => string), transports?: MailTimeTransport[], strategy?: 'backup' | 'balancer', failsToNext?: number, shouldFailOver?: (error: unknown, info: object | undefined, email: MailTimeTask) => boolean, retries?: number, maxTries?: number, retryDelay?: number, interval?: number, keepHistory?: boolean, concatEmails?: boolean | MailTimeConcatEmailsOptions, concatSubject?: string, concatDelimiter?: string, concatDelay?: number, concatThrottling?: number, revolvingInterval?: number, mode?: 'one' | 'batch', concurrency?: number, sendingTimeout?: number, renewClaim?: boolean | number, maxRenewals?: number, strictPayload?: boolean, allowedMailFields?: string[], verifyTransports?: boolean, template?: string, prefix?: string, debug?: boolean, josk?: MailTimeJoSkOptions, onError?: (error: unknown, email: MailTimeTask | null, details?: object) => void
|
|
307
|
+
* @typedef {{ queue: RedisQueue | MongoQueue | PostgresQueue | CustomQueue, type?: 'server' | 'client', from?: string | ((transport: MailTimeTransport, details: MailTimeFromDetails) => string), transports?: MailTimeTransport[], strategy?: 'backup' | 'balancer', failsToNext?: number, shouldFailOver?: (error: unknown, info: object | undefined, email: MailTimeTask) => boolean, retries?: number, maxTries?: number, retryDelay?: number, interval?: number, keepHistory?: boolean, concatEmails?: boolean | MailTimeConcatEmailsOptions, concatSubject?: string, concatDelimiter?: string, concatDelay?: number, concatThrottling?: number, revolvingInterval?: number, mode?: 'one' | 'batch', concurrency?: number, sendingTimeout?: number, renewClaim?: boolean | number, maxRenewals?: number, strictPayload?: boolean, allowedMailFields?: string[], verifyTransports?: boolean, template?: string, prefix?: string, debug?: boolean, josk?: MailTimeJoSkOptions, recipientPolicies?: MailTimeRecipientPolicy[], onError?: (error: unknown, email: MailTimeTask | null, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>, onSent?: (email: MailTimeTask, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>, onSuppressed?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>, onRejected?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void> }} MailTimeOptions
|
|
308
|
+
*/
|
|
309
|
+
/**
|
|
310
|
+
* Class of MailTime.
|
|
311
|
+
* With recipientPolicies, terminal callbacks receive grouped recipients and a complete summary after persistence.
|
|
312
|
+
* isSettled includes exhausted errors; isSent means all accepted; isFailed means an error or permanent rejection.
|
|
313
|
+
* Unparseable terminal preparation failures invoke onError with an empty recipient group.
|
|
314
|
+
* Hooks must bound their own I/O. Callback notifications are best-effort, not durable exactly-once delivery.
|
|
195
315
|
*/
|
|
196
|
-
/** Class of MailTime */
|
|
197
316
|
export class MailTime {
|
|
198
317
|
static set Template(newVal: string);
|
|
199
318
|
static get Template(): string;
|
|
@@ -223,8 +342,10 @@ export class MailTime {
|
|
|
223
342
|
retryDelay: number;
|
|
224
343
|
template: string;
|
|
225
344
|
keepHistory: boolean;
|
|
226
|
-
onSent: (email: MailTimeTask, details?: object) => void
|
|
227
|
-
onError: (error: unknown, email: MailTimeTask | null, details?: object) => void
|
|
345
|
+
onSent: (email: MailTimeTask, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
346
|
+
onError: (error: unknown, email: MailTimeTask | null, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
347
|
+
onSuppressed: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
348
|
+
onRejected: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
228
349
|
revolvingInterval: number;
|
|
229
350
|
mode: "one" | "batch";
|
|
230
351
|
concurrency: number;
|
|
@@ -283,12 +404,13 @@ export class MailTime {
|
|
|
283
404
|
/**
|
|
284
405
|
* @memberOf MailTime
|
|
285
406
|
* @name destroy
|
|
286
|
-
* @description Stop the scheduler and block future dispatches. Without `{ drain: true }`,
|
|
287
|
-
* @param {{ drain?: boolean }} [opts]
|
|
407
|
+
* @description Stop the scheduler and block future dispatches. Without `{ drain: true }`, in-flight SMTP attempts are neutralized and their claims recover after `sendingTimeout`. With `{ drain: true }`, await JoSk shutdown and in-flight SMTP; resolves false if a scheduler handler exceeds `schedulerTimeout` (default 10000ms) or JoSk shutdown throws (logged); never rejects. The timeout does not bound SMTP drain time.
|
|
408
|
+
* @param {{ drain?: boolean, schedulerTimeout?: number }} [opts] - schedulerTimeout must be finite and non-negative; used only with drain
|
|
288
409
|
* @returns {boolean | Promise<boolean>}
|
|
289
410
|
*/
|
|
290
411
|
destroy(opts?: {
|
|
291
412
|
drain?: boolean;
|
|
413
|
+
schedulerTimeout?: number;
|
|
292
414
|
}): boolean | Promise<boolean>;
|
|
293
415
|
/**
|
|
294
416
|
* @async
|
package/index.d.ts
CHANGED
|
@@ -50,15 +50,103 @@ export type MailTimeScheduler = {
|
|
|
50
50
|
ping: () => Promise<MailTimePingResult>;
|
|
51
51
|
setInterval: (func: (...args: any[]) => unknown, delay: number, uid: string) => Promise<string>;
|
|
52
52
|
destroy: () => boolean;
|
|
53
|
+
shutdown: (opts?: {
|
|
54
|
+
timeout?: number;
|
|
55
|
+
}) => Promise<boolean>;
|
|
53
56
|
pause: (timerId?: string) => boolean;
|
|
54
57
|
resume: (timerId?: string) => boolean;
|
|
55
58
|
};
|
|
59
|
+
export type MailTimeMailbox = string | {
|
|
60
|
+
address: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
};
|
|
63
|
+
export type MailTimePolicyRecipient = {
|
|
64
|
+
address: string;
|
|
65
|
+
sources: Array<"envelope" | "to" | "cc" | "bcc">;
|
|
66
|
+
};
|
|
67
|
+
export type MailTimePolicyDecision = {
|
|
68
|
+
address: string;
|
|
69
|
+
status: "suppressed" | "rejected" | "retry";
|
|
70
|
+
reason: string;
|
|
71
|
+
};
|
|
72
|
+
export type MailTimePolicyResult = {
|
|
73
|
+
decisions?: MailTimePolicyDecision[];
|
|
74
|
+
};
|
|
75
|
+
export type MailTimePolicyTransport = {
|
|
76
|
+
index: number;
|
|
77
|
+
name?: string;
|
|
78
|
+
};
|
|
79
|
+
export type MailTimePolicyEnvelope = {
|
|
80
|
+
from?: string;
|
|
81
|
+
to: string[];
|
|
82
|
+
};
|
|
83
|
+
export type MailTimePolicyContext = {
|
|
84
|
+
task: MailTimeTask;
|
|
85
|
+
attempt: number;
|
|
86
|
+
transport: MailTimePolicyTransport;
|
|
87
|
+
envelope: MailTimePolicyEnvelope;
|
|
88
|
+
recipients: MailTimePolicyRecipient[];
|
|
89
|
+
};
|
|
90
|
+
export type MailTimeBeforeSendPolicyContext = MailTimePolicyContext;
|
|
91
|
+
export type MailTimeStructuredRejection = {
|
|
92
|
+
address: string | null;
|
|
93
|
+
command?: string;
|
|
94
|
+
responseCode?: number;
|
|
95
|
+
response?: string;
|
|
96
|
+
message?: string;
|
|
97
|
+
transportIndex: number;
|
|
98
|
+
transportName?: string;
|
|
99
|
+
};
|
|
100
|
+
export type MailTimeRejectionPolicyContext = MailTimePolicyContext & {
|
|
101
|
+
error?: unknown;
|
|
102
|
+
info?: unknown;
|
|
103
|
+
rejections: MailTimeStructuredRejection[];
|
|
104
|
+
};
|
|
105
|
+
export type MailTimeRecipientResult = {
|
|
106
|
+
address: string;
|
|
107
|
+
status: "sent" | "error" | "suppressed" | "rejected";
|
|
108
|
+
sources?: Array<"envelope" | "to" | "cc" | "bcc">;
|
|
109
|
+
reasons: Array<{
|
|
110
|
+
provider: string;
|
|
111
|
+
reason: string;
|
|
112
|
+
}>;
|
|
113
|
+
attempt: number;
|
|
114
|
+
transportIndex?: number;
|
|
115
|
+
transportName?: string;
|
|
116
|
+
command?: string;
|
|
117
|
+
responseCode?: number;
|
|
118
|
+
response?: string;
|
|
119
|
+
message?: string;
|
|
120
|
+
};
|
|
121
|
+
export type MailTimeRecipientAttemptContext = MailTimeRejectionPolicyContext & {
|
|
122
|
+
decisions: MailTimeRecipientResult[];
|
|
123
|
+
};
|
|
124
|
+
export type MailTimeRecipientSummary = {
|
|
125
|
+
uuid: string;
|
|
126
|
+
tries: number;
|
|
127
|
+
isSettled: boolean;
|
|
128
|
+
recipients: {
|
|
129
|
+
sent: MailTimeRecipientResult[];
|
|
130
|
+
error: MailTimeRecipientResult[];
|
|
131
|
+
suppressed: MailTimeRecipientResult[];
|
|
132
|
+
rejected: MailTimeRecipientResult[];
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
export type MailTimeRecipientPolicy = {
|
|
136
|
+
name: string;
|
|
137
|
+
failureMode?: "retry" | "continue";
|
|
138
|
+
beforeSend?: (context: MailTimeBeforeSendPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>;
|
|
139
|
+
classifyRejections?: (context: MailTimeRejectionPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>;
|
|
140
|
+
observeAttempt?: (context: MailTimeRecipientAttemptContext) => void | Promise<void>;
|
|
141
|
+
};
|
|
56
142
|
export type MailTimeTask = {
|
|
57
143
|
uuid: string;
|
|
58
|
-
to?:
|
|
144
|
+
to?: MailTimeMailbox | MailTimeMailbox[];
|
|
59
145
|
tries: number;
|
|
60
146
|
sendAt: number;
|
|
61
147
|
isSent: boolean;
|
|
148
|
+
isSettled?: boolean;
|
|
149
|
+
recipientResults?: MailTimeRecipientResult[];
|
|
62
150
|
isCancelled: boolean;
|
|
63
151
|
isFailed: boolean;
|
|
64
152
|
isSending?: boolean;
|
|
@@ -84,6 +172,7 @@ export type CustomQueue = {
|
|
|
84
172
|
}) => Promise<boolean>;
|
|
85
173
|
update: (email: MailTimeTask | object, updateObj: object) => Promise<boolean>;
|
|
86
174
|
ready?: () => Promise<void>;
|
|
175
|
+
supportsRecipientPolicies?: boolean;
|
|
87
176
|
};
|
|
88
177
|
export type MailTimeRejectedRecipient = {
|
|
89
178
|
address: string;
|
|
@@ -91,7 +180,9 @@ export type MailTimeRejectedRecipient = {
|
|
|
91
180
|
};
|
|
92
181
|
export type MailTimeMailOptions = {
|
|
93
182
|
[key: string]: any;
|
|
94
|
-
to:
|
|
183
|
+
to: MailTimeMailbox | MailTimeMailbox[];
|
|
184
|
+
cc?: MailTimeMailbox | MailTimeMailbox[];
|
|
185
|
+
bcc?: MailTimeMailbox | MailTimeMailbox[];
|
|
95
186
|
sendAt?: Date | number;
|
|
96
187
|
template?: string;
|
|
97
188
|
concatSubject?: string;
|
|
@@ -139,8 +230,11 @@ export type MailTimeOptions = {
|
|
|
139
230
|
prefix?: string;
|
|
140
231
|
debug?: boolean;
|
|
141
232
|
josk?: MailTimeJoSkOptions;
|
|
142
|
-
|
|
143
|
-
|
|
233
|
+
recipientPolicies?: MailTimeRecipientPolicy[];
|
|
234
|
+
onError?: (error: unknown, email: MailTimeTask | null, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
235
|
+
onSent?: (email: MailTimeTask, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
236
|
+
onSuppressed?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
237
|
+
onRejected?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
144
238
|
};
|
|
145
239
|
/**
|
|
146
240
|
* @typedef {import('./presets.js').MailTimePresetName} MailTimePresetName
|
|
@@ -167,22 +261,41 @@ export type MailTimeOptions = {
|
|
|
167
261
|
* @typedef {{ [key: string]: any, adapter: MailTimeJoSkAdapterOptions | object, debug?: boolean, autoClear?: boolean, zombieTime?: number, lockLeaseTime?: number, minRevolvingDelay?: number, maxRevolvingDelay?: number, execute?: 'batch' | 'one', concurrency?: number, lockOwnerId?: string, resetOnInit?: boolean, onError?: (title: string, details: object) => void, onExecuted?: (uid: string, details: object) => void }} MailTimeJoSkOptions
|
|
168
262
|
*/
|
|
169
263
|
/**
|
|
170
|
-
* @typedef {{ [key: string]: any, ping: () => Promise<MailTimePingResult>, setInterval: (func: (...args: any[]) => unknown, delay: number, uid: string) => Promise<string>, destroy: () => boolean, pause: (timerId?: string) => boolean, resume: (timerId?: string) => boolean }} MailTimeScheduler
|
|
264
|
+
* @typedef {{ [key: string]: any, ping: () => Promise<MailTimePingResult>, setInterval: (func: (...args: any[]) => unknown, delay: number, uid: string) => Promise<string>, destroy: () => boolean, shutdown: (opts?: { timeout?: number }) => Promise<boolean>, pause: (timerId?: string) => boolean, resume: (timerId?: string) => boolean }} MailTimeScheduler
|
|
265
|
+
*/
|
|
266
|
+
/**
|
|
267
|
+
* @typedef {string | { address: string, name?: string }} MailTimeMailbox
|
|
171
268
|
*/
|
|
172
269
|
/**
|
|
173
|
-
* @typedef {{
|
|
270
|
+
* @typedef {{ address: string, sources: Array<'envelope' | 'to' | 'cc' | 'bcc'> }} MailTimePolicyRecipient
|
|
271
|
+
* @typedef {{ address: string, status: 'suppressed' | 'rejected' | 'retry', reason: string }} MailTimePolicyDecision
|
|
272
|
+
* @typedef {{ decisions?: MailTimePolicyDecision[] }} MailTimePolicyResult
|
|
273
|
+
* @typedef {{ index: number, name?: string }} MailTimePolicyTransport
|
|
274
|
+
* @typedef {{ from?: string, to: string[] }} MailTimePolicyEnvelope
|
|
275
|
+
* @typedef {{ task: MailTimeTask, attempt: number, transport: MailTimePolicyTransport, envelope: MailTimePolicyEnvelope, recipients: MailTimePolicyRecipient[] }} MailTimePolicyContext
|
|
276
|
+
* @typedef {MailTimePolicyContext} MailTimeBeforeSendPolicyContext
|
|
277
|
+
* @typedef {{ address: string | null, command?: string, responseCode?: number, response?: string, message?: string, transportIndex: number, transportName?: string }} MailTimeStructuredRejection
|
|
278
|
+
* @typedef {MailTimePolicyContext & { error?: unknown, info?: unknown, rejections: MailTimeStructuredRejection[] }} MailTimeRejectionPolicyContext
|
|
279
|
+
* @typedef {{ address: string, status: 'sent' | 'error' | 'suppressed' | 'rejected', sources?: Array<'envelope' | 'to' | 'cc' | 'bcc'>, reasons: Array<{ provider: string, reason: string }>, attempt: number, transportIndex?: number, transportName?: string, command?: string, responseCode?: number, response?: string, message?: string }} MailTimeRecipientResult
|
|
280
|
+
* @typedef {MailTimeRejectionPolicyContext & { decisions: MailTimeRecipientResult[] }} MailTimeRecipientAttemptContext
|
|
281
|
+
* @typedef {{ uuid: string, tries: number, isSettled: boolean, recipients: { sent: MailTimeRecipientResult[], error: MailTimeRecipientResult[], suppressed: MailTimeRecipientResult[], rejected: MailTimeRecipientResult[] } }} MailTimeRecipientSummary
|
|
282
|
+
* @typedef {{ name: string, failureMode?: 'retry' | 'continue', beforeSend?: (context: MailTimeBeforeSendPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>, classifyRejections?: (context: MailTimeRejectionPolicyContext) => void | MailTimePolicyResult | Promise<void | MailTimePolicyResult>, observeAttempt?: (context: MailTimeRecipientAttemptContext) => void | Promise<void> }} MailTimeRecipientPolicy
|
|
283
|
+
* @description Policy contexts are read-only by contract. Providers must bound their own I/O; renewal budgets do not limit hook duration.
|
|
284
|
+
*/
|
|
285
|
+
/**
|
|
286
|
+
* @typedef {{ uuid: string, to?: MailTimeMailbox | MailTimeMailbox[], tries: number, sendAt: number, isSent: boolean, isSettled?: boolean, recipientResults?: MailTimeRecipientResult[], isCancelled: boolean, isFailed: boolean, isSending?: boolean, sendingAt?: number, template?: string | false, transport: number, concatSubject?: string | false, mailOptions: MailTimeMailOptions[] }} MailTimeTask
|
|
174
287
|
*/
|
|
175
288
|
/**
|
|
176
289
|
* @typedef {{ limit?: number, sendingTimeout?: number }} MailTimeIterateOptions
|
|
177
290
|
*/
|
|
178
291
|
/**
|
|
179
|
-
* @typedef {{ ping: () => Promise<MailTimePingResult>, iterate: (opts?: MailTimeIterateOptions) => Promise<void> | void, getPendingTo: (to: string, sendAt: number) => Promise<MailTimeTask | object | null>, push: (email: MailTimeTask) => Promise<void> | void, cancel: (uuid: string) => Promise<boolean>, remove: (email: MailTimeTask | object, opts?: { leaseTries: number, leaseSendingAt: number }) => Promise<boolean>, update: (email: MailTimeTask | object, updateObj: object) => Promise<boolean>, ready?: () => Promise<void
|
|
292
|
+
* @typedef {{ ping: () => Promise<MailTimePingResult>, iterate: (opts?: MailTimeIterateOptions) => Promise<void> | void, getPendingTo: (to: string, sendAt: number) => Promise<MailTimeTask | object | null>, push: (email: MailTimeTask) => Promise<void> | void, cancel: (uuid: string) => Promise<boolean>, remove: (email: MailTimeTask | object, opts?: { leaseTries: number, leaseSendingAt: number }) => Promise<boolean>, update: (email: MailTimeTask | object, updateObj: object) => Promise<boolean>, ready?: () => Promise<void>, supportsRecipientPolicies?: boolean }} CustomQueue
|
|
180
293
|
*/
|
|
181
294
|
/**
|
|
182
295
|
* @typedef {{ address: string, error: string }} MailTimeRejectedRecipient
|
|
183
296
|
*/
|
|
184
297
|
/**
|
|
185
|
-
* @typedef {{ [key: string]: any, to:
|
|
298
|
+
* @typedef {{ [key: string]: any, to: MailTimeMailbox | MailTimeMailbox[], cc?: MailTimeMailbox | MailTimeMailbox[], bcc?: MailTimeMailbox | MailTimeMailbox[], sendAt?: Date | number, template?: string, concatSubject?: string, text?: string | false, html?: string | false, subject?: string, accepted?: string[], rejected?: MailTimeRejectedRecipient[] }} MailTimeMailOptions
|
|
186
299
|
*/
|
|
187
300
|
/**
|
|
188
301
|
* @typedef {{ subject?: string }} MailTimeConcatEmailsOptions
|
|
@@ -191,9 +304,15 @@ export type MailTimeOptions = {
|
|
|
191
304
|
* @typedef {{ index: number, from: string | undefined }} MailTimeFromDetails
|
|
192
305
|
*/
|
|
193
306
|
/**
|
|
194
|
-
* @typedef {{ queue: RedisQueue | MongoQueue | PostgresQueue | CustomQueue, type?: 'server' | 'client', from?: string | ((transport: MailTimeTransport, details: MailTimeFromDetails) => string), transports?: MailTimeTransport[], strategy?: 'backup' | 'balancer', failsToNext?: number, shouldFailOver?: (error: unknown, info: object | undefined, email: MailTimeTask) => boolean, retries?: number, maxTries?: number, retryDelay?: number, interval?: number, keepHistory?: boolean, concatEmails?: boolean | MailTimeConcatEmailsOptions, concatSubject?: string, concatDelimiter?: string, concatDelay?: number, concatThrottling?: number, revolvingInterval?: number, mode?: 'one' | 'batch', concurrency?: number, sendingTimeout?: number, renewClaim?: boolean | number, maxRenewals?: number, strictPayload?: boolean, allowedMailFields?: string[], verifyTransports?: boolean, template?: string, prefix?: string, debug?: boolean, josk?: MailTimeJoSkOptions, onError?: (error: unknown, email: MailTimeTask | null, details?: object) => void
|
|
307
|
+
* @typedef {{ queue: RedisQueue | MongoQueue | PostgresQueue | CustomQueue, type?: 'server' | 'client', from?: string | ((transport: MailTimeTransport, details: MailTimeFromDetails) => string), transports?: MailTimeTransport[], strategy?: 'backup' | 'balancer', failsToNext?: number, shouldFailOver?: (error: unknown, info: object | undefined, email: MailTimeTask) => boolean, retries?: number, maxTries?: number, retryDelay?: number, interval?: number, keepHistory?: boolean, concatEmails?: boolean | MailTimeConcatEmailsOptions, concatSubject?: string, concatDelimiter?: string, concatDelay?: number, concatThrottling?: number, revolvingInterval?: number, mode?: 'one' | 'batch', concurrency?: number, sendingTimeout?: number, renewClaim?: boolean | number, maxRenewals?: number, strictPayload?: boolean, allowedMailFields?: string[], verifyTransports?: boolean, template?: string, prefix?: string, debug?: boolean, josk?: MailTimeJoSkOptions, recipientPolicies?: MailTimeRecipientPolicy[], onError?: (error: unknown, email: MailTimeTask | null, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>, onSent?: (email: MailTimeTask, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>, onSuppressed?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>, onRejected?: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void> }} MailTimeOptions
|
|
308
|
+
*/
|
|
309
|
+
/**
|
|
310
|
+
* Class of MailTime.
|
|
311
|
+
* With recipientPolicies, terminal callbacks receive grouped recipients and a complete summary after persistence.
|
|
312
|
+
* isSettled includes exhausted errors; isSent means all accepted; isFailed means an error or permanent rejection.
|
|
313
|
+
* Unparseable terminal preparation failures invoke onError with an empty recipient group.
|
|
314
|
+
* Hooks must bound their own I/O. Callback notifications are best-effort, not durable exactly-once delivery.
|
|
195
315
|
*/
|
|
196
|
-
/** Class of MailTime */
|
|
197
316
|
export class MailTime {
|
|
198
317
|
static set Template(newVal: string);
|
|
199
318
|
static get Template(): string;
|
|
@@ -223,8 +342,10 @@ export class MailTime {
|
|
|
223
342
|
retryDelay: number;
|
|
224
343
|
template: string;
|
|
225
344
|
keepHistory: boolean;
|
|
226
|
-
onSent: (email: MailTimeTask, details?: object) => void
|
|
227
|
-
onError: (error: unknown, email: MailTimeTask | null, details?: object) => void
|
|
345
|
+
onSent: (email: MailTimeTask, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
346
|
+
onError: (error: unknown, email: MailTimeTask | null, details?: object, recipients?: MailTimeRecipientResult[], summary?: MailTimeRecipientSummary) => void | Promise<void>;
|
|
347
|
+
onSuppressed: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
348
|
+
onRejected: (email: MailTimeTask, recipients: MailTimeRecipientResult[], summary: MailTimeRecipientSummary) => void | Promise<void>;
|
|
228
349
|
revolvingInterval: number;
|
|
229
350
|
mode: "one" | "batch";
|
|
230
351
|
concurrency: number;
|
|
@@ -283,12 +404,13 @@ export class MailTime {
|
|
|
283
404
|
/**
|
|
284
405
|
* @memberOf MailTime
|
|
285
406
|
* @name destroy
|
|
286
|
-
* @description Stop the scheduler and block future dispatches. Without `{ drain: true }`,
|
|
287
|
-
* @param {{ drain?: boolean }} [opts]
|
|
407
|
+
* @description Stop the scheduler and block future dispatches. Without `{ drain: true }`, in-flight SMTP attempts are neutralized and their claims recover after `sendingTimeout`. With `{ drain: true }`, await JoSk shutdown and in-flight SMTP; resolves false if a scheduler handler exceeds `schedulerTimeout` (default 10000ms) or JoSk shutdown throws (logged); never rejects. The timeout does not bound SMTP drain time.
|
|
408
|
+
* @param {{ drain?: boolean, schedulerTimeout?: number }} [opts] - schedulerTimeout must be finite and non-negative; used only with drain
|
|
288
409
|
* @returns {boolean | Promise<boolean>}
|
|
289
410
|
*/
|
|
290
411
|
destroy(opts?: {
|
|
291
412
|
drain?: boolean;
|
|
413
|
+
schedulerTimeout?: number;
|
|
292
414
|
}): boolean | Promise<boolean>;
|
|
293
415
|
/**
|
|
294
416
|
* @async
|