@dereekb/nestjs 13.30.0 → 13.32.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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/mailgun",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.30.0",
6
- "@dereekb/model": "13.30.0",
7
- "@dereekb/nestjs": "13.30.0",
8
- "@dereekb/rxjs": "13.30.0",
9
- "@dereekb/util": "13.30.0",
5
+ "@dereekb/date": "13.32.0",
6
+ "@dereekb/model": "13.32.0",
7
+ "@dereekb/nestjs": "13.32.0",
8
+ "@dereekb/rxjs": "13.32.0",
9
+ "@dereekb/util": "13.32.0",
10
10
  "@nestjs/common": "^11.1.19",
11
11
  "@nestjs/config": "^4.0.4",
12
12
  "form-data": "^4.0.5",
@@ -1,6 +1,7 @@
1
1
  export * from './mailgun';
2
2
  export * from './mailgun.type';
3
3
  export * from './mailgun.api';
4
+ export * from './mailgun.diagnostic';
4
5
  export * from './mailgun.service.module';
5
6
  export * from './mailgun.service';
6
7
  export * from './mailgun.util';
@@ -1,12 +1,40 @@
1
1
  import { type EmailParticipantString, type WebsiteUrl } from '@dereekb/util';
2
2
  import { MailgunServiceConfig } from './mailgun.config';
3
3
  import { type MailgunSenderDomainString } from './mailgun';
