mailpit-api 1.5.4 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/dist/index.d.mts +239 -35
- package/dist/index.d.ts +239 -35
- package/dist/index.js +207 -2
- package/dist/index.mjs +207 -2
- package/package.json +22 -18
package/README.md
CHANGED
|
@@ -61,6 +61,7 @@ export const test = base.extend<MyFixtures>({
|
|
|
61
61
|
const mailpit = new MailpitClient("http://localhost:8025");
|
|
62
62
|
await mailpit.deleteMessages();
|
|
63
63
|
await use(mailpit);
|
|
64
|
+
mailpit.disconnect();
|
|
64
65
|
},
|
|
65
66
|
});
|
|
66
67
|
|
|
@@ -75,7 +76,10 @@ test("should receive welcome email after registration", async ({
|
|
|
75
76
|
page,
|
|
76
77
|
mailpit,
|
|
77
78
|
}) => {
|
|
78
|
-
//
|
|
79
|
+
// Start waiting for the new email event before triggering the action
|
|
80
|
+
const emailPromise = mailpit.waitForEvent("new");
|
|
81
|
+
|
|
82
|
+
// Register a new user
|
|
79
83
|
await page.goto("/register");
|
|
80
84
|
await page.getByTestId("email").fill("test@example.test");
|
|
81
85
|
await page.getByTestId("password").fill("password123");
|
|
@@ -84,12 +88,12 @@ test("should receive welcome email after registration", async ({
|
|
|
84
88
|
// Wait for success message on page
|
|
85
89
|
await expect(page.getByTestId("success-message")).toBeVisible();
|
|
86
90
|
|
|
87
|
-
//
|
|
88
|
-
const
|
|
91
|
+
// Wait for the new email event (up to 5 seconds by default)
|
|
92
|
+
const event = await emailPromise;
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
expect(
|
|
92
|
-
expect(
|
|
93
|
-
expect(
|
|
94
|
+
// Verify the email from the event data
|
|
95
|
+
expect(event.Data.To[0].Address).toBe("test@example.test");
|
|
96
|
+
expect(event.Data.From.Address).toBe("no-reply@your-app.test");
|
|
97
|
+
expect(event.Data.Subject).toBe("Welcome to Our App");
|
|
94
98
|
});
|
|
95
99
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -35,6 +35,15 @@ interface MailpitAttachmentResponse {
|
|
|
35
35
|
PartID: string;
|
|
36
36
|
/** Size in bytes */
|
|
37
37
|
Size: number;
|
|
38
|
+
/** Checksums for the attachment */
|
|
39
|
+
Checksums: {
|
|
40
|
+
/** MD5 checksum */
|
|
41
|
+
MD5: string;
|
|
42
|
+
/** SHA1 checksum */
|
|
43
|
+
SHA1: string;
|
|
44
|
+
/** SHA256 checksum */
|
|
45
|
+
SHA256: string;
|
|
46
|
+
};
|
|
38
47
|
}
|
|
39
48
|
/** Represents information about a Chaos trigger */
|
|
40
49
|
interface MailpitChaosTrigger {
|
|
@@ -177,38 +186,7 @@ interface MailpitMessageSummaryResponse {
|
|
|
177
186
|
/** Response for the {@link MailpitClient.listMessages| listMessages()} API containing the summary of multiple messages. */
|
|
178
187
|
interface MailpitMessagesSummaryResponse {
|
|
179
188
|
/** Messages */
|
|
180
|
-
messages:
|
|
181
|
-
/** The number of attachments */
|
|
182
|
-
Attachments: number;
|
|
183
|
-
/** BCC addresses */
|
|
184
|
-
Bcc: MailpitEmailAddressResponse[];
|
|
185
|
-
/** CC addresses */
|
|
186
|
-
Cc: MailpitEmailAddressResponse[];
|
|
187
|
-
/** Created time in ISO format: 1970-01-01T00:00:00.000Z */
|
|
188
|
-
Created: string;
|
|
189
|
-
/** Sender address */
|
|
190
|
-
From: MailpitEmailAddressResponse;
|
|
191
|
-
/** Database ID */
|
|
192
|
-
ID: string;
|
|
193
|
-
/** Message ID */
|
|
194
|
-
MessageID: string;
|
|
195
|
-
/** Read status */
|
|
196
|
-
Read: boolean;
|
|
197
|
-
/** Reply-To addresses */
|
|
198
|
-
ReplyTo: MailpitEmailAddressResponse[];
|
|
199
|
-
/** Message size in bytes (total) */
|
|
200
|
-
Size: number;
|
|
201
|
-
/** Message snippet includes up to 250 characters */
|
|
202
|
-
Snippet: string;
|
|
203
|
-
/** Email subject */
|
|
204
|
-
Subject: string;
|
|
205
|
-
/** Message tags */
|
|
206
|
-
Tags: string[];
|
|
207
|
-
/** To addresses */
|
|
208
|
-
To: MailpitEmailAddressResponse[];
|
|
209
|
-
/** Username used for authentication (if provided) with the SMTP or {@link MailpitClient.sendMessage| sendMessage} */
|
|
210
|
-
Username?: string;
|
|
211
|
-
}[];
|
|
189
|
+
messages: MailpitMessageListItem[];
|
|
212
190
|
/** Total number of messages matching the current query */
|
|
213
191
|
messages_count: number;
|
|
214
192
|
/** Total number of unread messages matching current query */
|
|
@@ -224,6 +202,39 @@ interface MailpitMessagesSummaryResponse {
|
|
|
224
202
|
/** @deprecated No longer documented upstream */
|
|
225
203
|
count: number;
|
|
226
204
|
}
|
|
205
|
+
/** Represents a message item in a list or WebSocket event */
|
|
206
|
+
interface MailpitMessageListItem {
|
|
207
|
+
/** The number of attachments */
|
|
208
|
+
Attachments: number;
|
|
209
|
+
/** BCC addresses */
|
|
210
|
+
Bcc: MailpitEmailAddressResponse[];
|
|
211
|
+
/** CC addresses */
|
|
212
|
+
Cc: MailpitEmailAddressResponse[];
|
|
213
|
+
/** Created time in ISO format: 1970-01-01T00:00:00.000Z */
|
|
214
|
+
Created: string;
|
|
215
|
+
/** Sender address */
|
|
216
|
+
From: MailpitEmailAddressResponse;
|
|
217
|
+
/** Database ID */
|
|
218
|
+
ID: string;
|
|
219
|
+
/** Message ID */
|
|
220
|
+
MessageID: string;
|
|
221
|
+
/** Read status */
|
|
222
|
+
Read: boolean;
|
|
223
|
+
/** Reply-To addresses */
|
|
224
|
+
ReplyTo: MailpitEmailAddressResponse[];
|
|
225
|
+
/** Message size in bytes (total) */
|
|
226
|
+
Size: number;
|
|
227
|
+
/** Message snippet includes up to 250 characters */
|
|
228
|
+
Snippet: string;
|
|
229
|
+
/** Email subject */
|
|
230
|
+
Subject: string;
|
|
231
|
+
/** Message tags */
|
|
232
|
+
Tags: string[];
|
|
233
|
+
/** To addresses */
|
|
234
|
+
To: MailpitEmailAddressResponse[];
|
|
235
|
+
/** Username used for authentication (if provided) with the SMTP or {@link MailpitClient.sendMessage| sendMessage} */
|
|
236
|
+
Username?: string;
|
|
237
|
+
}
|
|
227
238
|
/** Response for the {@link MailpitClient.getMessageHeaders | getMessageHeaders()} API containing message headers */
|
|
228
239
|
interface MailpitMessageHeadersResponse {
|
|
229
240
|
/** Message headers */
|
|
@@ -411,6 +422,91 @@ interface MailpitAttachmentDataResponse {
|
|
|
411
422
|
/** The attachment MIME type */
|
|
412
423
|
contentType: string;
|
|
413
424
|
}
|
|
425
|
+
/** Message summary data structure returned in "new" events */
|
|
426
|
+
type MailpitMessageSummary = MailpitMessageListItem;
|
|
427
|
+
/** Statistics data structure returned in "stats" events */
|
|
428
|
+
interface MailpitStatsData {
|
|
429
|
+
/** Total number of messages in the database */
|
|
430
|
+
Total: number;
|
|
431
|
+
/** Total number of unread messages */
|
|
432
|
+
Unread: number;
|
|
433
|
+
/** Mailpit version */
|
|
434
|
+
Version: string;
|
|
435
|
+
}
|
|
436
|
+
/** Update data structure returned in "update" events */
|
|
437
|
+
interface MailpitUpdateData {
|
|
438
|
+
/** Message database ID */
|
|
439
|
+
ID: string;
|
|
440
|
+
/** Read status (if changed) */
|
|
441
|
+
Read?: boolean;
|
|
442
|
+
/** Tags (if changed) */
|
|
443
|
+
Tags?: string[];
|
|
444
|
+
}
|
|
445
|
+
/** Delete data structure returned in "delete" events */
|
|
446
|
+
interface MailpitDeleteData {
|
|
447
|
+
/** Message database ID */
|
|
448
|
+
ID: string;
|
|
449
|
+
}
|
|
450
|
+
/** Error data structure returned in "error" events */
|
|
451
|
+
interface MailpitErrorData {
|
|
452
|
+
/** Error severity level */
|
|
453
|
+
Level: string;
|
|
454
|
+
/** Error type */
|
|
455
|
+
Type: string;
|
|
456
|
+
/** Client IP address */
|
|
457
|
+
IP: string;
|
|
458
|
+
/** Error message */
|
|
459
|
+
Message: string;
|
|
460
|
+
}
|
|
461
|
+
/** Event message containing a type and data payload */
|
|
462
|
+
interface MailpitEvent<T = MailpitMessageSummary | MailpitStatsData | MailpitUpdateData | MailpitDeleteData | MailpitErrorData | null> {
|
|
463
|
+
/** Type of event being broadcast */
|
|
464
|
+
Type: string;
|
|
465
|
+
/** Event data payload */
|
|
466
|
+
Data: T;
|
|
467
|
+
}
|
|
468
|
+
/** Event for new messages */
|
|
469
|
+
interface MailpitNewMessageEvent extends MailpitEvent<MailpitMessageSummary> {
|
|
470
|
+
Type: "new";
|
|
471
|
+
}
|
|
472
|
+
/** Event for statistics updates */
|
|
473
|
+
interface MailpitStatsEvent extends MailpitEvent<MailpitStatsData> {
|
|
474
|
+
Type: "stats";
|
|
475
|
+
}
|
|
476
|
+
/** Event for message updates */
|
|
477
|
+
interface MailpitUpdateEvent extends MailpitEvent<MailpitUpdateData> {
|
|
478
|
+
Type: "update";
|
|
479
|
+
}
|
|
480
|
+
/** Event for message deletion */
|
|
481
|
+
interface MailpitDeleteEvent extends MailpitEvent<MailpitDeleteData> {
|
|
482
|
+
Type: "delete";
|
|
483
|
+
}
|
|
484
|
+
/** Event for database pruning (Data is null) */
|
|
485
|
+
interface MailpitPruneEvent extends MailpitEvent<null> {
|
|
486
|
+
Type: "prune";
|
|
487
|
+
}
|
|
488
|
+
/** Event for truncating all messages (Data is null) */
|
|
489
|
+
interface MailpitTruncateEvent extends MailpitEvent<null> {
|
|
490
|
+
Type: "truncate";
|
|
491
|
+
}
|
|
492
|
+
/** Event for client errors (SMTP/POP3 errors) */
|
|
493
|
+
interface MailpitErrorEvent extends MailpitEvent<MailpitErrorData> {
|
|
494
|
+
Type: "error";
|
|
495
|
+
}
|
|
496
|
+
/** Maps event type strings to their corresponding event interfaces */
|
|
497
|
+
interface MailpitEventMap {
|
|
498
|
+
new: MailpitNewMessageEvent;
|
|
499
|
+
stats: MailpitStatsEvent;
|
|
500
|
+
update: MailpitUpdateEvent;
|
|
501
|
+
delete: MailpitDeleteEvent;
|
|
502
|
+
prune: MailpitPruneEvent;
|
|
503
|
+
truncate: MailpitTruncateEvent;
|
|
504
|
+
error: MailpitErrorEvent;
|
|
505
|
+
/** Wildcard event type that matches all events */
|
|
506
|
+
"*": MailpitEvent;
|
|
507
|
+
}
|
|
508
|
+
/** Valid event types including specific event names and the wildcard "*" */
|
|
509
|
+
type MailpitEventType = keyof MailpitEventMap;
|
|
414
510
|
/**
|
|
415
511
|
* Client for interacting with the {@link https://mailpit.axllent.org/docs/api-v1/ | Mailpit API}.
|
|
416
512
|
* @example
|
|
@@ -422,6 +518,10 @@ interface MailpitAttachmentDataResponse {
|
|
|
422
518
|
*/
|
|
423
519
|
declare class MailpitClient {
|
|
424
520
|
private readonly axiosInstance;
|
|
521
|
+
private readonly baseURL;
|
|
522
|
+
private readonly wsURL;
|
|
523
|
+
private webSocket;
|
|
524
|
+
private eventListeners;
|
|
425
525
|
/**
|
|
426
526
|
* Creates an instance of {@link MailpitClient}.
|
|
427
527
|
* @param baseURL - The base URL of the Mailpit API.
|
|
@@ -435,8 +535,8 @@ declare class MailpitClient {
|
|
|
435
535
|
* @example Basic Auth
|
|
436
536
|
* ```typescript
|
|
437
537
|
* const mailpit = new MailpitClient("http://localhost:8025", {
|
|
438
|
-
*
|
|
439
|
-
*
|
|
538
|
+
* username: "admin",
|
|
539
|
+
* password: "supersecret"
|
|
440
540
|
* });
|
|
441
541
|
* ```
|
|
442
542
|
*/
|
|
@@ -781,6 +881,110 @@ declare class MailpitClient {
|
|
|
781
881
|
* ```
|
|
782
882
|
*/
|
|
783
883
|
renderMessageText(id?: string): Promise<string>;
|
|
884
|
+
/**
|
|
885
|
+
* @internal
|
|
886
|
+
* Connects to the WebSocket endpoint for receiving real-time events.
|
|
887
|
+
*/
|
|
888
|
+
private connectWebSocket;
|
|
889
|
+
/**
|
|
890
|
+
* @internal
|
|
891
|
+
* Adds a listener to the event listeners map.
|
|
892
|
+
* @param eventType - The type of event to listen for
|
|
893
|
+
* @param listener - The listener function to add
|
|
894
|
+
*/
|
|
895
|
+
private addListener;
|
|
896
|
+
/**
|
|
897
|
+
* @internal
|
|
898
|
+
* Removes a listener from the event listeners map.
|
|
899
|
+
* @param eventType - The type of event to remove the listener from
|
|
900
|
+
* @param listener - The listener function to remove
|
|
901
|
+
*/
|
|
902
|
+
private removeListener;
|
|
903
|
+
/**
|
|
904
|
+
* @internal
|
|
905
|
+
* Dispatches a message to listeners of a specific event type.
|
|
906
|
+
* @param eventType - The event type to dispatch to
|
|
907
|
+
* @param message - The event message
|
|
908
|
+
*/
|
|
909
|
+
private dispatchToListeners;
|
|
910
|
+
/**
|
|
911
|
+
* @internal
|
|
912
|
+
* Handles incoming WebSocket messages and dispatches them to registered listeners.
|
|
913
|
+
* @param message - The event message
|
|
914
|
+
*/
|
|
915
|
+
private handleWebSocketMessage;
|
|
916
|
+
/**
|
|
917
|
+
* Disconnects from the real-time event stream.
|
|
918
|
+
* @example
|
|
919
|
+
* ```typescript
|
|
920
|
+
* mailpit.disconnect();
|
|
921
|
+
* ```
|
|
922
|
+
*/
|
|
923
|
+
disconnect(): void;
|
|
924
|
+
/**
|
|
925
|
+
* Registers a listener for real-time events of a specific type.
|
|
926
|
+
* @remarks
|
|
927
|
+
* Automatically connects to the event stream if not already connected.
|
|
928
|
+
* @param eventType - The type of event to listen for.
|
|
929
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
930
|
+
* Use "*" to listen for all event types (Useful if processing all events uniformly (e.g., logging, debugging, metrics)).
|
|
931
|
+
* @param listener - The callback function to invoke when an event is received
|
|
932
|
+
* @returns A function to unregister the listener
|
|
933
|
+
* @example Listen for event type "new" messages (recommended)
|
|
934
|
+
* ```typescript
|
|
935
|
+
* const unsubscribe = mailpit.onEvent("new", (event) => {
|
|
936
|
+
* // event.Data is typed as MailpitMessageSummary with full type safety
|
|
937
|
+
* console.log("New message:", event.Data.Subject);
|
|
938
|
+
* });
|
|
939
|
+
*
|
|
940
|
+
* // Other code...
|
|
941
|
+
*
|
|
942
|
+
* // Unsubscribe listener when no longer needed
|
|
943
|
+
* unsubscribe();
|
|
944
|
+
* ```
|
|
945
|
+
* @example Listen for all events uniformly (for logging/debugging)
|
|
946
|
+
* ```typescript
|
|
947
|
+
* const unsubscribe = mailpit.onEvent("*", (event) => {
|
|
948
|
+
* // Generic processing for all event types
|
|
949
|
+
* console.log(`Event ${event.Type} received`);
|
|
950
|
+
* });
|
|
951
|
+
*
|
|
952
|
+
* // Other code...
|
|
953
|
+
*
|
|
954
|
+
* // Unsubscribe listener when no longer needed
|
|
955
|
+
* unsubscribe();
|
|
956
|
+
* ```
|
|
957
|
+
*/
|
|
958
|
+
onEvent<T extends keyof MailpitEventMap>(eventType: T, listener: (event: MailpitEventMap[T]) => void): () => void;
|
|
959
|
+
/**
|
|
960
|
+
* Waits for the next event of a specific type.
|
|
961
|
+
* @remarks
|
|
962
|
+
* Automatically connects to the event stream if not already connected.
|
|
963
|
+
* Primarily intended for testing scenarios where you need to wait for a single specific event.
|
|
964
|
+
* The promise will reject if the timeout is reached before an event is received.
|
|
965
|
+
* @param eventType - The type of event to wait for.
|
|
966
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
967
|
+
* @param timeout - Timeout in milliseconds (default: 5000ms). Pass `Infinity` to disable timeout.
|
|
968
|
+
* @returns A promise that resolves with the event when received, or rejects on timeout
|
|
969
|
+
* @example Basic usage
|
|
970
|
+
* ```typescript
|
|
971
|
+
* // Create the promise before triggering the event
|
|
972
|
+
* const eventPromise = mailpit.waitForEvent("new");
|
|
973
|
+
*
|
|
974
|
+
* // Do something that triggers an email to send
|
|
975
|
+
* await mailpit.sendMessage({
|
|
976
|
+
* From: { Email: "test@example.com" },
|
|
977
|
+
* To: [{ Email: "recipient@example.com" }],
|
|
978
|
+
* Subject: "Test",
|
|
979
|
+
* });
|
|
980
|
+
*
|
|
981
|
+
* // Wait for the event confirming the message was received
|
|
982
|
+
* const event = await eventPromise;
|
|
983
|
+
* // event.Data is fully typed as MailpitMessageSummary
|
|
984
|
+
* console.log("Message received:", event.Data.Subject);
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
987
|
+
waitForEvent<T extends Exclude<keyof MailpitEventMap, "*">>(eventType: T, timeout?: number): Promise<MailpitEventMap[T]>;
|
|
784
988
|
}
|
|
785
989
|
|
|
786
|
-
export { type MailpitAttachmentDataResponse, type MailpitAttachmentRequest, type MailpitAttachmentResponse, type MailpitChaosTrigger, type MailpitChaosTriggersRequest, type MailpitChaosTriggersResponse, MailpitClient, type MailpitConfigurationResponse, type MailpitDatabaseIDsRequest, type MailpitEmailAddressRequest, type MailpitEmailAddressResponse, type MailpitHTMLCheckResponse, type MailpitInfoResponse, type MailpitLinkCheckResponse, type MailpitMessageHeadersResponse, type MailpitMessageSummaryResponse, type MailpitMessagesSummaryResponse, type MailpitReadStatusRequest, type MailpitSearchMessagesRequest, type MailpitSearchRequest, type MailpitSendMessageConfirmationResponse, type MailpitSendRequest, type MailpitSetTagsRequest, type MailpitSpamAssassinResponse, type MailpitTimeZoneRequest };
|
|
990
|
+
export { type MailpitAttachmentDataResponse, type MailpitAttachmentRequest, type MailpitAttachmentResponse, type MailpitChaosTrigger, type MailpitChaosTriggersRequest, type MailpitChaosTriggersResponse, MailpitClient, type MailpitConfigurationResponse, type MailpitDatabaseIDsRequest, type MailpitDeleteData, type MailpitDeleteEvent, type MailpitEmailAddressRequest, type MailpitEmailAddressResponse, type MailpitErrorData, type MailpitErrorEvent, type MailpitEvent, type MailpitEventMap, type MailpitEventType, type MailpitHTMLCheckResponse, type MailpitInfoResponse, type MailpitLinkCheckResponse, type MailpitMessageHeadersResponse, type MailpitMessageListItem, type MailpitMessageSummary, type MailpitMessageSummaryResponse, type MailpitMessagesSummaryResponse, type MailpitNewMessageEvent, type MailpitPruneEvent, type MailpitReadStatusRequest, type MailpitSearchMessagesRequest, type MailpitSearchRequest, type MailpitSendMessageConfirmationResponse, type MailpitSendRequest, type MailpitSetTagsRequest, type MailpitSpamAssassinResponse, type MailpitStatsData, type MailpitStatsEvent, type MailpitTimeZoneRequest, type MailpitTruncateEvent, type MailpitUpdateData, type MailpitUpdateEvent };
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,15 @@ interface MailpitAttachmentResponse {
|
|
|
35
35
|
PartID: string;
|
|
36
36
|
/** Size in bytes */
|
|
37
37
|
Size: number;
|
|
38
|
+
/** Checksums for the attachment */
|
|
39
|
+
Checksums: {
|
|
40
|
+
/** MD5 checksum */
|
|
41
|
+
MD5: string;
|
|
42
|
+
/** SHA1 checksum */
|
|
43
|
+
SHA1: string;
|
|
44
|
+
/** SHA256 checksum */
|
|
45
|
+
SHA256: string;
|
|
46
|
+
};
|
|
38
47
|
}
|
|
39
48
|
/** Represents information about a Chaos trigger */
|
|
40
49
|
interface MailpitChaosTrigger {
|
|
@@ -177,38 +186,7 @@ interface MailpitMessageSummaryResponse {
|
|
|
177
186
|
/** Response for the {@link MailpitClient.listMessages| listMessages()} API containing the summary of multiple messages. */
|
|
178
187
|
interface MailpitMessagesSummaryResponse {
|
|
179
188
|
/** Messages */
|
|
180
|
-
messages:
|
|
181
|
-
/** The number of attachments */
|
|
182
|
-
Attachments: number;
|
|
183
|
-
/** BCC addresses */
|
|
184
|
-
Bcc: MailpitEmailAddressResponse[];
|
|
185
|
-
/** CC addresses */
|
|
186
|
-
Cc: MailpitEmailAddressResponse[];
|
|
187
|
-
/** Created time in ISO format: 1970-01-01T00:00:00.000Z */
|
|
188
|
-
Created: string;
|
|
189
|
-
/** Sender address */
|
|
190
|
-
From: MailpitEmailAddressResponse;
|
|
191
|
-
/** Database ID */
|
|
192
|
-
ID: string;
|
|
193
|
-
/** Message ID */
|
|
194
|
-
MessageID: string;
|
|
195
|
-
/** Read status */
|
|
196
|
-
Read: boolean;
|
|
197
|
-
/** Reply-To addresses */
|
|
198
|
-
ReplyTo: MailpitEmailAddressResponse[];
|
|
199
|
-
/** Message size in bytes (total) */
|
|
200
|
-
Size: number;
|
|
201
|
-
/** Message snippet includes up to 250 characters */
|
|
202
|
-
Snippet: string;
|
|
203
|
-
/** Email subject */
|
|
204
|
-
Subject: string;
|
|
205
|
-
/** Message tags */
|
|
206
|
-
Tags: string[];
|
|
207
|
-
/** To addresses */
|
|
208
|
-
To: MailpitEmailAddressResponse[];
|
|
209
|
-
/** Username used for authentication (if provided) with the SMTP or {@link MailpitClient.sendMessage| sendMessage} */
|
|
210
|
-
Username?: string;
|
|
211
|
-
}[];
|
|
189
|
+
messages: MailpitMessageListItem[];
|
|
212
190
|
/** Total number of messages matching the current query */
|
|
213
191
|
messages_count: number;
|
|
214
192
|
/** Total number of unread messages matching current query */
|
|
@@ -224,6 +202,39 @@ interface MailpitMessagesSummaryResponse {
|
|
|
224
202
|
/** @deprecated No longer documented upstream */
|
|
225
203
|
count: number;
|
|
226
204
|
}
|
|
205
|
+
/** Represents a message item in a list or WebSocket event */
|
|
206
|
+
interface MailpitMessageListItem {
|
|
207
|
+
/** The number of attachments */
|
|
208
|
+
Attachments: number;
|
|
209
|
+
/** BCC addresses */
|
|
210
|
+
Bcc: MailpitEmailAddressResponse[];
|
|
211
|
+
/** CC addresses */
|
|
212
|
+
Cc: MailpitEmailAddressResponse[];
|
|
213
|
+
/** Created time in ISO format: 1970-01-01T00:00:00.000Z */
|
|
214
|
+
Created: string;
|
|
215
|
+
/** Sender address */
|
|
216
|
+
From: MailpitEmailAddressResponse;
|
|
217
|
+
/** Database ID */
|
|
218
|
+
ID: string;
|
|
219
|
+
/** Message ID */
|
|
220
|
+
MessageID: string;
|
|
221
|
+
/** Read status */
|
|
222
|
+
Read: boolean;
|
|
223
|
+
/** Reply-To addresses */
|
|
224
|
+
ReplyTo: MailpitEmailAddressResponse[];
|
|
225
|
+
/** Message size in bytes (total) */
|
|
226
|
+
Size: number;
|
|
227
|
+
/** Message snippet includes up to 250 characters */
|
|
228
|
+
Snippet: string;
|
|
229
|
+
/** Email subject */
|
|
230
|
+
Subject: string;
|
|
231
|
+
/** Message tags */
|
|
232
|
+
Tags: string[];
|
|
233
|
+
/** To addresses */
|
|
234
|
+
To: MailpitEmailAddressResponse[];
|
|
235
|
+
/** Username used for authentication (if provided) with the SMTP or {@link MailpitClient.sendMessage| sendMessage} */
|
|
236
|
+
Username?: string;
|
|
237
|
+
}
|
|
227
238
|
/** Response for the {@link MailpitClient.getMessageHeaders | getMessageHeaders()} API containing message headers */
|
|
228
239
|
interface MailpitMessageHeadersResponse {
|
|
229
240
|
/** Message headers */
|
|
@@ -411,6 +422,91 @@ interface MailpitAttachmentDataResponse {
|
|
|
411
422
|
/** The attachment MIME type */
|
|
412
423
|
contentType: string;
|
|
413
424
|
}
|
|
425
|
+
/** Message summary data structure returned in "new" events */
|
|
426
|
+
type MailpitMessageSummary = MailpitMessageListItem;
|
|
427
|
+
/** Statistics data structure returned in "stats" events */
|
|
428
|
+
interface MailpitStatsData {
|
|
429
|
+
/** Total number of messages in the database */
|
|
430
|
+
Total: number;
|
|
431
|
+
/** Total number of unread messages */
|
|
432
|
+
Unread: number;
|
|
433
|
+
/** Mailpit version */
|
|
434
|
+
Version: string;
|
|
435
|
+
}
|
|
436
|
+
/** Update data structure returned in "update" events */
|
|
437
|
+
interface MailpitUpdateData {
|
|
438
|
+
/** Message database ID */
|
|
439
|
+
ID: string;
|
|
440
|
+
/** Read status (if changed) */
|
|
441
|
+
Read?: boolean;
|
|
442
|
+
/** Tags (if changed) */
|
|
443
|
+
Tags?: string[];
|
|
444
|
+
}
|
|
445
|
+
/** Delete data structure returned in "delete" events */
|
|
446
|
+
interface MailpitDeleteData {
|
|
447
|
+
/** Message database ID */
|
|
448
|
+
ID: string;
|
|
449
|
+
}
|
|
450
|
+
/** Error data structure returned in "error" events */
|
|
451
|
+
interface MailpitErrorData {
|
|
452
|
+
/** Error severity level */
|
|
453
|
+
Level: string;
|
|
454
|
+
/** Error type */
|
|
455
|
+
Type: string;
|
|
456
|
+
/** Client IP address */
|
|
457
|
+
IP: string;
|
|
458
|
+
/** Error message */
|
|
459
|
+
Message: string;
|
|
460
|
+
}
|
|
461
|
+
/** Event message containing a type and data payload */
|
|
462
|
+
interface MailpitEvent<T = MailpitMessageSummary | MailpitStatsData | MailpitUpdateData | MailpitDeleteData | MailpitErrorData | null> {
|
|
463
|
+
/** Type of event being broadcast */
|
|
464
|
+
Type: string;
|
|
465
|
+
/** Event data payload */
|
|
466
|
+
Data: T;
|
|
467
|
+
}
|
|
468
|
+
/** Event for new messages */
|
|
469
|
+
interface MailpitNewMessageEvent extends MailpitEvent<MailpitMessageSummary> {
|
|
470
|
+
Type: "new";
|
|
471
|
+
}
|
|
472
|
+
/** Event for statistics updates */
|
|
473
|
+
interface MailpitStatsEvent extends MailpitEvent<MailpitStatsData> {
|
|
474
|
+
Type: "stats";
|
|
475
|
+
}
|
|
476
|
+
/** Event for message updates */
|
|
477
|
+
interface MailpitUpdateEvent extends MailpitEvent<MailpitUpdateData> {
|
|
478
|
+
Type: "update";
|
|
479
|
+
}
|
|
480
|
+
/** Event for message deletion */
|
|
481
|
+
interface MailpitDeleteEvent extends MailpitEvent<MailpitDeleteData> {
|
|
482
|
+
Type: "delete";
|
|
483
|
+
}
|
|
484
|
+
/** Event for database pruning (Data is null) */
|
|
485
|
+
interface MailpitPruneEvent extends MailpitEvent<null> {
|
|
486
|
+
Type: "prune";
|
|
487
|
+
}
|
|
488
|
+
/** Event for truncating all messages (Data is null) */
|
|
489
|
+
interface MailpitTruncateEvent extends MailpitEvent<null> {
|
|
490
|
+
Type: "truncate";
|
|
491
|
+
}
|
|
492
|
+
/** Event for client errors (SMTP/POP3 errors) */
|
|
493
|
+
interface MailpitErrorEvent extends MailpitEvent<MailpitErrorData> {
|
|
494
|
+
Type: "error";
|
|
495
|
+
}
|
|
496
|
+
/** Maps event type strings to their corresponding event interfaces */
|
|
497
|
+
interface MailpitEventMap {
|
|
498
|
+
new: MailpitNewMessageEvent;
|
|
499
|
+
stats: MailpitStatsEvent;
|
|
500
|
+
update: MailpitUpdateEvent;
|
|
501
|
+
delete: MailpitDeleteEvent;
|
|
502
|
+
prune: MailpitPruneEvent;
|
|
503
|
+
truncate: MailpitTruncateEvent;
|
|
504
|
+
error: MailpitErrorEvent;
|
|
505
|
+
/** Wildcard event type that matches all events */
|
|
506
|
+
"*": MailpitEvent;
|
|
507
|
+
}
|
|
508
|
+
/** Valid event types including specific event names and the wildcard "*" */
|
|
509
|
+
type MailpitEventType = keyof MailpitEventMap;
|
|
414
510
|
/**
|
|
415
511
|
* Client for interacting with the {@link https://mailpit.axllent.org/docs/api-v1/ | Mailpit API}.
|
|
416
512
|
* @example
|
|
@@ -422,6 +518,10 @@ interface MailpitAttachmentDataResponse {
|
|
|
422
518
|
*/
|
|
423
519
|
declare class MailpitClient {
|
|
424
520
|
private readonly axiosInstance;
|
|
521
|
+
private readonly baseURL;
|
|
522
|
+
private readonly wsURL;
|
|
523
|
+
private webSocket;
|
|
524
|
+
private eventListeners;
|
|
425
525
|
/**
|
|
426
526
|
* Creates an instance of {@link MailpitClient}.
|
|
427
527
|
* @param baseURL - The base URL of the Mailpit API.
|
|
@@ -435,8 +535,8 @@ declare class MailpitClient {
|
|
|
435
535
|
* @example Basic Auth
|
|
436
536
|
* ```typescript
|
|
437
537
|
* const mailpit = new MailpitClient("http://localhost:8025", {
|
|
438
|
-
*
|
|
439
|
-
*
|
|
538
|
+
* username: "admin",
|
|
539
|
+
* password: "supersecret"
|
|
440
540
|
* });
|
|
441
541
|
* ```
|
|
442
542
|
*/
|
|
@@ -781,6 +881,110 @@ declare class MailpitClient {
|
|
|
781
881
|
* ```
|
|
782
882
|
*/
|
|
783
883
|
renderMessageText(id?: string): Promise<string>;
|
|
884
|
+
/**
|
|
885
|
+
* @internal
|
|
886
|
+
* Connects to the WebSocket endpoint for receiving real-time events.
|
|
887
|
+
*/
|
|
888
|
+
private connectWebSocket;
|
|
889
|
+
/**
|
|
890
|
+
* @internal
|
|
891
|
+
* Adds a listener to the event listeners map.
|
|
892
|
+
* @param eventType - The type of event to listen for
|
|
893
|
+
* @param listener - The listener function to add
|
|
894
|
+
*/
|
|
895
|
+
private addListener;
|
|
896
|
+
/**
|
|
897
|
+
* @internal
|
|
898
|
+
* Removes a listener from the event listeners map.
|
|
899
|
+
* @param eventType - The type of event to remove the listener from
|
|
900
|
+
* @param listener - The listener function to remove
|
|
901
|
+
*/
|
|
902
|
+
private removeListener;
|
|
903
|
+
/**
|
|
904
|
+
* @internal
|
|
905
|
+
* Dispatches a message to listeners of a specific event type.
|
|
906
|
+
* @param eventType - The event type to dispatch to
|
|
907
|
+
* @param message - The event message
|
|
908
|
+
*/
|
|
909
|
+
private dispatchToListeners;
|
|
910
|
+
/**
|
|
911
|
+
* @internal
|
|
912
|
+
* Handles incoming WebSocket messages and dispatches them to registered listeners.
|
|
913
|
+
* @param message - The event message
|
|
914
|
+
*/
|
|
915
|
+
private handleWebSocketMessage;
|
|
916
|
+
/**
|
|
917
|
+
* Disconnects from the real-time event stream.
|
|
918
|
+
* @example
|
|
919
|
+
* ```typescript
|
|
920
|
+
* mailpit.disconnect();
|
|
921
|
+
* ```
|
|
922
|
+
*/
|
|
923
|
+
disconnect(): void;
|
|
924
|
+
/**
|
|
925
|
+
* Registers a listener for real-time events of a specific type.
|
|
926
|
+
* @remarks
|
|
927
|
+
* Automatically connects to the event stream if not already connected.
|
|
928
|
+
* @param eventType - The type of event to listen for.
|
|
929
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
930
|
+
* Use "*" to listen for all event types (Useful if processing all events uniformly (e.g., logging, debugging, metrics)).
|
|
931
|
+
* @param listener - The callback function to invoke when an event is received
|
|
932
|
+
* @returns A function to unregister the listener
|
|
933
|
+
* @example Listen for event type "new" messages (recommended)
|
|
934
|
+
* ```typescript
|
|
935
|
+
* const unsubscribe = mailpit.onEvent("new", (event) => {
|
|
936
|
+
* // event.Data is typed as MailpitMessageSummary with full type safety
|
|
937
|
+
* console.log("New message:", event.Data.Subject);
|
|
938
|
+
* });
|
|
939
|
+
*
|
|
940
|
+
* // Other code...
|
|
941
|
+
*
|
|
942
|
+
* // Unsubscribe listener when no longer needed
|
|
943
|
+
* unsubscribe();
|
|
944
|
+
* ```
|
|
945
|
+
* @example Listen for all events uniformly (for logging/debugging)
|
|
946
|
+
* ```typescript
|
|
947
|
+
* const unsubscribe = mailpit.onEvent("*", (event) => {
|
|
948
|
+
* // Generic processing for all event types
|
|
949
|
+
* console.log(`Event ${event.Type} received`);
|
|
950
|
+
* });
|
|
951
|
+
*
|
|
952
|
+
* // Other code...
|
|
953
|
+
*
|
|
954
|
+
* // Unsubscribe listener when no longer needed
|
|
955
|
+
* unsubscribe();
|
|
956
|
+
* ```
|
|
957
|
+
*/
|
|
958
|
+
onEvent<T extends keyof MailpitEventMap>(eventType: T, listener: (event: MailpitEventMap[T]) => void): () => void;
|
|
959
|
+
/**
|
|
960
|
+
* Waits for the next event of a specific type.
|
|
961
|
+
* @remarks
|
|
962
|
+
* Automatically connects to the event stream if not already connected.
|
|
963
|
+
* Primarily intended for testing scenarios where you need to wait for a single specific event.
|
|
964
|
+
* The promise will reject if the timeout is reached before an event is received.
|
|
965
|
+
* @param eventType - The type of event to wait for.
|
|
966
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
967
|
+
* @param timeout - Timeout in milliseconds (default: 5000ms). Pass `Infinity` to disable timeout.
|
|
968
|
+
* @returns A promise that resolves with the event when received, or rejects on timeout
|
|
969
|
+
* @example Basic usage
|
|
970
|
+
* ```typescript
|
|
971
|
+
* // Create the promise before triggering the event
|
|
972
|
+
* const eventPromise = mailpit.waitForEvent("new");
|
|
973
|
+
*
|
|
974
|
+
* // Do something that triggers an email to send
|
|
975
|
+
* await mailpit.sendMessage({
|
|
976
|
+
* From: { Email: "test@example.com" },
|
|
977
|
+
* To: [{ Email: "recipient@example.com" }],
|
|
978
|
+
* Subject: "Test",
|
|
979
|
+
* });
|
|
980
|
+
*
|
|
981
|
+
* // Wait for the event confirming the message was received
|
|
982
|
+
* const event = await eventPromise;
|
|
983
|
+
* // event.Data is fully typed as MailpitMessageSummary
|
|
984
|
+
* console.log("Message received:", event.Data.Subject);
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
987
|
+
waitForEvent<T extends Exclude<keyof MailpitEventMap, "*">>(eventType: T, timeout?: number): Promise<MailpitEventMap[T]>;
|
|
784
988
|
}
|
|
785
989
|
|
|
786
|
-
export { type MailpitAttachmentDataResponse, type MailpitAttachmentRequest, type MailpitAttachmentResponse, type MailpitChaosTrigger, type MailpitChaosTriggersRequest, type MailpitChaosTriggersResponse, MailpitClient, type MailpitConfigurationResponse, type MailpitDatabaseIDsRequest, type MailpitEmailAddressRequest, type MailpitEmailAddressResponse, type MailpitHTMLCheckResponse, type MailpitInfoResponse, type MailpitLinkCheckResponse, type MailpitMessageHeadersResponse, type MailpitMessageSummaryResponse, type MailpitMessagesSummaryResponse, type MailpitReadStatusRequest, type MailpitSearchMessagesRequest, type MailpitSearchRequest, type MailpitSendMessageConfirmationResponse, type MailpitSendRequest, type MailpitSetTagsRequest, type MailpitSpamAssassinResponse, type MailpitTimeZoneRequest };
|
|
990
|
+
export { type MailpitAttachmentDataResponse, type MailpitAttachmentRequest, type MailpitAttachmentResponse, type MailpitChaosTrigger, type MailpitChaosTriggersRequest, type MailpitChaosTriggersResponse, MailpitClient, type MailpitConfigurationResponse, type MailpitDatabaseIDsRequest, type MailpitDeleteData, type MailpitDeleteEvent, type MailpitEmailAddressRequest, type MailpitEmailAddressResponse, type MailpitErrorData, type MailpitErrorEvent, type MailpitEvent, type MailpitEventMap, type MailpitEventType, type MailpitHTMLCheckResponse, type MailpitInfoResponse, type MailpitLinkCheckResponse, type MailpitMessageHeadersResponse, type MailpitMessageListItem, type MailpitMessageSummary, type MailpitMessageSummaryResponse, type MailpitMessagesSummaryResponse, type MailpitNewMessageEvent, type MailpitPruneEvent, type MailpitReadStatusRequest, type MailpitSearchMessagesRequest, type MailpitSearchRequest, type MailpitSendMessageConfirmationResponse, type MailpitSendRequest, type MailpitSetTagsRequest, type MailpitSpamAssassinResponse, type MailpitStatsData, type MailpitStatsEvent, type MailpitTimeZoneRequest, type MailpitTruncateEvent, type MailpitUpdateData, type MailpitUpdateEvent };
|
package/dist/index.js
CHANGED
|
@@ -34,8 +34,14 @@ __export(index_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
var import_axios = __toESM(require("axios"));
|
|
37
|
+
var import_partysocket = require("partysocket");
|
|
38
|
+
var import_ws = __toESM(require("ws"));
|
|
37
39
|
var MailpitClient = class {
|
|
38
40
|
axiosInstance;
|
|
41
|
+
baseURL;
|
|
42
|
+
wsURL;
|
|
43
|
+
webSocket = null;
|
|
44
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
39
45
|
/**
|
|
40
46
|
* Creates an instance of {@link MailpitClient}.
|
|
41
47
|
* @param baseURL - The base URL of the Mailpit API.
|
|
@@ -49,12 +55,19 @@ var MailpitClient = class {
|
|
|
49
55
|
* @example Basic Auth
|
|
50
56
|
* ```typescript
|
|
51
57
|
* const mailpit = new MailpitClient("http://localhost:8025", {
|
|
52
|
-
*
|
|
53
|
-
*
|
|
58
|
+
* username: "admin",
|
|
59
|
+
* password: "supersecret"
|
|
54
60
|
* });
|
|
55
61
|
* ```
|
|
56
62
|
*/
|
|
57
63
|
constructor(baseURL, auth) {
|
|
64
|
+
if (!baseURL || !/^https?:\/\//.test(baseURL)) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"The value of the 'baseURL' parameter must start with http:// or https://"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
this.baseURL = baseURL;
|
|
70
|
+
this.wsURL = `${baseURL.replace(/^http/, "ws")}/api/events`;
|
|
58
71
|
this.axiosInstance = import_axios.default.create({
|
|
59
72
|
baseURL,
|
|
60
73
|
auth,
|
|
@@ -564,6 +577,198 @@ var MailpitClient = class {
|
|
|
564
577
|
() => this.axiosInstance.get(`/view/${id}.txt`)
|
|
565
578
|
);
|
|
566
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* @internal
|
|
582
|
+
* Connects to the WebSocket endpoint for receiving real-time events.
|
|
583
|
+
*/
|
|
584
|
+
connectWebSocket() {
|
|
585
|
+
if (this.webSocket && (this.webSocket.readyState === import_partysocket.WebSocket.OPEN || this.webSocket.readyState === import_partysocket.WebSocket.CONNECTING)) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const wsOptions = {};
|
|
589
|
+
if (this.axiosInstance.defaults.auth) {
|
|
590
|
+
wsOptions.headers = {
|
|
591
|
+
Authorization: `Basic ${Buffer.from(`${this.axiosInstance.defaults.auth.username}:${this.axiosInstance.defaults.auth.password}`).toString("base64")}`
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
class AuthenticatedWebSocket extends import_ws.default {
|
|
595
|
+
constructor(address, options) {
|
|
596
|
+
super(address, { ...wsOptions, ...options });
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
this.webSocket = new import_partysocket.WebSocket(this.wsURL, void 0, {
|
|
600
|
+
WebSocket: AuthenticatedWebSocket
|
|
601
|
+
});
|
|
602
|
+
this.webSocket.addEventListener("message", (event) => {
|
|
603
|
+
let message;
|
|
604
|
+
try {
|
|
605
|
+
message = JSON.parse(event.data);
|
|
606
|
+
} catch {
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
this.handleWebSocketMessage(message);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* @internal
|
|
614
|
+
* Adds a listener to the event listeners map.
|
|
615
|
+
* @param eventType - The type of event to listen for
|
|
616
|
+
* @param listener - The listener function to add
|
|
617
|
+
*/
|
|
618
|
+
addListener(eventType, listener) {
|
|
619
|
+
if (!this.eventListeners.has(eventType)) {
|
|
620
|
+
this.eventListeners.set(eventType, /* @__PURE__ */ new Set());
|
|
621
|
+
}
|
|
622
|
+
this.eventListeners.get(eventType)?.add(listener);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* @internal
|
|
626
|
+
* Removes a listener from the event listeners map.
|
|
627
|
+
* @param eventType - The type of event to remove the listener from
|
|
628
|
+
* @param listener - The listener function to remove
|
|
629
|
+
*/
|
|
630
|
+
removeListener(eventType, listener) {
|
|
631
|
+
const listeners = this.eventListeners.get(eventType);
|
|
632
|
+
if (listeners) {
|
|
633
|
+
listeners.delete(listener);
|
|
634
|
+
if (listeners.size === 0) {
|
|
635
|
+
this.eventListeners.delete(eventType);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* @internal
|
|
641
|
+
* Dispatches a message to listeners of a specific event type.
|
|
642
|
+
* @param eventType - The event type to dispatch to
|
|
643
|
+
* @param message - The event message
|
|
644
|
+
*/
|
|
645
|
+
dispatchToListeners(eventType, message) {
|
|
646
|
+
const listeners = this.eventListeners.get(eventType);
|
|
647
|
+
if (listeners) {
|
|
648
|
+
listeners.forEach((listener) => {
|
|
649
|
+
listener(message);
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* @internal
|
|
655
|
+
* Handles incoming WebSocket messages and dispatches them to registered listeners.
|
|
656
|
+
* @param message - The event message
|
|
657
|
+
*/
|
|
658
|
+
handleWebSocketMessage(message) {
|
|
659
|
+
this.dispatchToListeners(message.Type, message);
|
|
660
|
+
this.dispatchToListeners("*", message);
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Disconnects from the real-time event stream.
|
|
664
|
+
* @example
|
|
665
|
+
* ```typescript
|
|
666
|
+
* mailpit.disconnect();
|
|
667
|
+
* ```
|
|
668
|
+
*/
|
|
669
|
+
disconnect() {
|
|
670
|
+
if (this.webSocket) {
|
|
671
|
+
const ws = this.webSocket;
|
|
672
|
+
this.webSocket = null;
|
|
673
|
+
ws.close(1e3, "Client disconnect");
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Registers a listener for real-time events of a specific type.
|
|
678
|
+
* @remarks
|
|
679
|
+
* Automatically connects to the event stream if not already connected.
|
|
680
|
+
* @param eventType - The type of event to listen for.
|
|
681
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
682
|
+
* Use "*" to listen for all event types (Useful if processing all events uniformly (e.g., logging, debugging, metrics)).
|
|
683
|
+
* @param listener - The callback function to invoke when an event is received
|
|
684
|
+
* @returns A function to unregister the listener
|
|
685
|
+
* @example Listen for event type "new" messages (recommended)
|
|
686
|
+
* ```typescript
|
|
687
|
+
* const unsubscribe = mailpit.onEvent("new", (event) => {
|
|
688
|
+
* // event.Data is typed as MailpitMessageSummary with full type safety
|
|
689
|
+
* console.log("New message:", event.Data.Subject);
|
|
690
|
+
* });
|
|
691
|
+
*
|
|
692
|
+
* // Other code...
|
|
693
|
+
*
|
|
694
|
+
* // Unsubscribe listener when no longer needed
|
|
695
|
+
* unsubscribe();
|
|
696
|
+
* ```
|
|
697
|
+
* @example Listen for all events uniformly (for logging/debugging)
|
|
698
|
+
* ```typescript
|
|
699
|
+
* const unsubscribe = mailpit.onEvent("*", (event) => {
|
|
700
|
+
* // Generic processing for all event types
|
|
701
|
+
* console.log(`Event ${event.Type} received`);
|
|
702
|
+
* });
|
|
703
|
+
*
|
|
704
|
+
* // Other code...
|
|
705
|
+
*
|
|
706
|
+
* // Unsubscribe listener when no longer needed
|
|
707
|
+
* unsubscribe();
|
|
708
|
+
* ```
|
|
709
|
+
*/
|
|
710
|
+
onEvent(eventType, listener) {
|
|
711
|
+
if (!this.webSocket || this.webSocket.readyState === import_partysocket.WebSocket.CLOSED) {
|
|
712
|
+
this.connectWebSocket();
|
|
713
|
+
}
|
|
714
|
+
this.addListener(eventType, listener);
|
|
715
|
+
return () => {
|
|
716
|
+
this.removeListener(eventType, listener);
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Waits for the next event of a specific type.
|
|
721
|
+
* @remarks
|
|
722
|
+
* Automatically connects to the event stream if not already connected.
|
|
723
|
+
* Primarily intended for testing scenarios where you need to wait for a single specific event.
|
|
724
|
+
* The promise will reject if the timeout is reached before an event is received.
|
|
725
|
+
* @param eventType - The type of event to wait for.
|
|
726
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
727
|
+
* @param timeout - Timeout in milliseconds (default: 5000ms). Pass `Infinity` to disable timeout.
|
|
728
|
+
* @returns A promise that resolves with the event when received, or rejects on timeout
|
|
729
|
+
* @example Basic usage
|
|
730
|
+
* ```typescript
|
|
731
|
+
* // Create the promise before triggering the event
|
|
732
|
+
* const eventPromise = mailpit.waitForEvent("new");
|
|
733
|
+
*
|
|
734
|
+
* // Do something that triggers an email to send
|
|
735
|
+
* await mailpit.sendMessage({
|
|
736
|
+
* From: { Email: "test@example.com" },
|
|
737
|
+
* To: [{ Email: "recipient@example.com" }],
|
|
738
|
+
* Subject: "Test",
|
|
739
|
+
* });
|
|
740
|
+
*
|
|
741
|
+
* // Wait for the event confirming the message was received
|
|
742
|
+
* const event = await eventPromise;
|
|
743
|
+
* // event.Data is fully typed as MailpitMessageSummary
|
|
744
|
+
* console.log("Message received:", event.Data.Subject);
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
747
|
+
waitForEvent(eventType, timeout = 5e3) {
|
|
748
|
+
if (!this.webSocket || this.webSocket.readyState === import_partysocket.WebSocket.CLOSED) {
|
|
749
|
+
this.connectWebSocket();
|
|
750
|
+
}
|
|
751
|
+
return new Promise((resolve, reject) => {
|
|
752
|
+
let timer = null;
|
|
753
|
+
const cleanup = () => {
|
|
754
|
+
if (timer) {
|
|
755
|
+
clearTimeout(timer);
|
|
756
|
+
}
|
|
757
|
+
this.removeListener(eventType, listener);
|
|
758
|
+
};
|
|
759
|
+
const listener = (event) => {
|
|
760
|
+
cleanup();
|
|
761
|
+
resolve(event);
|
|
762
|
+
};
|
|
763
|
+
this.addListener(eventType, listener);
|
|
764
|
+
if (isFinite(timeout)) {
|
|
765
|
+
timer = setTimeout(() => {
|
|
766
|
+
cleanup();
|
|
767
|
+
reject(new Error(`Timeout waiting for event of type "${eventType}"`));
|
|
768
|
+
}, timeout);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
567
772
|
};
|
|
568
773
|
// Annotate the CommonJS export names for ESM import in node:
|
|
569
774
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
import axios, {
|
|
3
3
|
isAxiosError
|
|
4
4
|
} from "axios";
|
|
5
|
+
import { WebSocket as ReconnectingWebSocket } from "partysocket";
|
|
6
|
+
import WS from "ws";
|
|
5
7
|
var MailpitClient = class {
|
|
6
8
|
axiosInstance;
|
|
9
|
+
baseURL;
|
|
10
|
+
wsURL;
|
|
11
|
+
webSocket = null;
|
|
12
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
7
13
|
/**
|
|
8
14
|
* Creates an instance of {@link MailpitClient}.
|
|
9
15
|
* @param baseURL - The base URL of the Mailpit API.
|
|
@@ -17,12 +23,19 @@ var MailpitClient = class {
|
|
|
17
23
|
* @example Basic Auth
|
|
18
24
|
* ```typescript
|
|
19
25
|
* const mailpit = new MailpitClient("http://localhost:8025", {
|
|
20
|
-
*
|
|
21
|
-
*
|
|
26
|
+
* username: "admin",
|
|
27
|
+
* password: "supersecret"
|
|
22
28
|
* });
|
|
23
29
|
* ```
|
|
24
30
|
*/
|
|
25
31
|
constructor(baseURL, auth) {
|
|
32
|
+
if (!baseURL || !/^https?:\/\//.test(baseURL)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"The value of the 'baseURL' parameter must start with http:// or https://"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
this.baseURL = baseURL;
|
|
38
|
+
this.wsURL = `${baseURL.replace(/^http/, "ws")}/api/events`;
|
|
26
39
|
this.axiosInstance = axios.create({
|
|
27
40
|
baseURL,
|
|
28
41
|
auth,
|
|
@@ -532,6 +545,198 @@ var MailpitClient = class {
|
|
|
532
545
|
() => this.axiosInstance.get(`/view/${id}.txt`)
|
|
533
546
|
);
|
|
534
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* @internal
|
|
550
|
+
* Connects to the WebSocket endpoint for receiving real-time events.
|
|
551
|
+
*/
|
|
552
|
+
connectWebSocket() {
|
|
553
|
+
if (this.webSocket && (this.webSocket.readyState === ReconnectingWebSocket.OPEN || this.webSocket.readyState === ReconnectingWebSocket.CONNECTING)) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const wsOptions = {};
|
|
557
|
+
if (this.axiosInstance.defaults.auth) {
|
|
558
|
+
wsOptions.headers = {
|
|
559
|
+
Authorization: `Basic ${Buffer.from(`${this.axiosInstance.defaults.auth.username}:${this.axiosInstance.defaults.auth.password}`).toString("base64")}`
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
class AuthenticatedWebSocket extends WS {
|
|
563
|
+
constructor(address, options) {
|
|
564
|
+
super(address, { ...wsOptions, ...options });
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
this.webSocket = new ReconnectingWebSocket(this.wsURL, void 0, {
|
|
568
|
+
WebSocket: AuthenticatedWebSocket
|
|
569
|
+
});
|
|
570
|
+
this.webSocket.addEventListener("message", (event) => {
|
|
571
|
+
let message;
|
|
572
|
+
try {
|
|
573
|
+
message = JSON.parse(event.data);
|
|
574
|
+
} catch {
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
this.handleWebSocketMessage(message);
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* @internal
|
|
582
|
+
* Adds a listener to the event listeners map.
|
|
583
|
+
* @param eventType - The type of event to listen for
|
|
584
|
+
* @param listener - The listener function to add
|
|
585
|
+
*/
|
|
586
|
+
addListener(eventType, listener) {
|
|
587
|
+
if (!this.eventListeners.has(eventType)) {
|
|
588
|
+
this.eventListeners.set(eventType, /* @__PURE__ */ new Set());
|
|
589
|
+
}
|
|
590
|
+
this.eventListeners.get(eventType)?.add(listener);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* @internal
|
|
594
|
+
* Removes a listener from the event listeners map.
|
|
595
|
+
* @param eventType - The type of event to remove the listener from
|
|
596
|
+
* @param listener - The listener function to remove
|
|
597
|
+
*/
|
|
598
|
+
removeListener(eventType, listener) {
|
|
599
|
+
const listeners = this.eventListeners.get(eventType);
|
|
600
|
+
if (listeners) {
|
|
601
|
+
listeners.delete(listener);
|
|
602
|
+
if (listeners.size === 0) {
|
|
603
|
+
this.eventListeners.delete(eventType);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* @internal
|
|
609
|
+
* Dispatches a message to listeners of a specific event type.
|
|
610
|
+
* @param eventType - The event type to dispatch to
|
|
611
|
+
* @param message - The event message
|
|
612
|
+
*/
|
|
613
|
+
dispatchToListeners(eventType, message) {
|
|
614
|
+
const listeners = this.eventListeners.get(eventType);
|
|
615
|
+
if (listeners) {
|
|
616
|
+
listeners.forEach((listener) => {
|
|
617
|
+
listener(message);
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* @internal
|
|
623
|
+
* Handles incoming WebSocket messages and dispatches them to registered listeners.
|
|
624
|
+
* @param message - The event message
|
|
625
|
+
*/
|
|
626
|
+
handleWebSocketMessage(message) {
|
|
627
|
+
this.dispatchToListeners(message.Type, message);
|
|
628
|
+
this.dispatchToListeners("*", message);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Disconnects from the real-time event stream.
|
|
632
|
+
* @example
|
|
633
|
+
* ```typescript
|
|
634
|
+
* mailpit.disconnect();
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
637
|
+
disconnect() {
|
|
638
|
+
if (this.webSocket) {
|
|
639
|
+
const ws = this.webSocket;
|
|
640
|
+
this.webSocket = null;
|
|
641
|
+
ws.close(1e3, "Client disconnect");
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Registers a listener for real-time events of a specific type.
|
|
646
|
+
* @remarks
|
|
647
|
+
* Automatically connects to the event stream if not already connected.
|
|
648
|
+
* @param eventType - The type of event to listen for.
|
|
649
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
650
|
+
* Use "*" to listen for all event types (Useful if processing all events uniformly (e.g., logging, debugging, metrics)).
|
|
651
|
+
* @param listener - The callback function to invoke when an event is received
|
|
652
|
+
* @returns A function to unregister the listener
|
|
653
|
+
* @example Listen for event type "new" messages (recommended)
|
|
654
|
+
* ```typescript
|
|
655
|
+
* const unsubscribe = mailpit.onEvent("new", (event) => {
|
|
656
|
+
* // event.Data is typed as MailpitMessageSummary with full type safety
|
|
657
|
+
* console.log("New message:", event.Data.Subject);
|
|
658
|
+
* });
|
|
659
|
+
*
|
|
660
|
+
* // Other code...
|
|
661
|
+
*
|
|
662
|
+
* // Unsubscribe listener when no longer needed
|
|
663
|
+
* unsubscribe();
|
|
664
|
+
* ```
|
|
665
|
+
* @example Listen for all events uniformly (for logging/debugging)
|
|
666
|
+
* ```typescript
|
|
667
|
+
* const unsubscribe = mailpit.onEvent("*", (event) => {
|
|
668
|
+
* // Generic processing for all event types
|
|
669
|
+
* console.log(`Event ${event.Type} received`);
|
|
670
|
+
* });
|
|
671
|
+
*
|
|
672
|
+
* // Other code...
|
|
673
|
+
*
|
|
674
|
+
* // Unsubscribe listener when no longer needed
|
|
675
|
+
* unsubscribe();
|
|
676
|
+
* ```
|
|
677
|
+
*/
|
|
678
|
+
onEvent(eventType, listener) {
|
|
679
|
+
if (!this.webSocket || this.webSocket.readyState === ReconnectingWebSocket.CLOSED) {
|
|
680
|
+
this.connectWebSocket();
|
|
681
|
+
}
|
|
682
|
+
this.addListener(eventType, listener);
|
|
683
|
+
return () => {
|
|
684
|
+
this.removeListener(eventType, listener);
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Waits for the next event of a specific type.
|
|
689
|
+
* @remarks
|
|
690
|
+
* Automatically connects to the event stream if not already connected.
|
|
691
|
+
* Primarily intended for testing scenarios where you need to wait for a single specific event.
|
|
692
|
+
* The promise will reject if the timeout is reached before an event is received.
|
|
693
|
+
* @param eventType - The type of event to wait for.
|
|
694
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
695
|
+
* @param timeout - Timeout in milliseconds (default: 5000ms). Pass `Infinity` to disable timeout.
|
|
696
|
+
* @returns A promise that resolves with the event when received, or rejects on timeout
|
|
697
|
+
* @example Basic usage
|
|
698
|
+
* ```typescript
|
|
699
|
+
* // Create the promise before triggering the event
|
|
700
|
+
* const eventPromise = mailpit.waitForEvent("new");
|
|
701
|
+
*
|
|
702
|
+
* // Do something that triggers an email to send
|
|
703
|
+
* await mailpit.sendMessage({
|
|
704
|
+
* From: { Email: "test@example.com" },
|
|
705
|
+
* To: [{ Email: "recipient@example.com" }],
|
|
706
|
+
* Subject: "Test",
|
|
707
|
+
* });
|
|
708
|
+
*
|
|
709
|
+
* // Wait for the event confirming the message was received
|
|
710
|
+
* const event = await eventPromise;
|
|
711
|
+
* // event.Data is fully typed as MailpitMessageSummary
|
|
712
|
+
* console.log("Message received:", event.Data.Subject);
|
|
713
|
+
* ```
|
|
714
|
+
*/
|
|
715
|
+
waitForEvent(eventType, timeout = 5e3) {
|
|
716
|
+
if (!this.webSocket || this.webSocket.readyState === ReconnectingWebSocket.CLOSED) {
|
|
717
|
+
this.connectWebSocket();
|
|
718
|
+
}
|
|
719
|
+
return new Promise((resolve, reject) => {
|
|
720
|
+
let timer = null;
|
|
721
|
+
const cleanup = () => {
|
|
722
|
+
if (timer) {
|
|
723
|
+
clearTimeout(timer);
|
|
724
|
+
}
|
|
725
|
+
this.removeListener(eventType, listener);
|
|
726
|
+
};
|
|
727
|
+
const listener = (event) => {
|
|
728
|
+
cleanup();
|
|
729
|
+
resolve(event);
|
|
730
|
+
};
|
|
731
|
+
this.addListener(eventType, listener);
|
|
732
|
+
if (isFinite(timeout)) {
|
|
733
|
+
timer = setTimeout(() => {
|
|
734
|
+
cleanup();
|
|
735
|
+
reject(new Error(`Timeout waiting for event of type "${eventType}"`));
|
|
736
|
+
}, timeout);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
}
|
|
535
740
|
};
|
|
536
741
|
export {
|
|
537
742
|
MailpitClient
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailpit-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "A TypeScript client for interacting with Mailpit's REST API.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/mpspahr/mailpit-api.git"
|
|
7
|
+
"url": "git+https://github.com/mpspahr/mailpit-api.git"
|
|
8
8
|
},
|
|
9
9
|
"homepage": "https://mpspahr.github.io/mailpit-api/",
|
|
10
10
|
"bugs": {
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
14
|
"registry": "https://registry.npmjs.org/",
|
|
15
|
-
"provenance": true
|
|
15
|
+
"provenance": true,
|
|
16
|
+
"access": "public"
|
|
16
17
|
},
|
|
17
18
|
"engines": {
|
|
18
19
|
"node": ">=18.0.0"
|
|
@@ -59,23 +60,26 @@
|
|
|
59
60
|
"author": "Matthew Spahr",
|
|
60
61
|
"license": "MIT",
|
|
61
62
|
"dependencies": {
|
|
62
|
-
"axios": "^1.12.1"
|
|
63
|
+
"axios": "^1.12.1",
|
|
64
|
+
"partysocket": "^1.1.10",
|
|
65
|
+
"ws": "^8.18.3"
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
65
|
-
"@eslint/js": "^9.
|
|
66
|
-
"@jest/globals": "^30.
|
|
67
|
-
"@types/node": "^
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"eslint
|
|
71
|
-
"jest": "^
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
68
|
+
"@eslint/js": "^9.39.2",
|
|
69
|
+
"@jest/globals": "^30.2.0",
|
|
70
|
+
"@types/node": "^24.10.9",
|
|
71
|
+
"@types/ws": "^8.18.1",
|
|
72
|
+
"dotenv": "^17.2.3",
|
|
73
|
+
"eslint": "^9.39.2",
|
|
74
|
+
"eslint-plugin-jest": "^29.12.1",
|
|
75
|
+
"jest": "^30.2.0",
|
|
76
|
+
"prettier": "^3.8.1",
|
|
77
|
+
"ts-jest": "^29.4.6",
|
|
78
|
+
"tsup": "^8.5.1",
|
|
79
|
+
"tsx": "^4.21.0",
|
|
80
|
+
"typedoc": "^0.28.16",
|
|
77
81
|
"typedoc-github-theme": "^0.3.1",
|
|
78
|
-
"typescript": "^5.
|
|
79
|
-
"typescript-eslint": "^8.
|
|
82
|
+
"typescript": "^5.9.3",
|
|
83
|
+
"typescript-eslint": "^8.54.0"
|
|
80
84
|
}
|
|
81
85
|
}
|