@c9up/rover 0.1.3
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/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/BaseMail.d.ts +28 -0
- package/dist/BaseMail.d.ts.map +1 -0
- package/dist/BaseMail.js +42 -0
- package/dist/BaseMail.js.map +1 -0
- package/dist/Mail.d.ts +166 -0
- package/dist/Mail.d.ts.map +1 -0
- package/dist/Mail.js +451 -0
- package/dist/Mail.js.map +1 -0
- package/dist/MessageBuilder.d.ts +38 -0
- package/dist/MessageBuilder.d.ts.map +1 -0
- package/dist/MessageBuilder.js +70 -0
- package/dist/MessageBuilder.js.map +1 -0
- package/dist/RoverError.d.ts +30 -0
- package/dist/RoverError.d.ts.map +1 -0
- package/dist/RoverError.js +33 -0
- package/dist/RoverError.js.map +1 -0
- package/dist/RoverProvider.d.ts +24 -0
- package/dist/RoverProvider.d.ts.map +1 -0
- package/dist/RoverProvider.js +51 -0
- package/dist/RoverProvider.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/queue/MailJob.d.ts +41 -0
- package/dist/queue/MailJob.d.ts.map +1 -0
- package/dist/queue/MailJob.js +75 -0
- package/dist/queue/MailJob.js.map +1 -0
- package/dist/retry.d.ts +20 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +101 -0
- package/dist/retry.js.map +1 -0
- package/dist/services/main.d.ts +20 -0
- package/dist/services/main.d.ts.map +1 -0
- package/dist/services/main.js +33 -0
- package/dist/services/main.js.map +1 -0
- package/dist/templating/SimpleTemplate.d.ts +7 -0
- package/dist/templating/SimpleTemplate.d.ts.map +1 -0
- package/dist/templating/SimpleTemplate.js +192 -0
- package/dist/templating/SimpleTemplate.js.map +1 -0
- package/dist/templating/loadNapi.d.ts +21 -0
- package/dist/templating/loadNapi.d.ts.map +1 -0
- package/dist/templating/loadNapi.js +115 -0
- package/dist/templating/loadNapi.js.map +1 -0
- package/dist/testing/FakeMail.d.ts +31 -0
- package/dist/testing/FakeMail.d.ts.map +1 -0
- package/dist/testing/FakeMail.js +90 -0
- package/dist/testing/FakeMail.js.map +1 -0
- package/dist/transports/MailgunTransport.d.ts +7 -0
- package/dist/transports/MailgunTransport.d.ts.map +1 -0
- package/dist/transports/MailgunTransport.js +149 -0
- package/dist/transports/MailgunTransport.js.map +1 -0
- package/dist/transports/ResendTransport.d.ts +7 -0
- package/dist/transports/ResendTransport.d.ts.map +1 -0
- package/dist/transports/ResendTransport.js +111 -0
- package/dist/transports/ResendTransport.js.map +1 -0
- package/dist/transports/SendGridTransport.d.ts +7 -0
- package/dist/transports/SendGridTransport.d.ts.map +1 -0
- package/dist/transports/SendGridTransport.js +165 -0
- package/dist/transports/SendGridTransport.js.map +1 -0
- package/dist/transports/SesTransport.d.ts +7 -0
- package/dist/transports/SesTransport.d.ts.map +1 -0
- package/dist/transports/SesTransport.js +334 -0
- package/dist/transports/SesTransport.js.map +1 -0
- package/dist/transports/fetchError.d.ts +13 -0
- package/dist/transports/fetchError.d.ts.map +1 -0
- package/dist/transports/fetchError.js +35 -0
- package/dist/transports/fetchError.js.map +1 -0
- package/dist/webhooks/context.d.ts +35 -0
- package/dist/webhooks/context.d.ts.map +1 -0
- package/dist/webhooks/context.js +7 -0
- package/dist/webhooks/context.js.map +1 -0
- package/dist/webhooks/mailgun.d.ts +13 -0
- package/dist/webhooks/mailgun.d.ts.map +1 -0
- package/dist/webhooks/mailgun.js +102 -0
- package/dist/webhooks/mailgun.js.map +1 -0
- package/dist/webhooks/resend.d.ts +16 -0
- package/dist/webhooks/resend.d.ts.map +1 -0
- package/dist/webhooks/resend.js +121 -0
- package/dist/webhooks/resend.js.map +1 -0
- package/dist/webhooks/sendgrid.d.ts +13 -0
- package/dist/webhooks/sendgrid.d.ts.map +1 -0
- package/dist/webhooks/sendgrid.js +104 -0
- package/dist/webhooks/sendgrid.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +97 -0
- package/scripts/copy-napi.mjs +62 -0
- package/src/BaseMail.ts +52 -0
- package/src/Mail.ts +663 -0
- package/src/MessageBuilder.ts +101 -0
- package/src/RoverError.ts +44 -0
- package/src/RoverProvider.ts +72 -0
- package/src/config.ts +7 -0
- package/src/index.ts +30 -0
- package/src/queue/MailJob.ts +131 -0
- package/src/retry.ts +135 -0
- package/src/services/main.ts +41 -0
- package/src/templating/SimpleTemplate.ts +240 -0
- package/src/templating/loadNapi.ts +169 -0
- package/src/testing/FakeMail.ts +112 -0
- package/src/transports/MailgunTransport.ts +204 -0
- package/src/transports/ResendTransport.ts +147 -0
- package/src/transports/SendGridTransport.ts +246 -0
- package/src/transports/SesTransport.ts +394 -0
- package/src/transports/fetchError.ts +42 -0
- package/src/webhooks/context.ts +41 -0
- package/src/webhooks/mailgun.ts +134 -0
- package/src/webhooks/resend.ts +164 -0
- package/src/webhooks/sendgrid.ts +133 -0
package/dist/Mail.js
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { RoverError } from "./RoverError.js";
|
|
3
|
+
import nodemailer from "nodemailer";
|
|
4
|
+
import { BaseMail } from "./BaseMail.js";
|
|
5
|
+
import { MessageBuilder, } from "./MessageBuilder.js";
|
|
6
|
+
import { MAIL_JOB_NAME, MailJobHandler, } from "./queue/MailJob.js";
|
|
7
|
+
import { computeBackoffMs, isRetryableError, resolveRetryConfig, } from "./retry.js";
|
|
8
|
+
import { setViewsRoot } from "./templating/SimpleTemplate.js";
|
|
9
|
+
import { FakeMail } from "./testing/FakeMail.js";
|
|
10
|
+
export { MessageBuilder };
|
|
11
|
+
/**
|
|
12
|
+
* Message builder — fluent API for composing an email.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* SMTP transport — thin wrapper around `nodemailer`. Nodemailer handles
|
|
16
|
+
* the SMTP state machine, TLS / STARTTLS negotiation, AUTH LOGIN /
|
|
17
|
+
* PLAIN / XOAUTH2, dot-stuffing, MIME assembly, attachments, and address
|
|
18
|
+
* encoding for 10+ years. We forward the `MailMessage` shape and surface
|
|
19
|
+
* the `messageId` returned by the server.
|
|
20
|
+
*/
|
|
21
|
+
export class SmtpTransport {
|
|
22
|
+
#transporter;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
// Host is required — defaulting to "localhost" silently hid env-var
|
|
25
|
+
// misconfigurations (SMTP_HOST unset) until the SMTP connection
|
|
26
|
+
// timed out against a nonexistent local server. Fail at
|
|
27
|
+
// construction with an actionable message instead.
|
|
28
|
+
if (config.host !== undefined && typeof config.host !== "string") {
|
|
29
|
+
throw new RoverError("MAIL_PROVIDER_CONFIG", `SMTP host must be a string, got ${typeof config.host}`, { hint: "Set config.host to your SMTP server hostname." });
|
|
30
|
+
}
|
|
31
|
+
if (typeof config.host !== "string" || config.host.length === 0) {
|
|
32
|
+
throw new RoverError("MAIL_PROVIDER_CONFIG", "SMTP host is required", {
|
|
33
|
+
hint: "Set config.host (e.g. process.env.SMTP_HOST). Use the fake / log transports for local development.",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const host = config.host;
|
|
37
|
+
const port = typeof config.port === "number" ? config.port : 587;
|
|
38
|
+
const secure = typeof config.secure === "boolean" ? config.secure : false;
|
|
39
|
+
const user = typeof config.user === "string" ? config.user : undefined;
|
|
40
|
+
const pass = typeof config.pass === "string" ? config.pass : undefined;
|
|
41
|
+
const requireTLS = typeof config.requireTLS === "boolean" ? config.requireTLS : undefined;
|
|
42
|
+
// Partial auth config (only user OR only pass) is almost always a typo —
|
|
43
|
+
// fail fast rather than connect anonymously and let the server reject.
|
|
44
|
+
if ((user && !pass) || (!user && pass)) {
|
|
45
|
+
throw new RoverError("MAIL_PROVIDER_CONFIG", "SMTP auth requires both `user` and `pass` or neither", {
|
|
46
|
+
hint: "Check your env vars — one half of the credential pair is missing.",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Allow DI for tests: if the config carries a pre-built transporter,
|
|
50
|
+
// use it instead of nodemailer.createTransport.
|
|
51
|
+
const injected = config._transporter;
|
|
52
|
+
if (injected && typeof injected === "object" && "sendMail" in injected) {
|
|
53
|
+
this.#transporter = injected;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.#transporter = nodemailer.createTransport({
|
|
57
|
+
host,
|
|
58
|
+
port,
|
|
59
|
+
secure,
|
|
60
|
+
requireTLS,
|
|
61
|
+
auth: user && pass ? { user, pass } : undefined,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async send(message) {
|
|
66
|
+
if (message.to.length === 0 &&
|
|
67
|
+
message.cc.length === 0 &&
|
|
68
|
+
message.bcc.length === 0) {
|
|
69
|
+
throw new RoverError("MAIL_PROVIDER_CONFIG", "Mail message has no recipients", { hint: "Set at least one `to`, `cc`, or `bcc` before sending." });
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const info = await this.#transporter.sendMail({
|
|
73
|
+
from: message.from,
|
|
74
|
+
to: message.to,
|
|
75
|
+
cc: message.cc.length ? message.cc : undefined,
|
|
76
|
+
bcc: message.bcc.length ? message.bcc : undefined,
|
|
77
|
+
replyTo: message.replyTo,
|
|
78
|
+
subject: message.subject,
|
|
79
|
+
html: message.html,
|
|
80
|
+
text: message.text,
|
|
81
|
+
headers: Object.keys(message.headers).length
|
|
82
|
+
? message.headers
|
|
83
|
+
: undefined,
|
|
84
|
+
attachments: message.attachments.length
|
|
85
|
+
? message.attachments.map((att) => ({
|
|
86
|
+
filename: att.filename,
|
|
87
|
+
content: att.content,
|
|
88
|
+
contentType: att.contentType,
|
|
89
|
+
}))
|
|
90
|
+
: undefined,
|
|
91
|
+
});
|
|
92
|
+
if (info.messageId)
|
|
93
|
+
return { providerId: info.messageId };
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
throw wrapSmtpError(err);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Normalise nodemailer / socket errors into the uniform `MAIL_PROVIDER_ERROR`
|
|
103
|
+
* shape used by the rest of the library. Preserves the `code` field (errno)
|
|
104
|
+
* in `context.networkCode` so `isRetryableError` can classify transient
|
|
105
|
+
* network failures without losing the root cause.
|
|
106
|
+
*/
|
|
107
|
+
function wrapSmtpError(err) {
|
|
108
|
+
if (err instanceof RoverError)
|
|
109
|
+
return err;
|
|
110
|
+
const anyErr = err;
|
|
111
|
+
const status = typeof anyErr.responseCode === "number" ? anyErr.responseCode : 0;
|
|
112
|
+
const ctx = {
|
|
113
|
+
provider: "smtp",
|
|
114
|
+
upstreamStatus: String(status),
|
|
115
|
+
providerMessage: anyErr.message ?? "unknown",
|
|
116
|
+
};
|
|
117
|
+
if (typeof anyErr.code === "string") {
|
|
118
|
+
ctx.networkCode = anyErr.code;
|
|
119
|
+
}
|
|
120
|
+
return new RoverError("MAIL_PROVIDER_ERROR", `SMTP failed: ${anyErr.message ?? "unknown"}`, {
|
|
121
|
+
hint: "Inspect `context.networkCode` (ECONNRESET/ETIMEDOUT/...) or `context.upstreamStatus` (SMTP response code) to decide retry eligibility.",
|
|
122
|
+
context: ctx,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Log transport — logs emails to console (development).
|
|
127
|
+
*/
|
|
128
|
+
export class LogTransport {
|
|
129
|
+
async send(message) {
|
|
130
|
+
console.log(`[MAIL] To: ${message.to.join(", ")} | Subject: ${message.subject}`);
|
|
131
|
+
if (message.text)
|
|
132
|
+
console.log(` Body: ${message.text.slice(0, 200)}`);
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const transportFactories = {
|
|
137
|
+
smtp: (config) => new SmtpTransport(config),
|
|
138
|
+
log: () => new LogTransport(),
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Register a custom transport factory globally.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* registerTransport('mailgun', (config) => new MailgunTransport(config))
|
|
145
|
+
* // Now config/mail.ts can reference `transport: 'mailgun'`
|
|
146
|
+
*/
|
|
147
|
+
export function registerTransport(name, factory) {
|
|
148
|
+
transportFactories[name] = factory;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Mail manager — send emails via configured transport.
|
|
152
|
+
*/
|
|
153
|
+
export class Mail {
|
|
154
|
+
#transports = new Map();
|
|
155
|
+
#defaultTransport;
|
|
156
|
+
#defaultFrom;
|
|
157
|
+
#fakeSnapshot = null;
|
|
158
|
+
#queue = null;
|
|
159
|
+
#queueName;
|
|
160
|
+
#queueMaxAttempts;
|
|
161
|
+
#globalRetry;
|
|
162
|
+
#transportRetry = new Map();
|
|
163
|
+
#hooks;
|
|
164
|
+
#emitter;
|
|
165
|
+
constructor(config, options) {
|
|
166
|
+
this.#defaultTransport = config.default;
|
|
167
|
+
this.#defaultFrom = config.from;
|
|
168
|
+
// Bay uses a single `name` for both `register(name, handler)` and
|
|
169
|
+
// `dispatch(name, payload)`. Default to the canonical mail job name.
|
|
170
|
+
this.#queueName = config.queue?.name ?? MAIL_JOB_NAME;
|
|
171
|
+
this.#queueMaxAttempts = config.queue?.maxAttempts ?? 3;
|
|
172
|
+
this.#globalRetry = config.retry;
|
|
173
|
+
this.#hooks = options?.hooks ?? {};
|
|
174
|
+
this.#emitter = options?.emitter ?? null;
|
|
175
|
+
if (config.viewsRoot !== undefined) {
|
|
176
|
+
setViewsRoot(config.viewsRoot);
|
|
177
|
+
}
|
|
178
|
+
for (const [name, transportConfig] of Object.entries(config.transports)) {
|
|
179
|
+
const factory = transportFactories[transportConfig.transport];
|
|
180
|
+
if (!factory) {
|
|
181
|
+
throw new RoverError("MAIL_UNKNOWN_TRANSPORT", `Unknown mail transport type '${transportConfig.transport}' (configured under name '${name}')`, {
|
|
182
|
+
hint: "Register the transport with registerTransport() before constructing Mail, or fix the typo in config.mail.transports[*].transport.",
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
this.#transports.set(name, factory(transportConfig));
|
|
186
|
+
if (transportConfig.retry) {
|
|
187
|
+
this.#transportRetry.set(name, transportConfig.retry);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (options?.queue) {
|
|
191
|
+
this.#queue = options.queue;
|
|
192
|
+
this.#queue.register(this.#queueName, new MailJobHandler(this));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async send(arg, transport) {
|
|
196
|
+
const transportName = transport ?? this.#defaultTransport;
|
|
197
|
+
// Validate transport up-front before running any callback / prepare() side effects.
|
|
198
|
+
if (!this.#transports.has(transportName)) {
|
|
199
|
+
throw new Error(`Mail transport '${transportName}' not configured`);
|
|
200
|
+
}
|
|
201
|
+
const message = await this.#buildMessage(arg);
|
|
202
|
+
await this.dispatchMessage(message, transportName);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Enqueue a send onto the Bay queue. Returns the job id. Throws
|
|
206
|
+
* `MAIL_QUEUE_REQUIRED` if no `QueueManager` was wired through the
|
|
207
|
+
* constructor options.
|
|
208
|
+
*/
|
|
209
|
+
async sendLater(arg, options) {
|
|
210
|
+
if (this.#queue === null) {
|
|
211
|
+
throw new RoverError("MAIL_QUEUE_REQUIRED", "mail.sendLater() requires @c9up/bay QueueManager", {
|
|
212
|
+
hint: "Register @c9up/bay and pass the QueueManager to Mail via RoverProvider, or use mail.send() for synchronous delivery.",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const message = await this.#buildMessage(arg);
|
|
216
|
+
const queueName = options?.queue ?? this.#queueName;
|
|
217
|
+
return this.#queue.dispatch(queueName, { message, transport: options?.transport }, { maxAttempts: this.#queueMaxAttempts });
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Shared transport-resolve-then-send helper used by `send()` and `MailJobHandler`.
|
|
221
|
+
* Applies in-process retry with exponential backoff per `RetryConfig` resolution
|
|
222
|
+
* (per-transport > global > library default). Fires `onSent` / `onFailed` hooks.
|
|
223
|
+
*
|
|
224
|
+
* `overrideRetry` (optional) wins over config-level retry; `MailJobHandler` passes
|
|
225
|
+
* `{ maxAttempts: 1 }` so queue-level and sync-level retries don't compound.
|
|
226
|
+
*/
|
|
227
|
+
async dispatchMessage(message, transportName, overrideRetry) {
|
|
228
|
+
// Defense-in-depth: queue payloads bypass `#buildMessage`, so a
|
|
229
|
+
// malformed message deserialised from storage would otherwise reach
|
|
230
|
+
// the transport with the cryptic provider error A2 was meant to
|
|
231
|
+
// eliminate. Cheap re-validation on every dispatch keeps the
|
|
232
|
+
// failure mode uniform across send() and queue dequeue.
|
|
233
|
+
validateMailMessage(message);
|
|
234
|
+
const name = transportName ?? this.#defaultTransport;
|
|
235
|
+
const t = this.#transports.get(name);
|
|
236
|
+
if (!t)
|
|
237
|
+
throw new Error(`Mail transport '${name}' not configured`);
|
|
238
|
+
const retry = overrideRetry
|
|
239
|
+
? resolveRetryConfig(undefined, overrideRetry)
|
|
240
|
+
: resolveRetryConfig(this.#globalRetry, this.#transportRetry.get(name));
|
|
241
|
+
const generatedId = randomBytes(16).toString("hex");
|
|
242
|
+
let lastError;
|
|
243
|
+
for (let attempt = 1; attempt <= retry.maxAttempts; attempt += 1) {
|
|
244
|
+
let sendResult;
|
|
245
|
+
try {
|
|
246
|
+
sendResult = await t.send(message);
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
lastError = err;
|
|
250
|
+
const retryable = isRetryableError(err);
|
|
251
|
+
if (!retryable || attempt === retry.maxAttempts) {
|
|
252
|
+
const annotated = this.#withAttempts(err, attempt);
|
|
253
|
+
this.#fireFailed({
|
|
254
|
+
messageId: generatedId,
|
|
255
|
+
to: message.to.slice(),
|
|
256
|
+
cc: message.cc.slice(),
|
|
257
|
+
bcc: message.bcc.slice(),
|
|
258
|
+
transportName: name,
|
|
259
|
+
error: errorDescriptor(annotated, attempt),
|
|
260
|
+
timestamp: Date.now(),
|
|
261
|
+
});
|
|
262
|
+
throw annotated;
|
|
263
|
+
}
|
|
264
|
+
const delay = computeBackoffMs(attempt, retry, err);
|
|
265
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
// Success path lives outside the try/catch so a throw inside the
|
|
269
|
+
// success hook cannot be mistaken for a transport failure.
|
|
270
|
+
const providerIdRaw = sendResult &&
|
|
271
|
+
typeof sendResult === "object" &&
|
|
272
|
+
"providerId" in sendResult
|
|
273
|
+
? sendResult.providerId
|
|
274
|
+
: undefined;
|
|
275
|
+
// `??` would accept empty-string providerId; explicit truthy check
|
|
276
|
+
// so a provider returning `{ providerId: "" }` falls back to the
|
|
277
|
+
// internally generated correlation id.
|
|
278
|
+
const providerId = providerIdRaw && providerIdRaw.length > 0 ? providerIdRaw : undefined;
|
|
279
|
+
this.#fireSent({
|
|
280
|
+
messageId: providerId ?? generatedId,
|
|
281
|
+
to: message.to.slice(),
|
|
282
|
+
cc: message.cc.slice(),
|
|
283
|
+
bcc: message.bcc.slice(),
|
|
284
|
+
transportName: name,
|
|
285
|
+
timestamp: Date.now(),
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// Unreachable — the loop always returns or throws — but TS wants a throw.
|
|
290
|
+
throw lastError;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Return a shallow clone of `err` with `context.attempts` annotated. We
|
|
294
|
+
* avoid mutating the original error so outer retry layers / shared error
|
|
295
|
+
* references don't see their attempt counter overwritten.
|
|
296
|
+
*/
|
|
297
|
+
#withAttempts(err, attempts) {
|
|
298
|
+
if (!(err instanceof RoverError))
|
|
299
|
+
return err;
|
|
300
|
+
const clone = new RoverError(err.code, err.message, {
|
|
301
|
+
hint: err.hint,
|
|
302
|
+
sourceFile: err.sourceFile,
|
|
303
|
+
sourceLine: err.sourceLine,
|
|
304
|
+
docsUrl: err.docsUrl,
|
|
305
|
+
pipelineStage: err.pipelineStage,
|
|
306
|
+
context: { ...err.context, attempts: String(attempts) },
|
|
307
|
+
});
|
|
308
|
+
if (err.stack)
|
|
309
|
+
clone.stack = err.stack;
|
|
310
|
+
return clone;
|
|
311
|
+
}
|
|
312
|
+
#fireSent(event) {
|
|
313
|
+
// Hooks are in user-land and may throw; their failure must not poison
|
|
314
|
+
// delivery outcome. Emitter errors are already defensively swallowed.
|
|
315
|
+
try {
|
|
316
|
+
this.#hooks.onSent?.(event);
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
process.stderr.write(`[rover] onSent hook threw: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
320
|
+
}
|
|
321
|
+
if (this.#emitter) {
|
|
322
|
+
try {
|
|
323
|
+
this.#emitter.emit("mail.sent", event);
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// Event bus failure ≠ mail delivery failure — swallow.
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
#fireFailed(event) {
|
|
331
|
+
try {
|
|
332
|
+
this.#hooks.onFailed?.(event);
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
process.stderr.write(`[rover] onFailed hook threw: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
336
|
+
}
|
|
337
|
+
if (this.#emitter) {
|
|
338
|
+
try {
|
|
339
|
+
this.#emitter.emit("mail.failed", event);
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
// Event bus failure ≠ mail delivery failure — swallow.
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
async #buildMessage(arg) {
|
|
347
|
+
let result;
|
|
348
|
+
if (arg instanceof BaseMail) {
|
|
349
|
+
const built = await arg.build();
|
|
350
|
+
result = built.from ? built : { ...built, from: this.#defaultFrom };
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
const builder = new MessageBuilder();
|
|
354
|
+
builder.from(this.#defaultFrom);
|
|
355
|
+
arg(builder);
|
|
356
|
+
result = await builder.build();
|
|
357
|
+
}
|
|
358
|
+
validateMailMessage(result);
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
/** Get a specific transport. */
|
|
362
|
+
use(name) {
|
|
363
|
+
const t = this.#transports.get(name);
|
|
364
|
+
if (!t)
|
|
365
|
+
throw new Error(`Mail transport '${name}' not configured`);
|
|
366
|
+
return t;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Swap the default transport with a `FakeMail` that captures every send.
|
|
370
|
+
* Call `restore()` to re-install the original. Throws if a fake is already
|
|
371
|
+
* active — nested fakes always indicate a forgotten `restore()`.
|
|
372
|
+
*/
|
|
373
|
+
fake() {
|
|
374
|
+
if (this.#fakeSnapshot !== null) {
|
|
375
|
+
throw new Error("Mail.fake() already active — call restore() first");
|
|
376
|
+
}
|
|
377
|
+
const transportName = this.#defaultTransport;
|
|
378
|
+
const original = this.#transports.get(transportName);
|
|
379
|
+
if (!original) {
|
|
380
|
+
throw new Error(`Cannot fake default transport '${transportName}' — not configured`);
|
|
381
|
+
}
|
|
382
|
+
const fake = new FakeMail();
|
|
383
|
+
this.#fakeSnapshot = { transportName, original };
|
|
384
|
+
this.#transports.set(transportName, fake);
|
|
385
|
+
return fake;
|
|
386
|
+
}
|
|
387
|
+
/** Undo the swap installed by `fake()`. No-op if no fake is active. */
|
|
388
|
+
restore() {
|
|
389
|
+
if (this.#fakeSnapshot === null)
|
|
390
|
+
return;
|
|
391
|
+
const { transportName, original } = this.#fakeSnapshot;
|
|
392
|
+
this.#transports.set(transportName, original);
|
|
393
|
+
this.#fakeSnapshot = null;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Reject empty `from` and empty recipients before any transport is reached —
|
|
398
|
+
* keeps the failure mode uniform across SMTP / Mailgun / SendGrid / SES /
|
|
399
|
+
* Resend / log instead of relying on each transport to surface a (possibly
|
|
400
|
+
* cryptic) "no recipients" provider error.
|
|
401
|
+
*/
|
|
402
|
+
function validateMailMessage(message) {
|
|
403
|
+
// `MailMessage.from` is typed `string` but config-loader paths
|
|
404
|
+
// (`app.config.get<MailConfig>(...)`) cast at runtime — a missing key
|
|
405
|
+
// can yield `undefined` despite the type. Whitespace-only is also
|
|
406
|
+
// invalid per RFC 5321 reverse-path semantics.
|
|
407
|
+
if (typeof message.from !== "string" || message.from.trim() === "") {
|
|
408
|
+
throw new RoverError("MAIL_INVALID_MESSAGE", "Mail message has no `from` address", {
|
|
409
|
+
hint: "Set `config.from`, an instance `from`, or call `message.from(...)` in the builder.",
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
// Defense-in-depth on each array: `MailJob.validatePayload` only requires
|
|
413
|
+
// `to` to be an array (cc/bcc are optional at the queue boundary), so a
|
|
414
|
+
// deserialised job payload may reach here with `cc`/`bcc` as `undefined`.
|
|
415
|
+
// `.some(...)` on `undefined` throws `TypeError` instead of the
|
|
416
|
+
// structured `MAIL_INVALID_MESSAGE` this validator is supposed to surface.
|
|
417
|
+
const hasRecipient = (Array.isArray(message.to) && message.to.some(isNonEmptyAddress)) ||
|
|
418
|
+
(Array.isArray(message.cc) && message.cc.some(isNonEmptyAddress)) ||
|
|
419
|
+
(Array.isArray(message.bcc) && message.bcc.some(isNonEmptyAddress));
|
|
420
|
+
if (!hasRecipient) {
|
|
421
|
+
throw new RoverError("MAIL_INVALID_MESSAGE", "Mail message has no recipients", {
|
|
422
|
+
hint: "Call `message.to(...)`, `cc(...)`, or `bcc(...)` with a non-empty address before sending.",
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function isNonEmptyAddress(addr) {
|
|
427
|
+
return typeof addr === "string" && addr.trim() !== "";
|
|
428
|
+
}
|
|
429
|
+
function errorDescriptor(err, attempts) {
|
|
430
|
+
if (err instanceof RoverError) {
|
|
431
|
+
const statusStr = err.context.upstreamStatus;
|
|
432
|
+
const upstream = Number(statusStr);
|
|
433
|
+
return {
|
|
434
|
+
code: err.code,
|
|
435
|
+
message: err.message,
|
|
436
|
+
upstreamStatus: Number.isFinite(upstream) ? upstream : undefined,
|
|
437
|
+
upstreamStatusRaw: statusStr,
|
|
438
|
+
attempts,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
if (err instanceof Error) {
|
|
442
|
+
const errnoCode = err.code;
|
|
443
|
+
return {
|
|
444
|
+
code: typeof errnoCode === "string" ? errnoCode : "UNKNOWN",
|
|
445
|
+
message: err.message,
|
|
446
|
+
attempts,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return { code: "UNKNOWN", message: String(err), attempts };
|
|
450
|
+
}
|
|
451
|
+
//# sourceMappingURL=Mail.js.map
|
package/dist/Mail.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mail.js","sourceRoot":"","sources":["../src/Mail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface MailMessage {
|
|
2
|
+
from: string;
|
|
3
|
+
to: string[];
|
|
4
|
+
cc: string[];
|
|
5
|
+
bcc: string[];
|
|
6
|
+
replyTo?: string;
|
|
7
|
+
subject: string;
|
|
8
|
+
html?: string;
|
|
9
|
+
text?: string;
|
|
10
|
+
attachments: MailAttachment[];
|
|
11
|
+
headers: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export interface MailAttachment {
|
|
14
|
+
filename: string;
|
|
15
|
+
content: Buffer | string;
|
|
16
|
+
contentType?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class MessageBuilder {
|
|
19
|
+
#private;
|
|
20
|
+
from(address: string): this;
|
|
21
|
+
to(address: string): this;
|
|
22
|
+
cc(address: string): this;
|
|
23
|
+
bcc(address: string): this;
|
|
24
|
+
replyTo(address: string): this;
|
|
25
|
+
subject(text: string): this;
|
|
26
|
+
html(content: string): this;
|
|
27
|
+
text(content: string): this;
|
|
28
|
+
attach(filename: string, content: Buffer | string, contentType?: string): this;
|
|
29
|
+
header(key: string, value: string): this;
|
|
30
|
+
/**
|
|
31
|
+
* Queue an HTML template render. The render happens lazily at `build()` time
|
|
32
|
+
* so the fluent chain stays synchronous; `build()` is async and awaits the
|
|
33
|
+
* render before returning the finalised `MailMessage`.
|
|
34
|
+
*/
|
|
35
|
+
htmlView(viewPath: string, data?: Record<string, unknown>): this;
|
|
36
|
+
build(): Promise<MailMessage>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=MessageBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageBuilder.d.ts","sourceRoot":"","sources":["../src/MessageBuilder.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,cAAc;;IAY1B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIzB,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIzB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI1B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,MAAM,CACL,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GAClB,IAAI;IAKP,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKxC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAK1D,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;CAUnC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { renderFile as renderTemplateFile } from "./templating/SimpleTemplate.js";
|
|
2
|
+
export class MessageBuilder {
|
|
3
|
+
#msg = {
|
|
4
|
+
from: "",
|
|
5
|
+
to: [],
|
|
6
|
+
cc: [],
|
|
7
|
+
bcc: [],
|
|
8
|
+
subject: "",
|
|
9
|
+
attachments: [],
|
|
10
|
+
headers: {},
|
|
11
|
+
};
|
|
12
|
+
#pendingView = null;
|
|
13
|
+
from(address) {
|
|
14
|
+
this.#msg.from = address;
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
to(address) {
|
|
18
|
+
this.#msg.to.push(address);
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
cc(address) {
|
|
22
|
+
this.#msg.cc.push(address);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
bcc(address) {
|
|
26
|
+
this.#msg.bcc.push(address);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
replyTo(address) {
|
|
30
|
+
this.#msg.replyTo = address;
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
subject(text) {
|
|
34
|
+
this.#msg.subject = text;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
html(content) {
|
|
38
|
+
this.#msg.html = content;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
text(content) {
|
|
42
|
+
this.#msg.text = content;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
attach(filename, content, contentType) {
|
|
46
|
+
this.#msg.attachments.push({ filename, content, contentType });
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
header(key, value) {
|
|
50
|
+
this.#msg.headers[key] = value;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Queue an HTML template render. The render happens lazily at `build()` time
|
|
55
|
+
* so the fluent chain stays synchronous; `build()` is async and awaits the
|
|
56
|
+
* render before returning the finalised `MailMessage`.
|
|
57
|
+
*/
|
|
58
|
+
htmlView(viewPath, data) {
|
|
59
|
+
this.#pendingView = { path: viewPath, data: data ?? {} };
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
async build() {
|
|
63
|
+
if (this.#pendingView !== null) {
|
|
64
|
+
this.#msg.html = await renderTemplateFile(this.#pendingView.path, this.#pendingView.data);
|
|
65
|
+
this.#pendingView = null;
|
|
66
|
+
}
|
|
67
|
+
return this.#msg;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=MessageBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageBuilder.js","sourceRoot":"","sources":["../src/MessageBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAqBlF,MAAM,OAAO,cAAc;IAC1B,IAAI,GAAgB;QACnB,IAAI,EAAE,EAAE;QACR,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,GAAG,EAAE,EAAE;QACP,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,EAAE;KACX,CAAC;IACF,YAAY,GAA2D,IAAI,CAAC;IAE5E,IAAI,CAAC,OAAe;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,EAAE,CAAC,OAAe;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,EAAE,CAAC,OAAe;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,GAAG,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,CAAC,OAAe;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAC5B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,CAAC,IAAY;QACnB,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,CAAC,OAAe;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,CAAC,OAAe;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,CACL,QAAgB,EAChB,OAAwB,EACxB,WAAoB;QAEpB,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,CAAC,GAAW,EAAE,KAAa;QAChC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,QAAgB,EAAE,IAA8B;QACxD,IAAI,CAAC,YAAY,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,KAAK,CAAC,KAAK;QACV,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,kBAAkB,CACxC,IAAI,CAAC,YAAY,CAAC,IAAI,EACtB,IAAI,CAAC,YAAY,CAAC,IAAI,CACtB,CAAC;YACF,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;CACD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rover's own structured error — keeps the package framework-agnostic (no
|
|
3
|
+
* dependency on `@c9up/ream`'s `ReamError`). Mirrors the error shape Rover
|
|
4
|
+
* carries through its transports and retry logic.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RoverError extends Error {
|
|
7
|
+
/** Error code (e.g. "ROVER_SMTP_ERROR"). */
|
|
8
|
+
readonly code: string;
|
|
9
|
+
/** Additional context key-value pairs. */
|
|
10
|
+
readonly context: Record<string, string>;
|
|
11
|
+
/** Actionable hint for the developer. */
|
|
12
|
+
readonly hint?: string;
|
|
13
|
+
/** Source file where the error originated. */
|
|
14
|
+
readonly sourceFile?: string;
|
|
15
|
+
/** Line number in the source file. */
|
|
16
|
+
readonly sourceLine?: number;
|
|
17
|
+
/** URL to the error documentation page. */
|
|
18
|
+
readonly docsUrl?: string;
|
|
19
|
+
/** Pipeline stage where the error occurred (if applicable). */
|
|
20
|
+
readonly pipelineStage?: string;
|
|
21
|
+
constructor(code: string, message: string, options?: {
|
|
22
|
+
context?: Record<string, string>;
|
|
23
|
+
hint?: string;
|
|
24
|
+
sourceFile?: string;
|
|
25
|
+
sourceLine?: number;
|
|
26
|
+
docsUrl?: string;
|
|
27
|
+
pipelineStage?: string;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=RoverError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoverError.d.ts","sourceRoot":"","sources":["../src/RoverError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACpC,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,sCAAsC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;gBAG/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACvB;CAYF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rover's own structured error — keeps the package framework-agnostic (no
|
|
3
|
+
* dependency on `@c9up/ream`'s `ReamError`). Mirrors the error shape Rover
|
|
4
|
+
* carries through its transports and retry logic.
|
|
5
|
+
*/
|
|
6
|
+
export class RoverError extends Error {
|
|
7
|
+
/** Error code (e.g. "ROVER_SMTP_ERROR"). */
|
|
8
|
+
code;
|
|
9
|
+
/** Additional context key-value pairs. */
|
|
10
|
+
context;
|
|
11
|
+
/** Actionable hint for the developer. */
|
|
12
|
+
hint;
|
|
13
|
+
/** Source file where the error originated. */
|
|
14
|
+
sourceFile;
|
|
15
|
+
/** Line number in the source file. */
|
|
16
|
+
sourceLine;
|
|
17
|
+
/** URL to the error documentation page. */
|
|
18
|
+
docsUrl;
|
|
19
|
+
/** Pipeline stage where the error occurred (if applicable). */
|
|
20
|
+
pipelineStage;
|
|
21
|
+
constructor(code, message, options) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "RoverError";
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.context = options?.context ?? {};
|
|
26
|
+
this.hint = options?.hint;
|
|
27
|
+
this.sourceFile = options?.sourceFile;
|
|
28
|
+
this.sourceLine = options?.sourceLine;
|
|
29
|
+
this.docsUrl = options?.docsUrl;
|
|
30
|
+
this.pipelineStage = options?.pipelineStage;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=RoverError.js.map
|