@c9up/rover 0.1.15 → 0.1.16

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.
Files changed (70) hide show
  1. package/dist/Mail.d.ts +8 -4
  2. package/dist/Mail.d.ts.map +1 -1
  3. package/dist/Mail.js.map +1 -1
  4. package/dist/MessageBuilder.js +1 -1
  5. package/dist/MessageBuilder.js.map +1 -1
  6. package/dist/RoverProvider.d.ts +1 -0
  7. package/dist/RoverProvider.d.ts.map +1 -1
  8. package/dist/RoverProvider.js +9 -3
  9. package/dist/RoverProvider.js.map +1 -1
  10. package/dist/augmentations.d.ts +29 -0
  11. package/dist/augmentations.d.ts.map +1 -0
  12. package/dist/augmentations.js +18 -0
  13. package/dist/augmentations.js.map +1 -0
  14. package/dist/emitSafely.d.ts +18 -0
  15. package/dist/emitSafely.d.ts.map +1 -0
  16. package/dist/emitSafely.js +22 -0
  17. package/dist/emitSafely.js.map +1 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/queue/MemoryMailMessenger.d.ts.map +1 -1
  23. package/dist/queue/MemoryMailMessenger.js +14 -15
  24. package/dist/queue/MemoryMailMessenger.js.map +1 -1
  25. package/dist/retry.d.ts +10 -1
  26. package/dist/retry.d.ts.map +1 -1
  27. package/dist/retry.js +9 -0
  28. package/dist/retry.js.map +1 -1
  29. package/dist/testing/FakeMail.d.ts +4 -2
  30. package/dist/testing/FakeMail.d.ts.map +1 -1
  31. package/dist/testing/FakeMail.js +4 -19
  32. package/dist/testing/FakeMail.js.map +1 -1
  33. package/dist/transports/BrevoTransport.js +6 -3
  34. package/dist/transports/BrevoTransport.js.map +1 -1
  35. package/dist/transports/SparkPostTransport.js +6 -3
  36. package/dist/transports/SparkPostTransport.js.map +1 -1
  37. package/dist/webhooks/context.d.ts +9 -1
  38. package/dist/webhooks/context.d.ts.map +1 -1
  39. package/dist/webhooks/mailgun.d.ts.map +1 -1
  40. package/dist/webhooks/mailgun.js +2 -1
  41. package/dist/webhooks/mailgun.js.map +1 -1
  42. package/dist/webhooks/resend.d.ts.map +1 -1
  43. package/dist/webhooks/resend.js +2 -1
  44. package/dist/webhooks/resend.js.map +1 -1
  45. package/dist/webhooks/sendgrid.d.ts.map +1 -1
  46. package/dist/webhooks/sendgrid.js +2 -1
  47. package/dist/webhooks/sendgrid.js.map +1 -1
  48. package/index.darwin-arm64.node +0 -0
  49. package/index.darwin-x64.node +0 -0
  50. package/index.linux-arm64-gnu.node +0 -0
  51. package/index.linux-x64-gnu.node +0 -0
  52. package/index.win32-x64-msvc.node +0 -0
  53. package/package.json +7 -3
  54. package/scripts/build-napi-types.mjs +4 -3
  55. package/scripts/generate-napi-types.mjs +9 -6
  56. package/src/Mail.ts +10 -6
  57. package/src/MessageBuilder.ts +1 -1
  58. package/src/RoverProvider.ts +9 -3
  59. package/src/augmentations.ts +33 -0
  60. package/src/emitSafely.ts +31 -0
  61. package/src/index.ts +2 -0
  62. package/src/queue/MemoryMailMessenger.ts +15 -14
  63. package/src/retry.ts +11 -2
  64. package/src/testing/FakeMail.ts +12 -3
  65. package/src/transports/BrevoTransport.ts +6 -3
  66. package/src/transports/SparkPostTransport.ts +6 -3
  67. package/src/webhooks/context.ts +9 -1
  68. package/src/webhooks/mailgun.ts +2 -1
  69. package/src/webhooks/resend.ts +2 -1
  70. package/src/webhooks/sendgrid.ts +2 -1
package/src/retry.ts CHANGED
@@ -83,9 +83,18 @@ export function computeBackoffMs(
83
83
  return Math.min(config.maxDelayMs, Math.max(50, raw));
84
84
  }
85
85
 