4
- import { type MailgunClient, type MailgunMessagesClient } from './mailgun.type';
4
+ import { type MailgunClient, type MailgunDomainsClient, type MailgunEventsClient, type MailgunMessagesClient, type MailgunSuppressionsClient, type MailgunValidationClient } from './mailgun.type';
5
5
  export declare class MailgunApi {
6
6
  readonly config: MailgunServiceConfig;
7
7
  readonly client: MailgunClient;
8
8
  constructor(config: MailgunServiceConfig);
9
9
  get messages(): MailgunMessagesClient;
10
+ /**
11
+ * The domain's suppression lists (bounces, spam complaints, unsubscribes, whitelists).
12
+ *
13
+ * An address on the bounce or complaint list is silently dropped by Mailgun on every subsequent send,
14
+ * which makes this the first thing to check when diagnosing "this recipient stopped receiving email".
15
+ *
16
+ * @returns The suppressions client.
17
+ */
18
+ get suppressions(): MailgunSuppressionsClient;
19
+ /**
20
+ * The domain's event log, used to inspect what actually happened to sent messages
21
+ * (accepted/delivered/failed/rejected/complained/unsubscribed).
22
+ *
23
+ * @returns The events client.
24
+ */
25
+ get events(): MailgunEventsClient;
26
+ /**
27
+ * Single-address validation.
28
+ *
29
+ * @returns The validation client.
30
+ */
31
+ get validate(): MailgunValidationClient;
32
+ /**
33
+ * Domain administration, used to read the sending domain's verification state.
34
+ *
35
+ * @returns The domains client.
36
+ */
37
+ get domains(): MailgunDomainsClient;
10
38
  get clientUrl(): WebsiteUrl;
11
39
  get domain(): MailgunSenderDomainString;
12
40
  get sender(): EmailParticipantString;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @module mailgun.diagnostic
3
+ *
4
+ * Read-only helpers over the Mailgun Suppressions, Events, Validation, and Domains APIs.
5
+ *
6
+ * These exist to answer "why did this recipient not get the email?" without sending
7
+ * anything. They are all failure-tolerant: a missing suppression record or an
8
+ * unreachable API surfaces as an absent/empty result rather than a thrown error, so a
9
+ * diagnostic routine can report what it could learn instead of aborting.
10
+ */
11
+ import { type EmailAddress, type Maybe, type Milliseconds } from '@dereekb/util';
12
+ import { type MailgunApi } from './mailgun.api';
13
+ import { type MailgunBounceSuppression, type MailgunComplaintSuppression, type MailgunDomainEvent, type MailgunEmailValidationResult, type MailgunEventsQuery, type MailgunUnsubscribeSuppression } from './mailgun.type';
14
+ /**
15
+ * The default number of events to read back when inspecting a recipient's recent activity.
16
+ */
17
+ export declare const DEFAULT_MAILGUN_RECENT_EVENTS_LIMIT = 25;
18
+ /**
19
+ * The default window of history to inspect when reading a recipient's recent events.
20
+ */
21
+ export declare const DEFAULT_MAILGUN_RECENT_EVENTS_WINDOW_DAYS = 30;
22
+ /**
23
+ * Mailgun event names relevant to delivery diagnosis.
24
+ *
25
+ * Mailgun returns these as free-form strings; this enum names the ones that carry
26
+ * delivery meaning. Unknown values are passed through untouched.
27
+ */
28
+ export declare enum MailgunEventName {
29
+ ACCEPTED = "accepted",
30
+ DELIVERED = "delivered",
31
+ FAILED = "failed",
32
+ REJECTED = "rejected",
33
+ COMPLAINED = "complained",
34
+ UNSUBSCRIBED = "unsubscribed",
35
+ OPENED = "opened",
36
+ CLICKED = "clicked",
37
+ STORED = "stored"
38
+ }
39
+ /**
40
+ * Mailgun failure severities. A `permanent` failure will never succeed on retry;
41
+ * a `temporary` one may.
42
+ */
43
+ export declare enum MailgunEventSeverity {
44
+ PERMANENT = "permanent",
45
+ TEMPORARY = "temporary"
46
+ }
47
+ /**
48
+ * The suppression records found for a single address across a domain's suppression lists.
49
+ *
50
+ * A `bounce` or `complaint` entry means Mailgun will silently drop every subsequent
51
+ * message to this address until the entry is removed.
52
+ */
53
+ export interface MailgunRecipientSuppressions {
54
+ readonly bounce?: Maybe<MailgunBounceSuppression>;
55
+ readonly complaint?: Maybe<MailgunComplaintSuppression>;
56
+ readonly unsubscribe?: Maybe<MailgunUnsubscribeSuppression>;
57
+ }
58
+ /**
59
+ * True if any suppression record was found for the address.
60
+ *
61
+ * @param suppressions - The suppression records to check.
62
+ * @returns True if the address appears on any of the domain's suppression lists.
63
+ */
64
+ export declare function hasAnyMailgunRecipientSuppression(suppressions: MailgunRecipientSuppressions): boolean;
65
+ /**
66
+ * Looks up an address across the domain's bounce, complaint, and unsubscribe lists.
67
+ *
68
+ * @param api - The Mailgun API.
69
+ * @param email - The address to look up.
70
+ * @returns The suppression records found for the address. Absent fields mean the address is not on that list.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const suppressions = await mailgunSuppressionsForRecipient(api, 'user@example.com');
75
+ *
76
+ * if (suppressions.bounce) {
77
+ * console.log(`suppressed by bounce: ${suppressions.bounce.error}`);
78
+ * }
79
+ * ```
80
+ */
81
+ export declare function mailgunSuppressionsForRecipient(api: MailgunApi, email: EmailAddress): Promise<MailgunRecipientSuppressions>;
82
+ /**
83
+ * Configuration for reading a recipient's recent Mailgun events.
84
+ */
85
+ export interface MailgunRecentEventsForRecipientConfig {
86
+ /**
87
+ * The maximum number of events to return.
88
+ *
89
+ * Defaults to {@link DEFAULT_MAILGUN_RECENT_EVENTS_LIMIT}.
90
+ */
91
+ readonly limit?: Maybe<number>;
92
+ /**
93
+ * How far back to look.
94
+ *
95
+ * Defaults to {@link DEFAULT_MAILGUN_RECENT_EVENTS_WINDOW_DAYS} days.
96
+ */
97
+ readonly begin?: Maybe<Date>;
98
+ /**
99
+ * Restrict results to a single event name.
100
+ */
101
+ readonly event?: Maybe<string>;
102
+ }
103
+ /**
104
+ * Reads the most recent Mailgun events for a recipient address, newest first.
105
+ *
106
+ * @param api - The Mailgun API.
107
+ * @param email - The recipient address to filter on.
108
+ * @param config - Optional limit/window/event filters.
109
+ * @returns The matching events, newest first. Empty if there is no recent activity or the lookup failed.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * const events = await mailgunRecentEventsForRecipient(api, 'user@example.com', { limit: 10 });
114
+ * const lastDelivered = events.find((x) => x.event === MailgunEventName.DELIVERED);
115
+ * ```
116
+ */
117
+ export declare function mailgunRecentEventsForRecipient(api: MailgunApi, email: EmailAddress, config?: Maybe<MailgunRecentEventsForRecipientConfig>): Promise<MailgunDomainEvent[]>;
118
+ /**
119
+ * Strips the angle brackets Mailgun's send response wraps a message id in.
120
+ *
121
+ * `messages.create()` returns an id shaped like `<20240101120000.1.abc@domain>`, while the
122
+ * Events API `message-id` filter expects the bare `20240101120000.1.abc@domain`. Passing the
123
+ * bracketed form matches nothing.
124
+ *
125
+ * @param messageId - A message id in either form.
126
+ * @returns The message id without surrounding angle brackets.
127
+ */
128
+ export declare function bareMailgunMessageId(messageId: string): string;
129
+ /**
130
+ * Reads all Mailgun events recorded for a specific message id.
131
+ *
132
+ * Used to resolve the outcome of a message that was already sent — the Events API lags the
133
+ * send by seconds to minutes, so an empty result means "not known yet", not "not delivered".
134
+ *
135
+ * @param api - The Mailgun API.
136
+ * @param messageId - The message id, with or without angle brackets.
137
+ * @param config - Optional additional filters (e.g. `recipient` to scope the lookup).
138
+ * @returns The events recorded for the message. Empty if none are recorded yet or the lookup failed.
139
+ */
140
+ export declare function mailgunEventsForMessageId(api: MailgunApi, messageId: string, config?: Maybe<Pick<MailgunEventsQuery, 'recipient' | 'begin' | 'limit'>>): Promise<MailgunDomainEvent[]>;
141
+ /**
142
+ * Runs an arbitrary Events API query, returning an empty list if the lookup fails.
143
+ *
144
+ * @param api - The Mailgun API.
145
+ * @param query - The events query.
146
+ * @returns The matching events, or an empty array on failure.
147
+ */
148
+ export declare function mailgunEventsForQuery(api: MailgunApi, query: MailgunEventsQuery): Promise<MailgunDomainEvent[]>;
149
+ /**
150
+ * The state of a Mailgun sending domain.
151
+ */
152
+ export interface MailgunDomainState {
153
+ /**
154
+ * The domain name.
155
+ */
156
+ readonly domain: string;
157
+ /**
158
+ * Mailgun's state string for the domain. `active` is healthy; `unverified` means DNS is incomplete.
159
+ */
160
+ readonly state?: Maybe<string>;
161
+ /**
162
+ * True if the domain is disabled by Mailgun.
163
+ */
164
+ readonly disabled?: Maybe<boolean>;
165
+ /**
166
+ * True if the state could not be read.
167
+ */
168
+ readonly unknown?: Maybe<boolean>;
169
+ }
170
+ /**
171
+ * Reads the sending domain's state.
172
+ *
173
+ * A domain that is not `active` will fail to deliver regardless of recipient configuration,
174
+ * so this distinguishes a system-wide outage from a per-recipient problem.
175
+ *
176
+ * @param api - The Mailgun API.
177
+ * @returns The domain's state, with `unknown` set if it could not be read.
178
+ */
179
+ export declare function mailgunDomainState(api: MailgunApi): Promise<MailgunDomainState>;
180
+ /**
181
+ * Validates a single email address via the Mailgun Validation API.
182
+ *
183
+ * Note that validation consumes Mailgun validation quota, so callers should treat this as
184
+ * an opt-in check rather than something to run on every request.
185
+ *
186
+ * @param api - The Mailgun API.
187
+ * @param email - The address to validate.
188
+ * @returns The validation result, or undefined if validation is unavailable or failed.
189
+ */
190
+ export declare function mailgunValidateEmail(api: MailgunApi, email: EmailAddress): Promise<Maybe<MailgunEmailValidationResult>>;
191
+ /**
192
+ * Converts a Mailgun event's unix-seconds timestamp to a Date.
193
+ *
194
+ * @param event - The event.
195
+ * @returns The event's timestamp as a Date.
196
+ */
197
+ export declare function mailgunDomainEventDate(event: MailgunDomainEvent): Date;
198
+ /**
199
+ * The age of a Mailgun event in milliseconds relative to `now`.
200
+ *
201
+ * @param event - The event.
202
+ * @param now - The reference time. Defaults to the current time.
203
+ * @returns The event's age in milliseconds.
204
+ */
205
+ export declare function mailgunDomainEventAge(event: MailgunDomainEvent, now?: Date): Milliseconds;
206
+ /**
207
+ * Extracts the most useful human-readable reason from a failed/rejected Mailgun event.
208
+ *
209
+ * Mailgun spreads the explanation across `reason`, `delivery-status.description`, and
210
+ * `delivery-status.message` depending on how the failure occurred, and any of them may be
211
+ * empty.
212
+ *
213
+ * @param event - The event.
214
+ * @returns The best available description, or undefined if the event carries none.
215
+ */
216
+ export declare function mailgunDomainEventFailureReason(event: MailgunDomainEvent): Maybe<string>;
@@ -2,4 +2,67 @@ import type Mailgun from 'mailgun.js';
2
2
  import { type MailgunClientOptions } from 'node_modules/mailgun.js/Types/Types/MailgunClient/MailgunClientOptions';
3
3
  export type MailgunOptions = MailgunClientOptions;
4
4
  export type MailgunClient = ReturnType<Mailgun['client']>;
5
- export type MailgunMessagesClient = ReturnType<Mailgun['client']>['messages'];
5
+ export type MailgunMessagesClient = MailgunClient['messages'];
6
+ export type MailgunSuppressionsClient = MailgunClient['suppressions'];
7
+ export type MailgunEventsClient = MailgunClient['events'];
8
+ export type MailgunValidationClient = MailgunClient['validate'];
9
+ export type MailgunDomainsClient = MailgunClient['domains'];
10
+ /**
11
+ * A page of events returned by the Mailgun Events API.
12
+ */
13
+ export type MailgunEventsList = Awaited<ReturnType<MailgunEventsClient['get']>>;
14
+ /**
15
+ * A single event recorded by Mailgun for a message.
16
+ *
17
+ * Carries the delivery outcome (`event`), its `severity` for failures, and a `delivery-status` block
18
+ * with the receiving server's response.
19
+ */
20
+ export type MailgunDomainEvent = MailgunEventsList['items'][number];
21
+ /**
22
+ * Query/filter for the Mailgun Events API.
23
+ */
24
+ export type MailgunEventsQuery = NonNullable<Parameters<MailgunEventsClient['get']>[1]>;
25
+ /**
26
+ * The result of validating a single email address via the Mailgun Validation API.
27
+ */
28
+ export type MailgunEmailValidationResult = Awaited<ReturnType<MailgunValidationClient['get']>>;
29
+ /**
30
+ * A bounce record on a domain's suppression list.
31
+ *
32
+ * While the address has a bounce record, Mailgun drops every message sent to it.
33
+ */
34
+ export interface MailgunBounceSuppression {
35
+ readonly address: string;
36
+ /**
37
+ * The SMTP status code the receiving server returned.
38
+ */
39
+ readonly code: number;
40
+ /**
41
+ * The receiving server's explanation of the bounce.
42
+ */
43
+ readonly error: string;
44
+ readonly created_at: Date;
45
+ readonly type?: string;
46
+ }
47
+ /**
48
+ * A spam complaint record on a domain's suppression list.
49
+ *
50
+ * While the address has a complaint record, Mailgun drops every message sent to it.
51
+ */
52
+ export interface MailgunComplaintSuppression {
53
+ readonly address: string;
54
+ readonly created_at: Date;
55
+ readonly type?: string;
56
+ }
57
+ /**
58
+ * An unsubscribe record on a domain's suppression list.
59
+ */
60
+ export interface MailgunUnsubscribeSuppression {
61
+ readonly address: string;
62
+ /**
63
+ * The message tags the address unsubscribed from. An empty list means all mail.
64
+ */
65
+ readonly tags?: string[];
66
+ readonly created_at: Date;
67
+ readonly type?: string;
68
+ }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/openai",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.30.0",
6
- "@dereekb/model": "13.30.0",
7
- "@dereekb/nestjs": "13.30.0",
8
- "@dereekb/rxjs": "13.30.0",
9
- "@dereekb/util": "13.30.0",
5
+ "@dereekb/date": "13.32.0",
6
+ "@dereekb/model": "13.32.0",
7
+ "@dereekb/nestjs": "13.32.0",
8
+ "@dereekb/rxjs": "13.32.0",
9
+ "@dereekb/util": "13.32.0",
10
10
  "@nestjs/common": "^11.1.19",
11
11
  "@nestjs/config": "^4.0.4",
12
12
  "express": "^5.2.1",
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/openrouter",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/util": "13.30.0",
6
- "@dereekb/nestjs": "13.30.0",
5
+ "@dereekb/util": "13.32.0",
6
+ "@dereekb/nestjs": "13.32.0",
7
7
  "@nestjs/common": "^11.1.19",
8
8
  "@nestjs/config": "^4.0.4",
9
9
  "express": "^5.2.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "types": "./src/index.d.ts",
5
5
  "module": "./index.esm.js",
6
6
  "main": "./index.cjs.js",
@@ -68,8 +68,8 @@
68
68
  }
