mailpit-api 1.5.3 → 1.6.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 +230 -35
- package/dist/index.d.ts +230 -35
- package/dist/index.js +207 -2
- package/dist/index.mjs +207 -2
- package/package.json +20 -17
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
|
@@ -177,38 +177,7 @@ interface MailpitMessageSummaryResponse {
|
|
|
177
177
|
/** Response for the {@link MailpitClient.listMessages| listMessages()} API containing the summary of multiple messages. */
|
|
178
178
|
interface MailpitMessagesSummaryResponse {
|
|
179
179
|
/** 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
|
-
}[];
|
|
180
|
+
messages: MailpitMessageListItem[];
|
|
212
181
|
/** Total number of messages matching the current query */
|
|
213
182
|
messages_count: number;
|
|
214
183
|
/** Total number of unread messages matching current query */
|
|
@@ -224,6 +193,39 @@ interface MailpitMessagesSummaryResponse {
|
|
|
224
193
|
/** @deprecated No longer documented upstream */
|
|
225
194
|
count: number;
|
|
226
195
|
}
|
|
196
|
+
/** Represents a message item in a list or WebSocket event */
|
|
197
|
+
interface MailpitMessageListItem {
|
|
198
|
+
/** The number of attachments */
|
|
199
|
+
Attachments: number;
|
|
200
|
+
/** BCC addresses */
|
|
201
|
+
Bcc: MailpitEmailAddressResponse[];
|
|
202
|
+
/** CC addresses */
|
|
203
|
+
Cc: MailpitEmailAddressResponse[];
|
|
204
|
+
/** Created time in ISO format: 1970-01-01T00:00:00.000Z */
|
|
205
|
+
Created: string;
|
|
206
|
+
/** Sender address */
|
|
207
|
+
From: MailpitEmailAddressResponse;
|
|
208
|
+
/** Database ID */
|
|
209
|
+
ID: string;
|
|
210
|
+
/** Message ID */
|
|
211
|
+
MessageID: string;
|
|
212
|
+
/** Read status */
|
|
213
|
+
Read: boolean;
|
|
214
|
+
/** Reply-To addresses */
|
|
215
|
+
ReplyTo: MailpitEmailAddressResponse[];
|
|
216
|
+
/** Message size in bytes (total) */
|
|
217
|
+
Size: number;
|
|
218
|
+
/** Message snippet includes up to 250 characters */
|
|
219
|
+
Snippet: string;
|
|
220
|
+
/** Email subject */
|
|
221
|
+
Subject: string;
|
|
222
|
+
/** Message tags */
|
|
223
|
+
Tags: string[];
|
|
224
|
+
/** To addresses */
|
|
225
|
+
To: MailpitEmailAddressResponse[];
|
|
226
|
+
/** Username used for authentication (if provided) with the SMTP or {@link MailpitClient.sendMessage| sendMessage} */
|
|
227
|
+
Username?: string;
|
|
228
|
+
}
|
|
227
229
|
/** Response for the {@link MailpitClient.getMessageHeaders | getMessageHeaders()} API containing message headers */
|
|
228
230
|
interface MailpitMessageHeadersResponse {
|
|
229
231
|
/** Message headers */
|
|
@@ -411,6 +413,91 @@ interface MailpitAttachmentDataResponse {
|
|
|
411
413
|
/** The attachment MIME type */
|
|
412
414
|
contentType: string;
|
|
413
415
|
}
|
|
416
|
+
/** Message summary data structure returned in "new" events */
|
|
417
|
+
type MailpitMessageSummary = MailpitMessageListItem;
|
|
418
|
+
/** Statistics data structure returned in "stats" events */
|
|
419
|
+
interface MailpitStatsData {
|
|
420
|
+
/** Total number of messages in the database */
|
|
421
|
+
Total: number;
|
|
422
|
+
/** Total number of unread messages */
|
|
423
|
+
Unread: number;
|
|
424
|
+
/** Mailpit version */
|
|
425
|
+
Version: string;
|
|
426
|
+
}
|
|
427
|
+
/** Update data structure returned in "update" events */
|
|
428
|
+
interface MailpitUpdateData {
|
|
429
|
+
/** Message database ID */
|
|
430
|
+
ID: string;
|
|
431
|
+
/** Read status (if changed) */
|
|
432
|
+
Read?: boolean;
|
|
433
|
+
/** Tags (if changed) */
|
|
434
|
+
Tags?: string[];
|
|
435
|
+
}
|
|
436
|
+
/** Delete data structure returned in "delete" events */
|
|
437
|
+
interface MailpitDeleteData {
|
|
438
|
+
/** Message database ID */
|
|
439
|
+
ID: string;
|
|
440
|
+
}
|
|
441
|
+
/** Error data structure returned in "error" events */
|
|
442
|
+
interface MailpitErrorData {
|
|
443
|
+
/** Error severity level */
|
|
444
|
+
Level: string;
|
|
445
|
+
/** Error type */
|
|
446
|
+
Type: string;
|
|
447
|
+
/** Client IP address */
|
|
448
|
+
IP: string;
|
|
449
|
+
/** Error message */
|
|
450
|
+
Message: string;
|
|
451
|
+
}
|
|
452
|
+
/** Event message containing a type and data payload */
|
|
453
|
+
interface MailpitEvent<T = MailpitMessageSummary | MailpitStatsData | MailpitUpdateData | MailpitDeleteData | MailpitErrorData | null> {
|
|
454
|
+
/** Type of event being broadcast */
|
|
455
|
+
Type: string;
|
|
456
|
+
/** Event data payload */
|
|
457
|
+
Data: T;
|
|
458
|
+
}
|
|
459
|
+
/** Event for new messages */
|
|
460
|
+
interface MailpitNewMessageEvent extends MailpitEvent<MailpitMessageSummary> {
|
|
461
|
+
Type: "new";
|
|
462
|
+
}
|
|
463
|
+
/** Event for statistics updates */
|
|
464
|
+
interface MailpitStatsEvent extends MailpitEvent<MailpitStatsData> {
|
|
465
|
+
Type: "stats";
|
|
466
|
+
}
|
|
467
|
+
/** Event for message updates */
|
|
468
|
+
interface MailpitUpdateEvent extends MailpitEvent<MailpitUpdateData> {
|
|
469
|
+
Type: "update";
|
|
470
|
+
}
|
|
471
|
+
/** Event for message deletion */
|
|
472
|
+
interface MailpitDeleteEvent extends MailpitEvent<MailpitDeleteData> {
|
|
473
|
+
Type: "delete";
|
|
474
|
+
}
|
|
475
|
+
/** Event for database pruning (Data is null) */
|
|
476
|
+
interface MailpitPruneEvent extends MailpitEvent<null> {
|
|
477
|
+
Type: "prune";
|
|
478
|
+
}
|
|
479
|
+
/** Event for truncating all messages (Data is null) */
|
|
480
|
+
interface MailpitTruncateEvent extends MailpitEvent<null> {
|
|
481
|
+
Type: "truncate";
|
|
482
|
+
}
|
|
483
|
+
/** Event for client errors (SMTP/POP3 errors) */
|
|
484
|
+
interface MailpitErrorEvent extends MailpitEvent<MailpitErrorData> {
|
|
485
|
+
Type: "error";
|
|
486
|
+
}
|
|
487
|
+
/** Maps event type strings to their corresponding event interfaces */
|
|
488
|
+
interface MailpitEventMap {
|
|
489
|
+
new: MailpitNewMessageEvent;
|
|
490
|
+
stats: MailpitStatsEvent;
|
|
491
|
+
update: MailpitUpdateEvent;
|
|
492
|
+
delete: MailpitDeleteEvent;
|
|
493
|
+
prune: MailpitPruneEvent;
|
|
494
|
+
truncate: MailpitTruncateEvent;
|
|
495
|
+
error: MailpitErrorEvent;
|
|
496
|
+
/** Wildcard event type that matches all events */
|
|
497
|
+
"*": MailpitEvent;
|
|
498
|
+
}
|
|
499
|
+
/** Valid event types including specific event names and the wildcard "*" */
|
|
500
|
+
type MailpitEventType = keyof MailpitEventMap;
|
|
414
501
|
/**
|
|
415
502
|
* Client for interacting with the {@link https://mailpit.axllent.org/docs/api-v1/ | Mailpit API}.
|
|
416
503
|
* @example
|
|
@@ -422,6 +509,10 @@ interface MailpitAttachmentDataResponse {
|
|
|
422
509
|
*/
|
|
423
510
|
declare class MailpitClient {
|
|
424
511
|
private readonly axiosInstance;
|
|
512
|
+
private readonly baseURL;
|
|
513
|
+
private readonly wsURL;
|
|
514
|
+
private webSocket;
|
|
515
|
+
private eventListeners;
|
|
425
516
|
/**
|
|
426
517
|
* Creates an instance of {@link MailpitClient}.
|
|
427
518
|
* @param baseURL - The base URL of the Mailpit API.
|
|
@@ -435,8 +526,8 @@ declare class MailpitClient {
|
|
|
435
526
|
* @example Basic Auth
|
|
436
527
|
* ```typescript
|
|
437
528
|
* const mailpit = new MailpitClient("http://localhost:8025", {
|
|
438
|
-
*
|
|
439
|
-
*
|
|
529
|
+
* username: "admin",
|
|
530
|
+
* password: "supersecret"
|
|
440
531
|
* });
|
|
441
532
|
* ```
|
|
442
533
|
*/
|
|
@@ -781,6 +872,110 @@ declare class MailpitClient {
|
|
|
781
872
|
* ```
|
|
782
873
|
*/
|
|
783
874
|
renderMessageText(id?: string): Promise<string>;
|
|
875
|
+
/**
|
|
876
|
+
* @internal
|
|
877
|
+
* Connects to the WebSocket endpoint for receiving real-time events.
|
|
878
|
+
*/
|
|
879
|
+
private connectWebSocket;
|
|
880
|
+
/**
|
|
881
|
+
* @internal
|
|
882
|
+
* Adds a listener to the event listeners map.
|
|
883
|
+
* @param eventType - The type of event to listen for
|
|
884
|
+
* @param listener - The listener function to add
|
|
885
|
+
*/
|
|
886
|
+
private addListener;
|
|
887
|
+
/**
|
|
888
|
+
* @internal
|
|
889
|
+
* Removes a listener from the event listeners map.
|
|
890
|
+
* @param eventType - The type of event to remove the listener from
|
|
891
|
+
* @param listener - The listener function to remove
|
|
892
|
+
*/
|
|
893
|
+
private removeListener;
|
|
894
|
+
/**
|
|
895
|
+
* @internal
|
|
896
|
+
* Dispatches a message to listeners of a specific event type.
|
|
897
|
+
* @param eventType - The event type to dispatch to
|
|
898
|
+
* @param message - The event message
|
|
899
|
+
*/
|
|
900
|
+
private dispatchToListeners;
|
|
901
|
+
/**
|
|
902
|
+
* @internal
|
|
903
|
+
* Handles incoming WebSocket messages and dispatches them to registered listeners.
|
|
904
|
+
* @param message - The event message
|
|
905
|
+
*/
|
|
906
|
+
private handleWebSocketMessage;
|
|
907
|
+
/**
|
|
908
|
+
* Disconnects from the real-time event stream.
|
|
909
|
+
* @example
|
|
910
|
+
* ```typescript
|
|
911
|
+
* mailpit.disconnect();
|
|
912
|
+
* ```
|
|
913
|
+
*/
|
|
914
|
+
disconnect(): void;
|
|
915
|
+
/**
|
|
916
|
+
* Registers a listener for real-time events of a specific type.
|
|
917
|
+
* @remarks
|
|
918
|
+
* Automatically connects to the event stream if not already connected.
|
|
919
|
+
* @param eventType - The type of event to listen for.
|
|
920
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
921
|
+
* Use "*" to listen for all event types (Useful if processing all events uniformly (e.g., logging, debugging, metrics)).
|
|
922
|
+
* @param listener - The callback function to invoke when an event is received
|
|
923
|
+
* @returns A function to unregister the listener
|
|
924
|
+
* @example Listen for event type "new" messages (recommended)
|
|
925
|
+
* ```typescript
|
|
926
|
+
* const unsubscribe = mailpit.onEvent("new", (event) => {
|
|
927
|
+
* // event.Data is typed as MailpitMessageSummary with full type safety
|
|
928
|
+
* console.log("New message:", event.Data.Subject);
|
|
929
|
+
* });
|
|
930
|
+
*
|
|
931
|
+
* // Other code...
|
|
932
|
+
*
|
|
933
|
+
* // Unsubscribe listener when no longer needed
|
|
934
|
+
* unsubscribe();
|
|
935
|
+
* ```
|
|
936
|
+
* @example Listen for all events uniformly (for logging/debugging)
|
|
937
|
+
* ```typescript
|
|
938
|
+
* const unsubscribe = mailpit.onEvent("*", (event) => {
|
|
939
|
+
* // Generic processing for all event types
|
|
940
|
+
* console.log(`Event ${event.Type} received`);
|
|
941
|
+
* });
|
|
942
|
+
*
|
|
943
|
+
* // Other code...
|
|
944
|
+
*
|
|
945
|
+
* // Unsubscribe listener when no longer needed
|
|
946
|
+
* unsubscribe();
|
|
947
|
+
* ```
|
|
948
|
+
*/
|
|
949
|
+
onEvent<T extends keyof MailpitEventMap>(eventType: T, listener: (event: MailpitEventMap[T]) => void): () => void;
|
|
950
|
+
/**
|
|
951
|
+
* Waits for the next event of a specific type.
|
|
952
|
+
* @remarks
|
|
953
|
+
* Automatically connects to the event stream if not already connected.
|
|
954
|
+
* Primarily intended for testing scenarios where you need to wait for a single specific event.
|
|
955
|
+
* The promise will reject if the timeout is reached before an event is received.
|
|
956
|
+
* @param eventType - The type of event to wait for.
|
|
957
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
958
|
+
* @param timeout - Timeout in milliseconds (default: 5000ms). Pass `Infinity` to disable timeout.
|
|
959
|
+
* @returns A promise that resolves with the event when received, or rejects on timeout
|
|
960
|
+
* @example Basic usage
|
|
961
|
+
* ```typescript
|
|
962
|
+
* // Create the promise before triggering the event
|
|
963
|
+
* const eventPromise = mailpit.waitForEvent("new");
|
|
964
|
+
*
|
|
965
|
+
* // Do something that triggers an email to send
|
|
966
|
+
* await mailpit.sendMessage({
|
|
967
|
+
* From: { Email: "test@example.com" },
|
|
968
|
+
* To: [{ Email: "recipient@example.com" }],
|
|
969
|
+
* Subject: "Test",
|
|
970
|
+
* });
|
|
971
|
+
*
|
|
972
|
+
* // Wait for the event confirming the message was received
|
|
973
|
+
* const event = await eventPromise;
|
|
974
|
+
* // event.Data is fully typed as MailpitMessageSummary
|
|
975
|
+
* console.log("Message received:", event.Data.Subject);
|
|
976
|
+
* ```
|
|
977
|
+
*/
|
|
978
|
+
waitForEvent<T extends Exclude<keyof MailpitEventMap, "*">>(eventType: T, timeout?: number): Promise<MailpitEventMap[T]>;
|
|
784
979
|
}
|
|
785
980
|
|
|
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 };
|
|
981
|
+
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
|
@@ -177,38 +177,7 @@ interface MailpitMessageSummaryResponse {
|
|
|
177
177
|
/** Response for the {@link MailpitClient.listMessages| listMessages()} API containing the summary of multiple messages. */
|
|
178
178
|
interface MailpitMessagesSummaryResponse {
|
|
179
179
|
/** 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
|
-
}[];
|
|
180
|
+
messages: MailpitMessageListItem[];
|
|
212
181
|
/** Total number of messages matching the current query */
|
|
213
182
|
messages_count: number;
|
|
214
183
|
/** Total number of unread messages matching current query */
|
|
@@ -224,6 +193,39 @@ interface MailpitMessagesSummaryResponse {
|
|
|
224
193
|
/** @deprecated No longer documented upstream */
|
|
225
194
|
count: number;
|
|
226
195
|
}
|
|
196
|
+
/** Represents a message item in a list or WebSocket event */
|
|
197
|
+
interface MailpitMessageListItem {
|
|
198
|
+
/** The number of attachments */
|
|
199
|
+
Attachments: number;
|
|
200
|
+
/** BCC addresses */
|
|
201
|
+
Bcc: MailpitEmailAddressResponse[];
|
|
202
|
+
/** CC addresses */
|
|
203
|
+
Cc: MailpitEmailAddressResponse[];
|
|
204
|
+
/** Created time in ISO format: 1970-01-01T00:00:00.000Z */
|
|
205
|
+
Created: string;
|
|
206
|
+
/** Sender address */
|
|
207
|
+
From: MailpitEmailAddressResponse;
|
|
208
|
+
/** Database ID */
|
|
209
|
+
ID: string;
|
|
210
|
+
/** Message ID */
|
|
211
|
+
MessageID: string;
|
|
212
|
+
/** Read status */
|
|
213
|
+
Read: boolean;
|
|
214
|
+
/** Reply-To addresses */
|
|
215
|
+
ReplyTo: MailpitEmailAddressResponse[];
|
|
216
|
+
/** Message size in bytes (total) */
|
|
217
|
+
Size: number;
|
|
218
|
+
/** Message snippet includes up to 250 characters */
|
|
219
|
+
Snippet: string;
|
|
220
|
+
/** Email subject */
|
|
221
|
+
Subject: string;
|
|
222
|
+
/** Message tags */
|
|
223
|
+
Tags: string[];
|
|
224
|
+
/** To addresses */
|
|
225
|
+
To: MailpitEmailAddressResponse[];
|
|
226
|
+
/** Username used for authentication (if provided) with the SMTP or {@link MailpitClient.sendMessage| sendMessage} */
|
|
227
|
+
Username?: string;
|
|
228
|
+
}
|
|
227
229
|
/** Response for the {@link MailpitClient.getMessageHeaders | getMessageHeaders()} API containing message headers */
|
|
228
230
|
interface MailpitMessageHeadersResponse {
|
|
229
231
|
/** Message headers */
|
|
@@ -411,6 +413,91 @@ interface MailpitAttachmentDataResponse {
|
|
|
411
413
|
/** The attachment MIME type */
|
|
412
414
|
contentType: string;
|
|
413
415
|
}
|
|
416
|
+
/** Message summary data structure returned in "new" events */
|
|
417
|
+
type MailpitMessageSummary = MailpitMessageListItem;
|
|
418
|
+
/** Statistics data structure returned in "stats" events */
|
|
419
|
+
interface MailpitStatsData {
|
|
420
|
+
/** Total number of messages in the database */
|
|
421
|
+
Total: number;
|
|
422
|
+
/** Total number of unread messages */
|
|
423
|
+
Unread: number;
|
|
424
|
+
/** Mailpit version */
|
|
425
|
+
Version: string;
|
|
426
|
+
}
|
|
427
|
+
/** Update data structure returned in "update" events */
|
|
428
|
+
interface MailpitUpdateData {
|
|
429
|
+
/** Message database ID */
|
|
430
|
+
ID: string;
|
|
431
|
+
/** Read status (if changed) */
|
|
432
|
+
Read?: boolean;
|
|
433
|
+
/** Tags (if changed) */
|
|
434
|
+
Tags?: string[];
|
|
435
|
+
}
|
|
436
|
+
/** Delete data structure returned in "delete" events */
|
|
437
|
+
interface MailpitDeleteData {
|
|
438
|
+
/** Message database ID */
|
|
439
|
+
ID: string;
|
|
440
|
+
}
|
|
441
|
+
/** Error data structure returned in "error" events */
|
|
442
|
+
interface MailpitErrorData {
|
|
443
|
+
/** Error severity level */
|
|
444
|
+
Level: string;
|
|
445
|
+
/** Error type */
|
|
446
|
+
Type: string;
|
|
447
|
+
/** Client IP address */
|
|
448
|
+
IP: string;
|
|
449
|
+
/** Error message */
|
|
450
|
+
Message: string;
|
|
451
|
+
}
|
|
452
|
+
/** Event message containing a type and data payload */
|
|
453
|
+
interface MailpitEvent<T = MailpitMessageSummary | MailpitStatsData | MailpitUpdateData | MailpitDeleteData | MailpitErrorData | null> {
|
|
454
|
+
/** Type of event being broadcast */
|
|
455
|
+
Type: string;
|
|
456
|
+
/** Event data payload */
|
|
457
|
+
Data: T;
|
|
458
|
+
}
|
|
459
|
+
/** Event for new messages */
|
|
460
|
+
interface MailpitNewMessageEvent extends MailpitEvent<MailpitMessageSummary> {
|
|
461
|
+
Type: "new";
|
|
462
|
+
}
|
|
463
|
+
/** Event for statistics updates */
|
|
464
|
+
interface MailpitStatsEvent extends MailpitEvent<MailpitStatsData> {
|
|
465
|
+
Type: "stats";
|
|
466
|
+
}
|
|
467
|
+
/** Event for message updates */
|
|
468
|
+
interface MailpitUpdateEvent extends MailpitEvent<MailpitUpdateData> {
|
|
469
|
+
Type: "update";
|
|
470
|
+
}
|
|
471
|
+
/** Event for message deletion */
|
|
472
|
+
interface MailpitDeleteEvent extends MailpitEvent<MailpitDeleteData> {
|
|
473
|
+
Type: "delete";
|
|
474
|
+
}
|
|
475
|
+
/** Event for database pruning (Data is null) */
|
|
476
|
+
interface MailpitPruneEvent extends MailpitEvent<null> {
|
|
477
|
+
Type: "prune";
|
|
478
|
+
}
|
|
479
|
+
/** Event for truncating all messages (Data is null) */
|
|
480
|
+
interface MailpitTruncateEvent extends MailpitEvent<null> {
|
|
481
|
+
Type: "truncate";
|
|
482
|
+
}
|
|
483
|
+
/** Event for client errors (SMTP/POP3 errors) */
|
|
484
|
+
interface MailpitErrorEvent extends MailpitEvent<MailpitErrorData> {
|
|
485
|
+
Type: "error";
|
|
486
|
+
}
|
|
487
|
+
/** Maps event type strings to their corresponding event interfaces */
|
|
488
|
+
interface MailpitEventMap {
|
|
489
|
+
new: MailpitNewMessageEvent;
|
|
490
|
+
stats: MailpitStatsEvent;
|
|
491
|
+
update: MailpitUpdateEvent;
|
|
492
|
+
delete: MailpitDeleteEvent;
|
|
493
|
+
prune: MailpitPruneEvent;
|
|
494
|
+
truncate: MailpitTruncateEvent;
|
|
495
|
+
error: MailpitErrorEvent;
|
|
496
|
+
/** Wildcard event type that matches all events */
|
|
497
|
+
"*": MailpitEvent;
|
|
498
|
+
}
|
|
499
|
+
/** Valid event types including specific event names and the wildcard "*" */
|
|
500
|
+
type MailpitEventType = keyof MailpitEventMap;
|
|
414
501
|
/**
|
|
415
502
|
* Client for interacting with the {@link https://mailpit.axllent.org/docs/api-v1/ | Mailpit API}.
|
|
416
503
|
* @example
|
|
@@ -422,6 +509,10 @@ interface MailpitAttachmentDataResponse {
|
|
|
422
509
|
*/
|
|
423
510
|
declare class MailpitClient {
|
|
424
511
|
private readonly axiosInstance;
|
|
512
|
+
private readonly baseURL;
|
|
513
|
+
private readonly wsURL;
|
|
514
|
+
private webSocket;
|
|
515
|
+
private eventListeners;
|
|
425
516
|
/**
|
|
426
517
|
* Creates an instance of {@link MailpitClient}.
|
|
427
518
|
* @param baseURL - The base URL of the Mailpit API.
|
|
@@ -435,8 +526,8 @@ declare class MailpitClient {
|
|
|
435
526
|
* @example Basic Auth
|
|
436
527
|
* ```typescript
|
|
437
528
|
* const mailpit = new MailpitClient("http://localhost:8025", {
|
|
438
|
-
*
|
|
439
|
-
*
|
|
529
|
+
* username: "admin",
|
|
530
|
+
* password: "supersecret"
|
|
440
531
|
* });
|
|
441
532
|
* ```
|
|
442
533
|
*/
|
|
@@ -781,6 +872,110 @@ declare class MailpitClient {
|
|
|
781
872
|
* ```
|
|
782
873
|
*/
|
|
783
874
|
renderMessageText(id?: string): Promise<string>;
|
|
875
|
+
/**
|
|
876
|
+
* @internal
|
|
877
|
+
* Connects to the WebSocket endpoint for receiving real-time events.
|
|
878
|
+
*/
|
|
879
|
+
private connectWebSocket;
|
|
880
|
+
/**
|
|
881
|
+
* @internal
|
|
882
|
+
* Adds a listener to the event listeners map.
|
|
883
|
+
* @param eventType - The type of event to listen for
|
|
884
|
+
* @param listener - The listener function to add
|
|
885
|
+
*/
|
|
886
|
+
private addListener;
|
|
887
|
+
/**
|
|
888
|
+
* @internal
|
|
889
|
+
* Removes a listener from the event listeners map.
|
|
890
|
+
* @param eventType - The type of event to remove the listener from
|
|
891
|
+
* @param listener - The listener function to remove
|
|
892
|
+
*/
|
|
893
|
+
private removeListener;
|
|
894
|
+
/**
|
|
895
|
+
* @internal
|
|
896
|
+
* Dispatches a message to listeners of a specific event type.
|
|
897
|
+
* @param eventType - The event type to dispatch to
|
|
898
|
+
* @param message - The event message
|
|
899
|
+
*/
|
|
900
|
+
private dispatchToListeners;
|
|
901
|
+
/**
|
|
902
|
+
* @internal
|
|
903
|
+
* Handles incoming WebSocket messages and dispatches them to registered listeners.
|
|
904
|
+
* @param message - The event message
|
|
905
|
+
*/
|
|
906
|
+
private handleWebSocketMessage;
|
|
907
|
+
/**
|
|
908
|
+
* Disconnects from the real-time event stream.
|
|
909
|
+
* @example
|
|
910
|
+
* ```typescript
|
|
911
|
+
* mailpit.disconnect();
|
|
912
|
+
* ```
|
|
913
|
+
*/
|
|
914
|
+
disconnect(): void;
|
|
915
|
+
/**
|
|
916
|
+
* Registers a listener for real-time events of a specific type.
|
|
917
|
+
* @remarks
|
|
918
|
+
* Automatically connects to the event stream if not already connected.
|
|
919
|
+
* @param eventType - The type of event to listen for.
|
|
920
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
921
|
+
* Use "*" to listen for all event types (Useful if processing all events uniformly (e.g., logging, debugging, metrics)).
|
|
922
|
+
* @param listener - The callback function to invoke when an event is received
|
|
923
|
+
* @returns A function to unregister the listener
|
|
924
|
+
* @example Listen for event type "new" messages (recommended)
|
|
925
|
+
* ```typescript
|
|
926
|
+
* const unsubscribe = mailpit.onEvent("new", (event) => {
|
|
927
|
+
* // event.Data is typed as MailpitMessageSummary with full type safety
|
|
928
|
+
* console.log("New message:", event.Data.Subject);
|
|
929
|
+
* });
|
|
930
|
+
*
|
|
931
|
+
* // Other code...
|
|
932
|
+
*
|
|
933
|
+
* // Unsubscribe listener when no longer needed
|
|
934
|
+
* unsubscribe();
|
|
935
|
+
* ```
|
|
936
|
+
* @example Listen for all events uniformly (for logging/debugging)
|
|
937
|
+
* ```typescript
|
|
938
|
+
* const unsubscribe = mailpit.onEvent("*", (event) => {
|
|
939
|
+
* // Generic processing for all event types
|
|
940
|
+
* console.log(`Event ${event.Type} received`);
|
|
941
|
+
* });
|
|
942
|
+
*
|
|
943
|
+
* // Other code...
|
|
944
|
+
*
|
|
945
|
+
* // Unsubscribe listener when no longer needed
|
|
946
|
+
* unsubscribe();
|
|
947
|
+
* ```
|
|
948
|
+
*/
|
|
949
|
+
onEvent<T extends keyof MailpitEventMap>(eventType: T, listener: (event: MailpitEventMap[T]) => void): () => void;
|
|
950
|
+
/**
|
|
951
|
+
* Waits for the next event of a specific type.
|
|
952
|
+
* @remarks
|
|
953
|
+
* Automatically connects to the event stream if not already connected.
|
|
954
|
+
* Primarily intended for testing scenarios where you need to wait for a single specific event.
|
|
955
|
+
* The promise will reject if the timeout is reached before an event is received.
|
|
956
|
+
* @param eventType - The type of event to wait for.
|
|
957
|
+
* Specific event types include: "new" (new messages), "stats", "update", "delete", "prune", "truncate", and "error".
|
|
958
|
+
* @param timeout - Timeout in milliseconds (default: 5000ms). Pass `Infinity` to disable timeout.
|
|
959
|
+
* @returns A promise that resolves with the event when received, or rejects on timeout
|
|
960
|
+
* @example Basic usage
|
|
961
|
+
* ```typescript
|
|
962
|
+
* // Create the promise before triggering the event
|
|
963
|
+
* const eventPromise = mailpit.waitForEvent("new");
|
|
964
|
+
*
|
|
965
|
+
* // Do something that triggers an email to send
|
|
966
|
+
* await mailpit.sendMessage({
|
|
967
|
+
* From: { Email: "test@example.com" },
|
|
968
|
+
* To: [{ Email: "recipient@example.com" }],
|
|
969
|
+
* Subject: "Test",
|
|
970
|
+
* });
|
|
971
|
+
*
|
|
972
|
+
* // Wait for the event confirming the message was received
|
|
973
|
+
* const event = await eventPromise;
|
|
974
|
+
* // event.Data is fully typed as MailpitMessageSummary
|
|
975
|
+
* console.log("Message received:", event.Data.Subject);
|
|
976
|
+
* ```
|
|
977
|
+
*/
|
|
978
|
+
waitForEvent<T extends Exclude<keyof MailpitEventMap, "*">>(eventType: T, timeout?: number): Promise<MailpitEventMap[T]>;
|
|
784
979
|
}
|
|
785
980
|
|
|
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 };
|
|
981
|
+
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailpit-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "A TypeScript client for interacting with Mailpit's REST API.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -59,23 +59,26 @@
|
|
|
59
59
|
"author": "Matthew Spahr",
|
|
60
60
|
"license": "MIT",
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"axios": "^1.
|
|
62
|
+
"axios": "^1.12.1",
|
|
63
|
+
"partysocket": "^1.1.10",
|
|
64
|
+
"ws": "^8.18.3"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
|
-
"@eslint/js": "^9.
|
|
66
|
-
"@jest/globals": "^30.0
|
|
67
|
-
"@types/node": "^22.
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"eslint
|
|
71
|
-
"jest": "^
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"typedoc
|
|
78
|
-
"
|
|
79
|
-
"typescript
|
|
67
|
+
"@eslint/js": "^9.39.2",
|
|
68
|
+
"@jest/globals": "^30.2.0",
|
|
69
|
+
"@types/node": "^22.19.5",
|
|
70
|
+
"@types/ws": "^8.18.1",
|
|
71
|
+
"dotenv": "^17.2.3",
|
|
72
|
+
"eslint": "^9.39.2",
|
|
73
|
+
"eslint-plugin-jest": "^29.12.1",
|
|
74
|
+
"jest": "^30.2.0",
|
|
75
|
+
"prettier": "^3.7.4",
|
|
76
|
+
"ts-jest": "^29.4.6",
|
|
77
|
+
"tsup": "^8.5.1",
|
|
78
|
+
"tsx": "^4.21.0",
|
|
79
|
+
"typedoc": "^0.28.15",
|
|
80
|
+
"typedoc-github-theme": "^0.3.1",
|
|
81
|
+
"typescript": "^5.9.3",
|
|
82
|
+
"typescript-eslint": "^8.52.0"
|
|
80
83
|
}
|
|
81
84
|
}
|