86
+ /**
87
+ * Global and per-transport overrides, merged over the defaults.
88
+ *
89
+ * `Partial`, because that is what the function does: it spreads whatever it is
90
+ * given over {@link DEFAULT_RETRY_CONFIG}, so `{ maxAttempts: 1 }` is a
91
+ * complete answer. Declared as the full `RetryConfig`, a config file writing
92
+ * exactly that was a type error for doing the supported thing — and every
93
+ * caller had to spell `baseDelayMs` and `factor` it did not want to change.
94
+ */
86
95
  export function resolveRetryConfig(
87
- globalConfig: RetryConfig | undefined,
88
- transportConfig: RetryConfig | undefined,
96
+ globalConfig: Partial<RetryConfig> | undefined,
97
+ transportConfig: Partial<RetryConfig> | undefined,
89
98
  ): Required<RetryConfig> {
90
99
  // Skip entries whose value is `undefined` so a partial override doesn't
91
100
  // clobber a default or global value. Pre-spread filter is required because
@@ -1,4 +1,4 @@
1
- import type { Plugin } from "@c9up/helix";
1
+ import type { PluginApi } from "@c9up/helix";
2
2
  import { BaseMail } from "../BaseMail.js";
3
3
  import type { MailMessage, MailSendOutcome, MailTransport } from "../Mail.js";
4
4
 
@@ -340,8 +340,17 @@ export interface FakeableMailer {
340
340
  * frame) and torn down when that test ends — so capture never leaks between
341
341
  * tests. Uses the manager's own `fake()`/`restore()` (the Adonis pattern).
342
342
  */
343
- export function mailFake(mailer: FakeableMailer): Plugin {
344
- return (api) => {
343
+ /** The slice of helix's `PluginApi` this plugin uses. */
344
+ export type MailPluginHost = Pick<PluginApi, "context">;
345
+
346
+ export function mailFake(
347
+ mailer: FakeableMailer,
348
+ ): (api: MailPluginHost) => void {
349
+ // Typed by what it touches, not by the whole `PluginApi`: a test wiring the
350
+ // plugin had to build every field of it — `config`, `cliArgs`, `runner`,
351
+ // `emitter`, `cleanup` — to exercise a function that reads one. Same shape
352
+ // `@c9up/helix-plugin-ream` uses for its own host.
353
+ return (api: MailPluginHost) => {
345
354
  api.context.getter("mail", (ctx) => {
346
355
  const fake = mailer.fake();
347
356
  ctx.cleanup(() => mailer.restore());
@@ -165,9 +165,12 @@ export class BrevoTransport implements MailTransport {
165
165
  function parseContact(input: string): BrevoContact {
166
166
  const s = stripCrlf(input).trim();
167
167
  const match = s.match(/^(.*)<([^>]+)>\s*$/);
168
- if (match) {
169
- const email = match[2].trim();
170
- const name = match[1].trim().replace(/^"|"$/g, "").trim();
168
+ // Both groups are required by the pattern, so a match carries both —
169
+ // named rather than indexed, which is what says so.
170
+ const [, rawName, rawEmail] = match ?? [];
171
+ if (rawEmail !== undefined) {
172
+ const email = rawEmail.trim();
173
+ const name = (rawName ?? "").trim().replace(/^"|"$/g, "").trim();
171
174
  return name ? { email, name } : { email };
172
175
  }
173
176
  return { email: s };
@@ -177,9 +177,12 @@ export class SparkPostTransport implements MailTransport {
177
177
  function parseAddress(input: string): { email: string; name?: string } {
178
178
  const s = stripCrlf(input).trim();
179
179
  const match = s.match(/^(.*)<([^>]+)>\s*$/);
180
- if (match) {
181
- const email = match[2].trim();
182
- const name = match[1].trim().replace(/^"|"$/g, "").trim();
180
+ // Both groups are required by the pattern, so a match carries both —
181
+ // named rather than indexed, which is what says so.
182
+ const [, rawName, rawEmail] = match ?? [];
183
+ if (rawEmail !== undefined) {
184
+ const email = rawEmail.trim();
185
+ const name = (rawName ?? "").trim().replace(/^"|"$/g, "").trim();
183
186
  return name ? { email, name } : { email };
184
187
  }
185
188
  return { email: s };
@@ -37,5 +37,13 @@ export type WebhookMiddleware = (
37
37
  ) => Promise<void>;
38
38
 
39
39
  export interface WebhookEmitter {
40
- emit(event: string, data: unknown): void;
40
+ /**
41
+ * `unknown`, not `void`. `@adonisjs/events` declares
42
+ * `emit(): Promise<void>` and rethrows when a listener fails and no error
43
+ * handler is registered — and a `void` return ACCEPTS a promise-returning
44
+ * function, so the call site reads as if there were nothing to handle.
45
+ * Duck-typed, so it stays wider than Adonis's own class: a Node
46
+ * EventEmitter returns boolean.
47
+ */
48
+ emit(event: string, data: unknown): unknown;
41
49
  }
@@ -1,5 +1,6 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
+ import { emitSafely } from "../emitSafely.js";
3
4
  import type {
4
5
  WebhookEmitter,
5
6
  WebhookHttpContext,
@@ -94,7 +95,7 @@ export function createMailgunWebhookHandler(
94
95
  const eventName = EVENT_MAP[data.event];
95
96
  if (eventName) {
96
97
  try {
97
- emitter.emit(eventName, {
98
+ emitSafely(emitter, eventName, {
98
99
  messageId: data.message?.headers?.["message-id"] ?? "",
99
100
  to: data.recipient ?? "",
100
101
  reason: data.reason,
@@ -1,5 +1,6 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
+ import { emitSafely } from "../emitSafely.js";
3
4
  import type {
4
5
  WebhookEmitter,
5
6
  WebhookHttpContext,
@@ -176,7 +177,7 @@ function emitMappedEvent(
176
177
  ? (payload.data.to[0] ?? "")
177
178
  : (payload.data?.to ?? "");
178
179
  try {
179
- emitter.emit(mapped, {
180
+ emitSafely(emitter, mapped, {
180
181
  messageId: payload.data?.email_id ?? "",
181
182
  to,
182
183
  reason: payload.data?.reason,
@@ -1,5 +1,6 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { createPublicKey, verify } from "node:crypto";
3
+ import { emitSafely } from "../emitSafely.js";
3
4
  import type {
4
5
  WebhookEmitter,
5
6
  WebhookHttpContext,
@@ -101,7 +102,7 @@ export function createSendGridWebhookHandler(
101
102
  const mapped = EVENT_MAP[ev.event];
102
103
  if (!mapped) continue;
103
104
  try {
104
- emitter.emit(mapped, {
105
+ emitSafely(emitter, mapped, {
105
106
  messageId: ev.sg_message_id ?? "",
106
107
  to: ev.email ?? "",
107
108
  reason: ev.reason,