69
69
  },
70
70
  "peerDependencies": {
71
- "@dereekb/rxjs": "13.30.0",
72
- "@dereekb/util": "13.30.0",
71
+ "@dereekb/rxjs": "13.32.0",
72
+ "@dereekb/util": "13.32.0",
73
73
  "@nestjs/common": "^11.1.19",
74
74
  "@nestjs/config": "^4.0.4",
75
75
  "@typeform/api-client": "^2.10.2",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/stripe",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.30.0",
6
- "@dereekb/model": "13.30.0",
7
- "@dereekb/nestjs": "13.30.0",
8
- "@dereekb/rxjs": "13.30.0",
9
- "@dereekb/util": "13.30.0",
5
+ "@dereekb/date": "13.32.0",
6
+ "@dereekb/model": "13.32.0",
7
+ "@dereekb/nestjs": "13.32.0",
8
+ "@dereekb/rxjs": "13.32.0",
9
+ "@dereekb/util": "13.32.0",
10
10
  "@nestjs/common": "^11.1.19",
11
11
  "@nestjs/config": "^4.0.4",
12
12
  "express": "^5.2.1",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/twilio",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.30.0",
6
- "@dereekb/model": "13.30.0",
7
- "@dereekb/nestjs": "13.30.0",
8
- "@dereekb/rxjs": "13.30.0",
9
- "@dereekb/util": "13.30.0",
5
+ "@dereekb/date": "13.32.0",
6
+ "@dereekb/model": "13.32.0",
7
+ "@dereekb/nestjs": "13.32.0",
8
+ "@dereekb/rxjs": "13.32.0",
9
+ "@dereekb/util": "13.32.0",
10
10
  "@nestjs/common": "^11.1.19",
11
11
  "@nestjs/config": "^4.0.4",
12
12
  "express": "^5.2.1",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/typeform",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.30.0",
6
- "@dereekb/model": "13.30.0",
7
- "@dereekb/nestjs": "13.30.0",
8
- "@dereekb/rxjs": "13.30.0",
9
- "@dereekb/util": "13.30.0",
5
+ "@dereekb/date": "13.32.0",
6
+ "@dereekb/model": "13.32.0",
7
+ "@dereekb/nestjs": "13.32.0",
8
+ "@dereekb/rxjs": "13.32.0",
9
+ "@dereekb/util": "13.32.0",
10
10
  "@nestjs/common": "^11.1.19",
11
11
  "@nestjs/config": "^4.0.4",
12
12
  "@typeform/api-client": "^2.10.2",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/vapiai",
3
- "version": "13.30.0",
3
+ "version": "13.32.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.30.0",
6
- "@dereekb/model": "13.30.0",
7
- "@dereekb/nestjs": "13.30.0",
8
- "@dereekb/rxjs": "13.30.0",
9
- "@dereekb/util": "13.30.0",
5
+ "@dereekb/date": "13.32.0",
6
+ "@dereekb/model": "13.32.0",
7
+ "@dereekb/nestjs": "13.32.0",
8
+ "@dereekb/rxjs": "13.32.0",
9
+ "@dereekb/util": "13.32.0",
10
10
  "@nestjs/common": "^11.1.19",
11
11
  "@nestjs/config": "^4.0.4",
12
12
  "@vapi-ai/server-sdk": "^0.11.0",