@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoverError.js","sourceRoot":"","sources":["../src/RoverError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,KAAK;IACpC,4CAA4C;IACnC,IAAI,CAAS;IACtB,0CAA0C;IACjC,OAAO,CAAyB;IACzC,yCAAyC;IAChC,IAAI,CAAU;IACvB,8CAA8C;IACrC,UAAU,CAAU;IAC7B,sCAAsC;IAC7B,UAAU,CAAU;IAC7B,2CAA2C;IAClC,OAAO,CAAU;IAC1B,+DAA+D;IACtD,aAAa,CAAU;IAEhC,YACC,IAAY,EACZ,OAAe,EACf,OAOC;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,CAAC;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC;QAChC,IAAI,CAAC,aAAa,GAAG,OAAO,EAAE,aAAa,CAAC;IAC7C,CAAC;CACD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duck-typed slice of the host's IoC container — rover does NOT import
|
|
3
|
+
* `@c9up/ream` so it stays publishable as a standalone package.
|
|
4
|
+
*/
|
|
5
|
+
interface RoverContainer {
|
|
6
|
+
singleton(token: unknown, factory: () => unknown): void;
|
|
7
|
+
resolve<T = unknown>(token: unknown): T;
|
|
8
|
+
}
|
|
9
|
+
interface RoverConfigStore {
|
|
10
|
+
get<T = unknown>(key: string): T | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface RoverAppContext {
|
|
13
|
+
container: RoverContainer;
|
|
14
|
+
config: RoverConfigStore;
|
|
15
|
+
}
|
|
16
|
+
export default class RoverProvider {
|
|
17
|
+
protected app: RoverAppContext;
|
|
18
|
+
constructor(app: RoverAppContext);
|
|
19
|
+
register(): void;
|
|
20
|
+
boot(): Promise<void>;
|
|
21
|
+
shutdown(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=RoverProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoverProvider.d.ts","sourceRoot":"","sources":["../src/RoverProvider.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,UAAU,cAAc;IACvB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IACxD,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC;CACxC;AACD,UAAU,gBAAgB;IACzB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AACD,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,CAAC,OAAO,OAAO,aAAa;IACrB,SAAS,CAAC,GAAG,EAAE,eAAe;gBAApB,GAAG,EAAE,eAAe;IAE1C,QAAQ;IA0BF,IAAI;IAOJ,QAAQ;CACd"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Mail } from "./Mail.js";
|
|
2
|
+
import { setMail } from "./services/main.js";
|
|
3
|
+
export default class RoverProvider {
|
|
4
|
+
app;
|
|
5
|
+
constructor(app) {
|
|
6
|
+
this.app = app;
|
|
7
|
+
}
|
|
8
|
+
register() {
|
|
9
|
+
this.app.container.singleton(Mail, () => {
|
|
10
|
+
const config = this.app.config.get("mail");
|
|
11
|
+
return new Mail(config ?? {
|
|
12
|
+
default: "log",
|
|
13
|
+
from: "noreply@localhost",
|
|
14
|
+
transports: { log: { transport: "log" } },
|
|
15
|
+
}, {
|
|
16
|
+
// Optional-peer wiring: if `@c9up/bay` is installed and its
|
|
17
|
+
// `QueueManager` is registered in the container, Mail gets
|
|
18
|
+
// queue support for `sendLater()`. If not, `sendLater()`
|
|
19
|
+
// throws `MAIL_QUEUE_REQUIRED` at call time (by design).
|
|
20
|
+
queue: tryResolve(this.app, "QueueManager"),
|
|
21
|
+
// Same pattern for the event bus `Emitter` — enables `mail.sent`
|
|
22
|
+
// / `mail.failed` emission when available.
|
|
23
|
+
emitter: tryResolve(this.app, "Emitter"),
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
this.app.container.singleton("mail", () => {
|
|
27
|
+
return this.app.container.resolve(Mail);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async boot() {
|
|
31
|
+
// Populate the `@c9up/rover/services/main` singleton with the
|
|
32
|
+
// container-resolved Mail instance so apps can
|
|
33
|
+
// `import mail from '@c9up/rover/services/main'` from anywhere.
|
|
34
|
+
setMail(this.app.container.resolve(Mail));
|
|
35
|
+
}
|
|
36
|
+
async shutdown() { }
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a token from the container without throwing when it's not
|
|
40
|
+
* registered. Rover never hard-depends on Bay or the event bus — both wire-points
|
|
41
|
+
* are purely opt-in.
|
|
42
|
+
*/
|
|
43
|
+
function tryResolve(app, token) {
|
|
44
|
+
try {
|
|
45
|
+
return app.container.resolve(token);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=RoverProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoverProvider.js","sourceRoot":"","sources":["../src/RoverProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAkB7C,MAAM,CAAC,OAAO,OAAO,aAAa;IACX;IAAtB,YAAsB,GAAoB;QAApB,QAAG,GAAH,GAAG,CAAiB;IAAG,CAAC;IAE9C,QAAQ;QACP,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAa,MAAM,CAAC,CAAC;YACvD,OAAO,IAAI,IAAI,CACd,MAAM,IAAI;gBACT,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,mBAAmB;gBACzB,UAAU,EAAE,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;aACzC,EACD;gBACC,4DAA4D;gBAC5D,2DAA2D;gBAC3D,yDAAyD;gBACzD,yDAAyD;gBACzD,KAAK,EAAE,UAAU,CAAe,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC;gBACzD,iEAAiE;gBACjE,2CAA2C;gBAC3C,OAAO,EAAE,UAAU,CAAc,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC;aACrD,CACD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE;YACzC,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAO,IAAI,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI;QACT,8DAA8D;QAC9D,+CAA+C;QAC/C,gEAAgE;QAChE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAO,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,QAAQ,KAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAI,GAAoB,EAAE,KAAa;IACzD,IAAI,CAAC;QACJ,OAAO,GAAG,CAAC,SAAS,CAAC,OAAO,CAAI,KAAK,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAE3D;AAED,YAAY,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,MAAkB;IAC9C,OAAO,MAAM,CAAC;AACf,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { MailAddress } from "./BaseMail.js";
|
|
2
|
+
export { BaseMail } from "./BaseMail.js";
|
|
3
|
+
export { defineConfig } from "./config.js";
|
|
4
|
+
export { RoverError } from "./RoverError.js";
|
|
5
|
+
export type { EmitterLike, MailAttachment, MailConfig, MailFailedEvent, MailHooks, MailMessage, MailSendOutcome, MailSendResult, MailSentEvent, MailTransport, MailTransportFactory, } from "./Mail.js";
|
|
6
|
+
export { LogTransport, Mail, MessageBuilder, registerTransport, SmtpTransport, } from "./Mail.js";
|
|
7
|
+
export { default as RoverProvider } from "./RoverProvider.js";
|
|
8
|
+
export { DEFAULT_RETRY_CONFIG, isRetryableError, type RetryConfig, } from "./retry.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACX,WAAW,EACX,cAAc,EACd,UAAU,EACV,eAAe,EACf,SAAS,EACT,WAAW,EACX,eAAe,EACf,cAAc,EACd,aAAa,EACb,aAAa,EACb,oBAAoB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EACN,YAAY,EACZ,IAAI,EACJ,cAAc,EACd,iBAAiB,EACjB,aAAa,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACN,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,WAAW,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { BaseMail } from "./BaseMail.js";
|
|
2
|
+
export { defineConfig } from "./config.js";
|
|
3
|
+
export { RoverError } from "./RoverError.js";
|
|
4
|
+
export { LogTransport, Mail, MessageBuilder, registerTransport, SmtpTransport, } from "./Mail.js";
|
|
5
|
+
export { default as RoverProvider } from "./RoverProvider.js";
|
|
6
|
+
export { DEFAULT_RETRY_CONFIG, isRetryableError, } from "./retry.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAc7C,OAAO,EACN,YAAY,EACZ,IAAI,EACJ,cAAc,EACd,iBAAiB,EACjB,aAAa,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACN,oBAAoB,EACpB,gBAAgB,GAEhB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MailMessage } from "../Mail.js";
|
|
2
|
+
export declare const MAIL_JOB_NAME = "mail.send";
|
|
3
|
+
export interface MailJobPayload {
|
|
4
|
+
message: MailMessage;
|
|
5
|
+
transport?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Minimal structural interface for Bay's `QueueManager` — peer-dep friendly,
|
|
9
|
+
* matches `@c9up/bay`'s public API so `new QueueManager(driver)` is assignable.
|
|
10
|
+
*/
|
|
11
|
+
export interface BayQueueLike {
|
|
12
|
+
register(name: string, handler: BayJobHandlerLike): void;
|
|
13
|
+
dispatch(name: string, payload: unknown, options?: {
|
|
14
|
+
maxAttempts?: number;
|
|
15
|
+
}): Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
export interface BayJobHandlerLike {
|
|
18
|
+
handle(payload: unknown): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** Pared-down RetryConfig shape — avoids importing from `../retry.js` into queue/. */
|
|
21
|
+
interface RetryOverride {
|
|
22
|
+
maxAttempts: number;
|
|
23
|
+
baseDelayMs: number;
|
|
24
|
+
factor: number;
|
|
25
|
+
maxDelayMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface MailDispatcher {
|
|
28
|
+
dispatchMessage(message: MailMessage, transport?: string, overrideRetry?: RetryOverride): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Bay job handler for queued mail. Sets `maxAttempts: 1` so the in-process
|
|
32
|
+
* retry loop runs exactly once per job execution — Bay's own `maxAttempts`
|
|
33
|
+
* handles re-dispatch on throw. Prevents sync × queue retry compounding.
|
|
34
|
+
*/
|
|
35
|
+
export declare class MailJobHandler implements BayJobHandlerLike {
|
|
36
|
+
#private;
|
|
37
|
+
constructor(mail: MailDispatcher);
|
|
38
|
+
handle(payload: unknown): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=MailJob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MailJob.d.ts","sourceRoot":"","sources":["../../src/queue/MailJob.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACzD,QAAQ,CACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAChC,OAAO,CAAC,MAAM,CAAC,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,sFAAsF;AACtF,UAAU,aAAa;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC9B,eAAe,CACd,OAAO,EAAE,WAAW,EACpB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,aAAa,GAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,cAAe,YAAW,iBAAiB;;gBAG3C,IAAI,EAAE,cAAc;IAI1B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAY7C"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { RoverError } from "../RoverError.js";
|
|
3
|
+
export const MAIL_JOB_NAME = "mail.send";
|
|
4
|
+
/**
|
|
5
|
+
* Bay job handler for queued mail. Sets `maxAttempts: 1` so the in-process
|
|
6
|
+
* retry loop runs exactly once per job execution — Bay's own `maxAttempts`
|
|
7
|
+
* handles re-dispatch on throw. Prevents sync × queue retry compounding.
|
|
8
|
+
*/
|
|
9
|
+
export class MailJobHandler {
|
|
10
|
+
#mail;
|
|
11
|
+
constructor(mail) {
|
|
12
|
+
this.#mail = mail;
|
|
13
|
+
}
|
|
14
|
+
async handle(payload) {
|
|
15
|
+
const parsed = validatePayload(payload);
|
|
16
|
+
// `{ maxAttempts: 1 }` alone is sufficient — the loop runs exactly once
|
|
17
|
+
// and `computeBackoffMs` is never reached; the other RetryConfig fields
|
|
18
|
+
// resolve to defaults via `resolveRetryConfig` but don't affect control
|
|
19
|
+
// flow. Matches AC 8 wording exactly.
|
|
20
|
+
await this.#mail.dispatchMessage(revive(parsed.message), parsed.transport, {
|
|
21
|
+
maxAttempts: 1,
|
|
22
|
+
baseDelayMs: 0,
|
|
23
|
+
factor: 1,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Narrow an `unknown` payload from the queue driver into a `MailJobPayload`.
|
|
29
|
+
* Throws `MAIL_JOB_MALFORMED` when the shape is unrecognisable so Bay records
|
|
30
|
+
* a clean failure rather than crashing inside `dispatchMessage` with a raw
|
|
31
|
+
* `TypeError`.
|
|
32
|
+
*/
|
|
33
|
+
function validatePayload(payload) {
|
|
34
|
+
if (!payload || typeof payload !== "object") {
|
|
35
|
+
throw new RoverError("MAIL_JOB_MALFORMED", "Mail job payload is missing or not an object", { hint: "Queue driver returned a non-object — check serialisation." });
|
|
36
|
+
}
|
|
37
|
+
const asObj = payload;
|
|
38
|
+
const message = asObj.message;
|
|
39
|
+
if (!message || typeof message !== "object") {
|
|
40
|
+
throw new RoverError("MAIL_JOB_MALFORMED", "Mail job payload.message is missing or not an object", {
|
|
41
|
+
hint: "Payload shape must be { message: MailMessage, transport?: string }.",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const m = message;
|
|
45
|
+
if (typeof m.from !== "string" ||
|
|
46
|
+
!Array.isArray(m.to) ||
|
|
47
|
+
!Array.isArray(m.attachments)) {
|
|
48
|
+
throw new RoverError("MAIL_JOB_MALFORMED", "Mail job payload.message does not match MailMessage shape", {
|
|
49
|
+
hint: "Expected `{ from: string, to: string[], ..., attachments: [] }`.",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const transport = typeof asObj.transport === "string" ? asObj.transport : undefined;
|
|
53
|
+
return { message: message, transport };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Revive Buffer attachments after JSON round-trip. Node serialises `Buffer` as
|
|
57
|
+
* `{ type: "Buffer", data: [...bytes] }`; we reconstruct to real `Buffer`.
|
|
58
|
+
*/
|
|
59
|
+
function revive(message) {
|
|
60
|
+
if (!message.attachments || message.attachments.length === 0)
|
|
61
|
+
return message;
|
|
62
|
+
const attachments = message.attachments.map((att) => {
|
|
63
|
+
if (typeof att.content === "string")
|
|
64
|
+
return att;
|
|
65
|
+
if (Buffer.isBuffer(att.content))
|
|
66
|
+
return att;
|
|
67
|
+
const serialised = att.content;
|
|
68
|
+
if (serialised?.type === "Buffer" && Array.isArray(serialised.data)) {
|
|
69
|
+
return { ...att, content: Buffer.from(serialised.data) };
|
|
70
|
+
}
|
|
71
|
+
return att;
|
|
72
|
+
});
|
|
73
|
+
return { ...message, attachments };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=MailJob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MailJob.js","sourceRoot":"","sources":["../../src/queue/MailJob.ts"],"names":[],"mappings":"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"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface RetryConfig {
|
|
2
|
+
maxAttempts: number;
|
|
3
|
+
baseDelayMs: number;
|
|
4
|
+
factor: number;
|
|
5
|
+
maxDelayMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_RETRY_CONFIG: Required<RetryConfig>;
|
|
8
|
+
/**
|
|
9
|
+
* A failure is retryable when:
|
|
10
|
+
* - it's a `MAIL_PROVIDER_ERROR` with `upstreamStatus` 429 or ≥ 500
|
|
11
|
+
* - or it's a `MAIL_PROVIDER_ERROR` whose `context.networkCode` is a known
|
|
12
|
+
* retryable Node errno (SDK wrappers surface the original errno this way
|
|
13
|
+
* when the HTTP layer never produced a status)
|
|
14
|
+
* - or it's a raw Error with a matching Node networking errno on `.code`
|
|
15
|
+
* 4xx (non-429) is treated as permanent: retrying won't help.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isRetryableError(err: unknown): boolean;
|
|
18
|
+
export declare function computeBackoffMs(attempt: number, config: Required<RetryConfig>, err?: unknown): number;
|
|
19
|
+
export declare function resolveRetryConfig(globalConfig: RetryConfig | undefined, transportConfig: RetryConfig | undefined): Required<RetryConfig>;
|
|
20
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,WAAW,CAKtD,CAAC;AAUF;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA4BtD;AAED,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC7B,GAAG,CAAC,EAAE,OAAO,GACX,MAAM,CAgBR;AAED,wBAAgB,kBAAkB,CACjC,YAAY,EAAE,WAAW,GAAG,SAAS,EACrC,eAAe,EAAE,WAAW,GAAG,SAAS,GACtC,QAAQ,CAAC,WAAW,CAAC,CA8CvB"}
|
package/dist/retry.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { RoverError } from "./RoverError.js";
|
|
2
|
+
export const DEFAULT_RETRY_CONFIG = {
|
|
3
|
+
maxAttempts: 3,
|
|
4
|
+
baseDelayMs: 500,
|
|
5
|
+
factor: 2,
|
|
6
|
+
maxDelayMs: 10_000,
|
|
7
|
+
};
|
|
8
|
+
const RETRYABLE_ERRNO = new Set([
|
|
9
|
+
"ETIMEDOUT",
|
|
10
|
+
"ECONNRESET",
|
|
11
|
+
"ECONNREFUSED",
|
|
12
|
+
"ENOTFOUND",
|
|
13
|
+
"EAI_AGAIN",
|
|
14
|
+
]);
|
|
15
|
+
/**
|
|
16
|
+
* A failure is retryable when:
|
|
17
|
+
* - it's a `MAIL_PROVIDER_ERROR` with `upstreamStatus` 429 or ≥ 500
|
|
18
|
+
* - or it's a `MAIL_PROVIDER_ERROR` whose `context.networkCode` is a known
|
|
19
|
+
* retryable Node errno (SDK wrappers surface the original errno this way
|
|
20
|
+
* when the HTTP layer never produced a status)
|
|
21
|
+
* - or it's a raw Error with a matching Node networking errno on `.code`
|
|
22
|
+
* 4xx (non-429) is treated as permanent: retrying won't help.
|
|
23
|
+
*/
|
|
24
|
+
export function isRetryableError(err) {
|
|
25
|
+
if (err instanceof RoverError && err.code === "MAIL_PROVIDER_ERROR") {
|
|
26
|
+
const statusStr = err.context.upstreamStatus;
|
|
27
|
+
const status = Number(statusStr);
|
|
28
|
+
if (Number.isFinite(status)) {
|
|
29
|
+
if (status === 429)
|
|
30
|
+
return true;
|
|
31
|
+
if (status >= 500 && status < 600)
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
const networkCode = err.context.networkCode;
|
|
35
|
+
if (networkCode && RETRYABLE_ERRNO.has(networkCode))
|
|
36
|
+
return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (err instanceof Error) {
|
|
40
|
+
const code = err.code;
|
|
41
|
+
if (typeof code === "string" && RETRYABLE_ERRNO.has(code))
|
|
42
|
+
return true;
|
|
43
|
+
// Node 18+ `fetch` (undici) wraps the underlying socket error in
|
|
44
|
+
// `cause` and surfaces `TypeError: fetch failed` at the top level —
|
|
45
|
+
// the original errno is on `err.cause.code`, not `err.code`. Without
|
|
46
|
+
// this branch transient ECONNRESET/ENOTFOUND/etc. from raw fetch
|
|
47
|
+
// look indistinguishable from a permanent failure and never retry.
|
|
48
|
+
const cause = err.cause;
|
|
49
|
+
if (cause && typeof cause === "object") {
|
|
50
|
+
const causeCode = cause.code;
|
|
51
|
+
if (typeof causeCode === "string" && RETRYABLE_ERRNO.has(causeCode))
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
export function computeBackoffMs(attempt, config, err) {
|
|
58
|
+
// Honour the provider's Retry-After hint when present (Mailgun/SendGrid/
|
|
59
|
+
// SES/Resend transports capture it into `context.retryAfter`). Value is
|
|
60
|
+
// seconds per HTTP RFC 7231 §7.1.3; we cap at `maxDelayMs` so a malicious
|
|
61
|
+
// or mistaken provider can't force a very-long wait.
|
|
62
|
+
if (err instanceof RoverError && err.code === "MAIL_PROVIDER_ERROR") {
|
|
63
|
+
const hint = err.context.retryAfter;
|
|
64
|
+
if (hint) {
|
|
65
|
+
const seconds = Number(hint);
|
|
66
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
67
|
+
return Math.min(config.maxDelayMs, Math.max(50, seconds * 1000));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const raw = config.baseDelayMs * config.factor ** (attempt - 1);
|
|
72
|
+
return Math.min(config.maxDelayMs, Math.max(50, raw));
|
|
73
|
+
}
|
|
74
|
+
export function resolveRetryConfig(globalConfig, transportConfig) {
|
|
75
|
+
// Skip entries whose value is `undefined` so a partial override doesn't
|
|
76
|
+
// clobber a default or global value. Pre-spread filter is required because
|
|
77
|
+
// `{ ...obj }` propagates explicit-undefined keys.
|
|
78
|
+
const strip = (x) => x
|
|
79
|
+
? Object.fromEntries(Object.entries(x).filter(([, v]) => v !== undefined))
|
|
80
|
+
: {};
|
|
81
|
+
const merged = {
|
|
82
|
+
...DEFAULT_RETRY_CONFIG,
|
|
83
|
+
...strip(globalConfig),
|
|
84
|
+
...strip(transportConfig),
|
|
85
|
+
};
|
|
86
|
+
if (!Number.isInteger(merged.maxAttempts) || merged.maxAttempts < 1) {
|
|
87
|
+
throw new RoverError("MAIL_RETRY_CONFIG", `RetryConfig.maxAttempts must be an integer >= 1 (got ${merged.maxAttempts})`, { hint: "Set retry.maxAttempts to a positive integer." });
|
|
88
|
+
}
|
|
89
|
+
if (typeof merged.baseDelayMs !== "number" ||
|
|
90
|
+
!Number.isFinite(merged.baseDelayMs) ||
|
|
91
|
+
merged.baseDelayMs < 0) {
|
|
92
|
+
throw new RoverError("MAIL_RETRY_CONFIG", `RetryConfig.baseDelayMs must be a non-negative finite number (got ${merged.baseDelayMs})`, { hint: "Use 0 or a positive number; the 50 ms floor kicks in anyway." });
|
|
93
|
+
}
|
|
94
|
+
if (typeof merged.factor !== "number" ||
|
|
95
|
+
!Number.isFinite(merged.factor) ||
|
|
96
|
+
merged.factor <= 0) {
|
|
97
|
+
throw new RoverError("MAIL_RETRY_CONFIG", `RetryConfig.factor must be a positive finite number (got ${merged.factor})`, { hint: "Use >= 1 for exponential growth; 1 means constant delay." });
|
|
98
|
+
}
|
|
99
|
+
return merged;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `Mail` singleton — mirror of Adonis's
|
|
3
|
+
* `import mail from '@adonisjs/mail/services/main'` shape.
|
|
4
|
+
*
|
|
5
|
+
* The instance is populated by `RoverProvider.boot()` once the
|
|
6
|
+
* container has resolved the `Mail` binding. Callers can `import mail`
|
|
7
|
+
* before boot — the proxy delays method access until `setMail` runs.
|
|
8
|
+
*
|
|
9
|
+
* import mail from '@c9up/rover/services/main'
|
|
10
|
+
*
|
|
11
|
+
* await mail.send((m) => m.to(user.email).subject('Hi').text('Hello'))
|
|
12
|
+
*/
|
|
13
|
+
import type { Mail } from "../Mail.js";
|
|
14
|
+
/** @internal Set the resolved singleton (called by RoverProvider.boot). */
|
|
15
|
+
export declare function setMail(mail: Mail): void;
|
|
16
|
+
/** @internal Get the resolved singleton (or `undefined` pre-boot). */
|
|
17
|
+
export declare function getMail(): Mail | undefined;
|
|
18
|
+
declare const mail: Mail;
|
|
19
|
+
export default mail;
|
|
20
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,2EAA2E;AAC3E,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAExC;AAED,sEAAsE;AACtE,wBAAgB,OAAO,IAAI,IAAI,GAAG,SAAS,CAE1C;AAED,QAAA,MAAM,IAAI,EAAE,IAWV,CAAC;AAEH,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `Mail` singleton — mirror of Adonis's
|
|
3
|
+
* `import mail from '@adonisjs/mail/services/main'` shape.
|
|
4
|
+
*
|
|
5
|
+
* The instance is populated by `RoverProvider.boot()` once the
|
|
6
|
+
* container has resolved the `Mail` binding. Callers can `import mail`
|
|
7
|
+
* before boot — the proxy delays method access until `setMail` runs.
|
|
8
|
+
*
|
|
9
|
+
* import mail from '@c9up/rover/services/main'
|
|
10
|
+
*
|
|
11
|
+
* await mail.send((m) => m.to(user.email).subject('Hi').text('Hello'))
|
|
12
|
+
*/
|
|
13
|
+
let instance;
|
|
14
|
+
/** @internal Set the resolved singleton (called by RoverProvider.boot). */
|
|
15
|
+
export function setMail(mail) {
|
|
16
|
+
instance = mail;
|
|
17
|
+
}
|
|
18
|
+
/** @internal Get the resolved singleton (or `undefined` pre-boot). */
|
|
19
|
+
export function getMail() {
|
|
20
|
+
return instance;
|
|
21
|
+
}
|
|
22
|
+
const mail = new Proxy({}, {
|
|
23
|
+
get(_target, prop) {
|
|
24
|
+
if (!instance) {
|
|
25
|
+
throw new Error("[rover] Mail singleton accessed before RoverProvider.boot() ran. " +
|
|
26
|
+
"Check that `@c9up/rover/provider` is listed in your reamrc.ts providers.");
|
|
27
|
+
}
|
|
28
|
+
const value = Reflect.get(instance, prop, instance);
|
|
29
|
+
return typeof value === "function" ? value.bind(instance) : value;
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
export default mail;
|
|
33
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,IAAI,QAA0B,CAAC;AAE/B,2EAA2E;AAC3E,MAAM,UAAU,OAAO,CAAC,IAAU;IACjC,QAAQ,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,OAAO;IACtB,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,MAAM,IAAI,GAAS,IAAI,KAAK,CAAC,EAAU,EAAE;IACxC,GAAG,CAAC,OAAO,EAAE,IAAI;QAChB,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACd,mEAAmE;gBAClE,0EAA0E,CAC3E,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function setViewsRoot(rootDir: string): void;
|
|
2
|
+
export declare function getViewsRoot(): string;
|
|
3
|
+
/** Reset cached compiled templates (test helper). */
|
|
4
|
+
export declare function resetCache(): void;
|
|
5
|
+
export declare function render(source: string, data: Record<string, unknown>): Promise<string>;
|
|
6
|
+
export declare function renderFile(viewPath: string, data: Record<string, unknown>, _visited?: Set<string>): Promise<string>;
|
|
7
|
+
//# sourceMappingURL=SimpleTemplate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SimpleTemplate.d.ts","sourceRoot":"","sources":["../../src/templating/SimpleTemplate.ts"],"names":[],"mappings":"AAoBA,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,qDAAqD;AACrD,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAsB,MAAM,CAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,wBAAsB,UAAU,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,OAAO,CAAC,MAAM,CAAC,CAIjB"}
|