@mailhooks/sdk 1.0.3 → 1.0.4

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 CHANGED
@@ -99,6 +99,47 @@ const attachment = await mailhooks.emails.downloadAttachment('email-id', 'attach
99
99
  // attachment.contentType contains the MIME type
100
100
  ```
101
101
 
102
+ #### Wait for Email
103
+
104
+ Wait for an email that matches specific filters. Useful for testing and automation.
105
+
106
+ ```typescript
107
+ // Basic usage - wait for email from specific sender
108
+ const email = await mailhooks.emails.waitFor({
109
+ filter: { from: 'noreply@example.com' },
110
+ timeout: 30000, // 30 seconds
111
+ pollInterval: 2000, // Check every 2 seconds
112
+ });
113
+
114
+ // Advanced usage with all options
115
+ const email = await mailhooks.emails.waitFor({
116
+ filter: {
117
+ from: 'noreply@example.com',
118
+ to: 'test@yourdomain.com',
119
+ subject: 'Order Confirmation',
120
+ },
121
+ lookbackWindow: 10000, // Only consider emails from last 10 seconds
122
+ initialDelay: 5000, // Wait 5 seconds before first check
123
+ timeout: 60000, // Total timeout of 60 seconds
124
+ pollInterval: 3000, // Check every 3 seconds
125
+ maxRetries: 20, // Stop after 20 attempts
126
+ });
127
+ ```
128
+
129
+ **Options:**
130
+ - `filter`: Same filters as `list()` method (from, to, subject, startDate, endDate)
131
+ - `lookbackWindow`: How far back to look for emails on first check (default: 10000ms)
132
+ - `initialDelay`: Delay before starting to poll (default: 0ms)
133
+ - `timeout`: Maximum time to wait before throwing error (default: 30000ms)
134
+ - `pollInterval`: Time between checks (default: 1000ms)
135
+ - `maxRetries`: Maximum number of polling attempts (default: unlimited)
136
+
137
+ **Key Features:**
138
+ - Returns immediately if a matching email already exists (within lookback window)
139
+ - Prevents returning old emails by using the lookback window
140
+ - Efficiently tracks checked emails to avoid duplicates
141
+ - Throws error on timeout or max retries exceeded
142
+
102
143
  ## Types
103
144
 
104
145
  The SDK includes comprehensive TypeScript types:
@@ -1,5 +1,5 @@
1
1
  import { MailhooksClient } from '../client';
2
- import { Email, EmailContent, EmailsResponse, EmailListParams, DownloadResponse } from '../types';
2
+ import { Email, EmailContent, EmailsResponse, EmailListParams, DownloadResponse, WaitForOptions } from '../types';
3
3
  export declare class EmailsResource extends MailhooksClient {
4
4
  /**
5
5
  * Get a paginated list of emails
@@ -21,5 +21,31 @@ export declare class EmailsResource extends MailhooksClient {
21
21
  * Download a specific attachment from an email
22
22
  */
23
23
  downloadAttachment(emailId: string, attachmentId: string): Promise<DownloadResponse>;
24
+ /**
25
+ * Wait for an email that matches the given filters
26
+ *
27
+ * @param options - Options for waiting including filters, timeouts, and delays
28
+ * @returns The first email that matches the filters
29
+ * @throws Error if timeout is reached or max retries exceeded
30
+ *
31
+ * @example
32
+ * // Wait for an email from a specific sender (only considers emails from last 10 seconds)
33
+ * const email = await mailhooks.emails.waitFor({
34
+ * filter: { from: 'test@example.com' },
35
+ * timeout: 30000, // 30 seconds
36
+ * pollInterval: 2000, // Check every 2 seconds
37
+ * lookbackWindow: 10000, // Only consider emails from last 10 seconds
38
+ * });
39
+ *
40
+ * @example
41
+ * // Wait with initial delay (useful when you know email will take time)
42
+ * const email = await mailhooks.emails.waitFor({
43
+ * filter: { subject: 'Order Confirmation' },
44
+ * initialDelay: 5000, // Wait 5 seconds before first check
45
+ * timeout: 60000,
46
+ * lookbackWindow: 5000, // Only consider very recent emails
47
+ * });
48
+ */
49
+ waitFor(options?: WaitForOptions): Promise<Email>;
24
50
  }
25
51
  //# sourceMappingURL=emails.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"emails.d.ts","sourceRoot":"","sources":["../../src/resources/emails.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,KAAK,EACL,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAElB,qBAAa,cAAe,SAAQ,eAAe;IACjD;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAyB7D;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAI/C;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIxD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAS7D;;OAEG;IACG,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC;CAoB7B"}
1
+ {"version":3,"file":"emails.d.ts","sourceRoot":"","sources":["../../src/resources/emails.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,KAAK,EACL,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACf,MAAM,UAAU,CAAC;AAElB,qBAAa,cAAe,SAAQ,eAAe;IACjD;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAyB7D;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAI/C;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIxD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAS7D;;OAEG;IACG,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC;IAqB5B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,OAAO,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,KAAK,CAAC;CA8F5D"}
@@ -75,5 +75,109 @@ class EmailsResource extends client_1.MailhooksClient {
75
75
  contentType: response.headers['content-type'],
76
76
  };
77
77
  }
78
+ /**
79
+ * Wait for an email that matches the given filters
80
+ *
81
+ * @param options - Options for waiting including filters, timeouts, and delays
82
+ * @returns The first email that matches the filters
83
+ * @throws Error if timeout is reached or max retries exceeded
84
+ *
85
+ * @example
86
+ * // Wait for an email from a specific sender (only considers emails from last 10 seconds)
87
+ * const email = await mailhooks.emails.waitFor({
88
+ * filter: { from: 'test@example.com' },
89
+ * timeout: 30000, // 30 seconds
90
+ * pollInterval: 2000, // Check every 2 seconds
91
+ * lookbackWindow: 10000, // Only consider emails from last 10 seconds
92
+ * });
93
+ *
94
+ * @example
95
+ * // Wait with initial delay (useful when you know email will take time)
96
+ * const email = await mailhooks.emails.waitFor({
97
+ * filter: { subject: 'Order Confirmation' },
98
+ * initialDelay: 5000, // Wait 5 seconds before first check
99
+ * timeout: 60000,
100
+ * lookbackWindow: 5000, // Only consider very recent emails
101
+ * });
102
+ */
103
+ async waitFor(options = {}) {
104
+ const { filter = {}, timeout = 30000, // Default 30 seconds
105
+ pollInterval = 1000, // Default poll every 1 second
106
+ maxRetries = null, initialDelay = 0, lookbackWindow = 10000, // Default 10 seconds lookback
107
+ } = options;
108
+ const startTime = Date.now();
109
+ let retries = 0;
110
+ let lastCheckedTime = null;
111
+ // Helper function to check for matching emails
112
+ const checkForEmail = async (isFirstCheck = false) => {
113
+ try {
114
+ // Calculate the time window for filtering
115
+ const now = new Date();
116
+ let startDateFilter;
117
+ if (isFirstCheck && lookbackWindow) {
118
+ // On first check, only look back the specified window
119
+ startDateFilter = new Date(now.getTime() - lookbackWindow).toISOString();
120
+ }
121
+ else if (lastCheckedTime) {
122
+ // On subsequent checks, look for emails since last check
123
+ startDateFilter = lastCheckedTime.toISOString();
124
+ }
125
+ else {
126
+ // Fallback to lookback window
127
+ startDateFilter = new Date(now.getTime() - lookbackWindow).toISOString();
128
+ }
129
+ // Merge the time filter with user-provided filters
130
+ const searchFilter = {
131
+ ...filter,
132
+ startDate: startDateFilter,
133
+ };
134
+ const response = await this.list({
135
+ filter: searchFilter,
136
+ perPage: 10,
137
+ sort: { field: 'createdAt', order: 'desc' },
138
+ });
139
+ // Update last checked time for next iteration
140
+ lastCheckedTime = now;
141
+ if (response.data.length > 0) {
142
+ // Return the most recent matching email
143
+ return response.data[0];
144
+ }
145
+ return null;
146
+ }
147
+ catch (error) {
148
+ // Log error but continue polling
149
+ console.warn('Error checking for email:', error);
150
+ return null;
151
+ }
152
+ };
153
+ // Check immediately for existing emails (before any delay)
154
+ const existingEmail = await checkForEmail(true);
155
+ if (existingEmail) {
156
+ return existingEmail;
157
+ }
158
+ // Apply initial delay if specified
159
+ if (initialDelay > 0) {
160
+ await new Promise(resolve => setTimeout(resolve, initialDelay));
161
+ }
162
+ // Start polling
163
+ while (true) {
164
+ // Check timeout
165
+ if (timeout && Date.now() - startTime > timeout) {
166
+ throw new Error(`Timeout waiting for email after ${timeout}ms`);
167
+ }
168
+ // Check max retries
169
+ if (maxRetries !== null && retries >= maxRetries) {
170
+ throw new Error(`Max retries (${maxRetries}) exceeded waiting for email`);
171
+ }
172
+ // Check for email
173
+ const email = await checkForEmail();
174
+ if (email) {
175
+ return email;
176
+ }
177
+ // Wait before next poll
178
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
179
+ retries++;
180
+ }
181
+ }
78
182
  }
79
183
  exports.EmailsResource = EmailsResource;
package/dist/types.d.ts CHANGED
@@ -53,4 +53,12 @@ export interface DownloadResponse {
53
53
  filename?: string;
54
54
  contentType?: string;
55
55
  }
56
+ export interface WaitForOptions {
57
+ filter?: EmailFilter;
58
+ timeout?: number;
59
+ pollInterval?: number;
60
+ maxRetries?: number;
61
+ initialDelay?: number;
62
+ lookbackWindow?: number;
63
+ }
56
64
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,IAAI,EAAE,KAAK,EAAE,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,IAAI,EAAE,KAAK,EAAE,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailhooks/sdk",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "TypeScript SDK for Mailhooks API",
5
5
  "publishConfig": {
6
6
  "access": "public"