@vaultsandbox/client 0.5.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +612 -0
  3. package/dist/client.d.ts +231 -0
  4. package/dist/client.js +432 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/crypto/constants.d.ts +13 -0
  7. package/dist/crypto/constants.js +14 -0
  8. package/dist/crypto/constants.js.map +1 -0
  9. package/dist/crypto/decrypt.d.ts +41 -0
  10. package/dist/crypto/decrypt.js +112 -0
  11. package/dist/crypto/decrypt.js.map +1 -0
  12. package/dist/crypto/keypair.d.ts +39 -0
  13. package/dist/crypto/keypair.js +109 -0
  14. package/dist/crypto/keypair.js.map +1 -0
  15. package/dist/crypto/signature.d.ts +28 -0
  16. package/dist/crypto/signature.js +89 -0
  17. package/dist/crypto/signature.js.map +1 -0
  18. package/dist/crypto/utils.d.ts +28 -0
  19. package/dist/crypto/utils.js +60 -0
  20. package/dist/crypto/utils.js.map +1 -0
  21. package/dist/email.d.ts +63 -0
  22. package/dist/email.js +186 -0
  23. package/dist/email.js.map +1 -0
  24. package/dist/http/api-client.d.ts +145 -0
  25. package/dist/http/api-client.js +242 -0
  26. package/dist/http/api-client.js.map +1 -0
  27. package/dist/inbox.d.ts +120 -0
  28. package/dist/inbox.js +243 -0
  29. package/dist/inbox.js.map +1 -0
  30. package/dist/index.d.ts +14 -0
  31. package/dist/index.js +17 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/strategies/delivery-strategy.d.ts +29 -0
  34. package/dist/strategies/delivery-strategy.js +2 -0
  35. package/dist/strategies/delivery-strategy.js.map +1 -0
  36. package/dist/strategies/polling-strategy.d.ts +36 -0
  37. package/dist/strategies/polling-strategy.js +146 -0
  38. package/dist/strategies/polling-strategy.js.map +1 -0
  39. package/dist/strategies/sse-strategy.d.ts +49 -0
  40. package/dist/strategies/sse-strategy.js +266 -0
  41. package/dist/strategies/sse-strategy.js.map +1 -0
  42. package/dist/types/index.d.ts +434 -0
  43. package/dist/types/index.js +127 -0
  44. package/dist/types/index.js.map +1 -0
  45. package/dist/utils/email-utils.d.ts +19 -0
  46. package/dist/utils/email-utils.js +92 -0
  47. package/dist/utils/email-utils.js.map +1 -0
  48. package/dist/utils/sleep.d.ts +6 -0
  49. package/dist/utils/sleep.js +9 -0
  50. package/dist/utils/sleep.js.map +1 -0
  51. package/package.json +85 -0
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Inbox class - manages email retrieval and decryption for a single inbox
3
+ */
4
+ import type { InboxData, Keypair, WaitOptions, WaitForCountOptions, SyncStatus, RawEmail, Subscription, IEmail, ExportedInboxData } from './types/index.js';
5
+ import type { ApiClient } from './http/api-client.js';
6
+ import type { DeliveryStrategy } from './strategies/delivery-strategy.js';
7
+ /**
8
+ * Represents a single email inbox.
9
+ *
10
+ * This class provides methods for retrieving, decrypting, and managing emails
11
+ * within a specific inbox.
12
+ */
13
+ export declare class Inbox {
14
+ /** The email address of the inbox. */
15
+ readonly emailAddress: string;
16
+ /** The date and time when the inbox will expire. */
17
+ expiresAt: Date;
18
+ /** A unique identifier for the inbox. */
19
+ readonly inboxHash: string;
20
+ private keypair;
21
+ private apiClient;
22
+ private serverPublicKey;
23
+ private strategy;
24
+ /**
25
+ * @internal
26
+ * Do not construct this class directly. Use `VaultSandboxClient.createInbox()` instead.
27
+ */
28
+ constructor(inboxData: InboxData, keypair: Keypair, apiClient: ApiClient, serverPublicKey: string);
29
+ /**
30
+ * @internal
31
+ * Sets the delivery strategy for this inbox.
32
+ * @param strategy - The delivery strategy to use.
33
+ */
34
+ setStrategy(strategy: DeliveryStrategy): void;
35
+ /**
36
+ * Retrieves all emails from the inbox.
37
+ *
38
+ * @returns A promise that resolves to an array of `Email` instances.
39
+ */
40
+ listEmails(): Promise<IEmail[]>;
41
+ /**
42
+ * Retrieves a specific email by its ID.
43
+ *
44
+ * @param emailId - The ID of the email to retrieve.
45
+ * @returns A promise that resolves to an `Email` instance.
46
+ */
47
+ getEmail(emailId: string): Promise<IEmail>;
48
+ /**
49
+ * Retrieves the raw, decrypted source of a specific email.
50
+ *
51
+ * @param emailId - The ID of the email to retrieve.
52
+ * @returns A promise that resolves to the raw email data.
53
+ */
54
+ getRawEmail(emailId: string): Promise<RawEmail>;
55
+ /**
56
+ * Waits for an email that matches the specified criteria.
57
+ *
58
+ * This method uses the configured delivery strategy (SSE or polling) to wait
59
+ * for an email to arrive.
60
+ *
61
+ * @param options - Options for waiting for the email.
62
+ * @returns A promise that resolves to the matched `Email` instance.
63
+ */
64
+ waitForEmail(options?: WaitOptions): Promise<IEmail>;
65
+ /**
66
+ * Waits until the inbox contains at least a specified number of emails.
67
+ *
68
+ * This method uses the configured delivery strategy (SSE or polling) to
69
+ * efficiently wait for emails to arrive instead of constantly polling the API.
70
+ *
71
+ * @param count - The number of emails to wait for.
72
+ * @param options - Options for waiting.
73
+ * @returns A promise that resolves when the email count is reached.
74
+ */
75
+ waitForEmailCount(count: number, options?: WaitForCountOptions): Promise<void>;
76
+ /**
77
+ * Subscribes to new emails as they arrive in the inbox.
78
+ *
79
+ * This method uses the configured delivery strategy (SSE or polling) to
80
+ * provide real-time email notifications.
81
+ *
82
+ * @param callback - A function to call with the new `Email` instance.
83
+ * @returns A `Subscription` object with an `unsubscribe` method.
84
+ */
85
+ onNewEmail(callback: (email: IEmail) => void | Promise<void>): Subscription;
86
+ /**
87
+ * Marks a specific email as read.
88
+ *
89
+ * @param emailId - The ID of the email to mark as read.
90
+ * @returns A promise that resolves when the email is marked as read.
91
+ */
92
+ markEmailAsRead(emailId: string): Promise<void>;
93
+ /**
94
+ * Deletes a specific email from the inbox.
95
+ *
96
+ * @param emailId - The ID of the email to delete.
97
+ * @returns A promise that resolves when the email is deleted.
98
+ */
99
+ deleteEmail(emailId: string): Promise<void>;
100
+ /**
101
+ * Deletes the entire inbox and all its emails.
102
+ *
103
+ * @returns A promise that resolves when the inbox is deleted.
104
+ */
105
+ delete(): Promise<void>;
106
+ /**
107
+ * Exports this inbox, including its key material, for backup/sharing.
108
+ * Keys are returned in plain base64 to keep import/export symmetric.
109
+ */
110
+ export(): ExportedInboxData;
111
+ /**
112
+ * Retrieves the synchronization status of the inbox.
113
+ *
114
+ * This includes the number of emails and a hash of the email list, which
115
+ * can be used to efficiently check for changes.
116
+ *
117
+ * @returns A promise that resolves to the sync status.
118
+ */
119
+ getSyncStatus(): Promise<SyncStatus>;
120
+ }
package/dist/inbox.js ADDED
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Inbox class - manages email retrieval and decryption for a single inbox
3
+ */
4
+ import createDebug from 'debug';
5
+ import { decryptRaw } from './crypto/decrypt.js';
6
+ import { decryptEmailData } from './utils/email-utils.js';
7
+ import { toBase64 } from './crypto/utils.js';
8
+ import { TimeoutError, StrategyError } from './types/index.js';
9
+ const debug = createDebug('vaultsandbox:inbox');
10
+ /**
11
+ * Represents a single email inbox.
12
+ *
13
+ * This class provides methods for retrieving, decrypting, and managing emails
14
+ * within a specific inbox.
15
+ */
16
+ export class Inbox {
17
+ /** The email address of the inbox. */
18
+ emailAddress;
19
+ /** The date and time when the inbox will expire. */
20
+ expiresAt;
21
+ /** A unique identifier for the inbox. */
22
+ inboxHash;
23
+ keypair;
24
+ apiClient;
25
+ serverPublicKey;
26
+ strategy = null;
27
+ /**
28
+ * @internal
29
+ * Do not construct this class directly. Use `VaultSandboxClient.createInbox()` instead.
30
+ */
31
+ constructor(inboxData, keypair, apiClient, serverPublicKey) {
32
+ this.emailAddress = inboxData.emailAddress;
33
+ this.inboxHash = inboxData.inboxHash;
34
+ this.expiresAt = new Date(inboxData.expiresAt);
35
+ this.keypair = keypair;
36
+ this.apiClient = apiClient;
37
+ this.serverPublicKey = serverPublicKey;
38
+ debug('Created inbox for %s (expires: %s)', this.emailAddress, this.expiresAt.toISOString());
39
+ }
40
+ /**
41
+ * @internal
42
+ * Sets the delivery strategy for this inbox.
43
+ * @param strategy - The delivery strategy to use.
44
+ */
45
+ setStrategy(strategy) {
46
+ this.strategy = strategy;
47
+ debug('Set delivery strategy for inbox %s', this.emailAddress);
48
+ }
49
+ /**
50
+ * Retrieves all emails from the inbox.
51
+ *
52
+ * @returns A promise that resolves to an array of `Email` instances.
53
+ */
54
+ async listEmails() {
55
+ debug('Listing emails for inbox %s', this.emailAddress);
56
+ const emailsData = await this.apiClient.listEmails(this.emailAddress);
57
+ debug('Retrieved %d raw email data entries', emailsData.length);
58
+ const emails = [];
59
+ for (const emailData of emailsData) {
60
+ const email = await decryptEmailData(emailData, this.keypair, this.emailAddress, this.apiClient);
61
+ emails.push(email);
62
+ }
63
+ debug('Successfully decrypted %d emails for inbox %s', emails.length, this.emailAddress);
64
+ return emails;
65
+ }
66
+ /**
67
+ * Retrieves a specific email by its ID.
68
+ *
69
+ * @param emailId - The ID of the email to retrieve.
70
+ * @returns A promise that resolves to an `Email` instance.
71
+ */
72
+ async getEmail(emailId) {
73
+ debug('Retrieving email %s from inbox %s', emailId, this.emailAddress);
74
+ const emailData = await this.apiClient.getEmail(this.emailAddress, emailId);
75
+ const email = await decryptEmailData(emailData, this.keypair, this.emailAddress, this.apiClient);
76
+ debug('Successfully retrieved and decrypted email %s', emailId);
77
+ return email;
78
+ }
79
+ /**
80
+ * Retrieves the raw, decrypted source of a specific email.
81
+ *
82
+ * @param emailId - The ID of the email to retrieve.
83
+ * @returns A promise that resolves to the raw email data.
84
+ */
85
+ async getRawEmail(emailId) {
86
+ debug('Retrieving raw email %s from inbox %s', emailId, this.emailAddress);
87
+ const rawEmailData = await this.apiClient.getRawEmail(this.emailAddress, emailId);
88
+ const raw = await decryptRaw(rawEmailData.encryptedRaw, this.keypair);
89
+ debug('Successfully retrieved and decrypted raw email %s (%d characters)', emailId, raw.length);
90
+ return { id: rawEmailData.id, raw };
91
+ }
92
+ /**
93
+ * Waits for an email that matches the specified criteria.
94
+ *
95
+ * This method uses the configured delivery strategy (SSE or polling) to wait
96
+ * for an email to arrive.
97
+ *
98
+ * @param options - Options for waiting for the email.
99
+ * @returns A promise that resolves to the matched `Email` instance.
100
+ */
101
+ async waitForEmail(options = {}) {
102
+ if (!this.strategy) {
103
+ throw new StrategyError('No delivery strategy set. Call setStrategy() first.');
104
+ }
105
+ debug('Waiting for email in inbox %s with options: %O', this.emailAddress, options);
106
+ const email = await this.strategy.waitForEmail(this.emailAddress, this.inboxHash, this.keypair, options);
107
+ debug('Successfully received email %s in inbox %s', email.id, this.emailAddress);
108
+ return email;
109
+ }
110
+ /**
111
+ * Waits until the inbox contains at least a specified number of emails.
112
+ *
113
+ * This method uses the configured delivery strategy (SSE or polling) to
114
+ * efficiently wait for emails to arrive instead of constantly polling the API.
115
+ *
116
+ * @param count - The number of emails to wait for.
117
+ * @param options - Options for waiting.
118
+ * @returns A promise that resolves when the email count is reached.
119
+ */
120
+ async waitForEmailCount(count, options = {}) {
121
+ const timeout = options.timeout ?? 30000;
122
+ debug('Waiting for %d emails in inbox %s (timeout: %dms)', count, this.emailAddress, timeout);
123
+ // Check if we already have enough emails
124
+ const syncStatus = await this.getSyncStatus();
125
+ if (syncStatus.emailCount >= count) {
126
+ debug('Target email count %d already reached in inbox %s', count, this.emailAddress);
127
+ return;
128
+ }
129
+ return new Promise((resolve, reject) => {
130
+ let subscription;
131
+ let timeoutTimer;
132
+ // Centralized cleanup to prevent memory leaks
133
+ const cleanup = () => {
134
+ if (timeoutTimer)
135
+ clearTimeout(timeoutTimer);
136
+ if (subscription)
137
+ subscription.unsubscribe();
138
+ };
139
+ timeoutTimer = setTimeout(() => {
140
+ cleanup();
141
+ debug('Timeout reached while waiting for %d emails in inbox %s', count, this.emailAddress);
142
+ reject(new TimeoutError(`Inbox did not receive ${count} emails within timeout`));
143
+ }, timeout);
144
+ subscription = this.onNewEmail(async () => {
145
+ try {
146
+ const syncStatus = await this.getSyncStatus();
147
+ debug('Current email count in inbox %s: %d', this.emailAddress, syncStatus.emailCount);
148
+ if (syncStatus.emailCount >= count) {
149
+ cleanup();
150
+ debug('Target email count %d reached in inbox %s', count, this.emailAddress);
151
+ resolve();
152
+ }
153
+ }
154
+ catch (error) {
155
+ cleanup();
156
+ debug('Error checking sync status: %O', error);
157
+ reject(error);
158
+ }
159
+ });
160
+ });
161
+ }
162
+ /**
163
+ * Subscribes to new emails as they arrive in the inbox.
164
+ *
165
+ * This method uses the configured delivery strategy (SSE or polling) to
166
+ * provide real-time email notifications.
167
+ *
168
+ * @param callback - A function to call with the new `Email` instance.
169
+ * @returns A `Subscription` object with an `unsubscribe` method.
170
+ */
171
+ onNewEmail(callback) {
172
+ if (!this.strategy) {
173
+ throw new StrategyError('No delivery strategy set. Call setStrategy() first.');
174
+ }
175
+ debug('Subscribing to new emails for inbox %s', this.emailAddress);
176
+ return this.strategy.subscribe(this.emailAddress, this.inboxHash, this.keypair, callback);
177
+ }
178
+ /**
179
+ * Marks a specific email as read.
180
+ *
181
+ * @param emailId - The ID of the email to mark as read.
182
+ * @returns A promise that resolves when the email is marked as read.
183
+ */
184
+ async markEmailAsRead(emailId) {
185
+ debug('Marking email %s as read in inbox %s', emailId, this.emailAddress);
186
+ await this.apiClient.markEmailAsRead(this.emailAddress, emailId);
187
+ debug('Successfully marked email %s as read', emailId);
188
+ }
189
+ /**
190
+ * Deletes a specific email from the inbox.
191
+ *
192
+ * @param emailId - The ID of the email to delete.
193
+ * @returns A promise that resolves when the email is deleted.
194
+ */
195
+ async deleteEmail(emailId) {
196
+ debug('Deleting email %s from inbox %s', emailId, this.emailAddress);
197
+ await this.apiClient.deleteEmail(this.emailAddress, emailId);
198
+ debug('Successfully deleted email %s', emailId);
199
+ }
200
+ /**
201
+ * Deletes the entire inbox and all its emails.
202
+ *
203
+ * @returns A promise that resolves when the inbox is deleted.
204
+ */
205
+ async delete() {
206
+ debug('Deleting inbox %s', this.emailAddress);
207
+ await this.apiClient.deleteInbox(this.emailAddress);
208
+ debug('Successfully deleted inbox %s', this.emailAddress);
209
+ }
210
+ /**
211
+ * Exports this inbox, including its key material, for backup/sharing.
212
+ * Keys are returned in plain base64 to keep import/export symmetric.
213
+ */
214
+ export() {
215
+ debug('Exporting inbox %s with key material', this.emailAddress);
216
+ const exportedData = {
217
+ emailAddress: this.emailAddress,
218
+ expiresAt: this.expiresAt.toISOString(),
219
+ inboxHash: this.inboxHash,
220
+ serverSigPk: this.serverPublicKey,
221
+ publicKeyB64: toBase64(this.keypair.publicKey),
222
+ secretKeyB64: toBase64(this.keypair.secretKey),
223
+ exportedAt: new Date().toISOString(),
224
+ };
225
+ debug('Successfully exported inbox %s', this.emailAddress);
226
+ return exportedData;
227
+ }
228
+ /**
229
+ * Retrieves the synchronization status of the inbox.
230
+ *
231
+ * This includes the number of emails and a hash of the email list, which
232
+ * can be used to efficiently check for changes.
233
+ *
234
+ * @returns A promise that resolves to the sync status.
235
+ */
236
+ async getSyncStatus() {
237
+ debug('Retrieving sync status for inbox %s', this.emailAddress);
238
+ const syncStatus = await this.apiClient.getSyncStatus(this.emailAddress);
239
+ debug('Sync status for inbox %s: %d emails, hash: %s', this.emailAddress, syncStatus.emailCount, syncStatus.emailsHash);
240
+ return syncStatus;
241
+ }
242
+ }
243
+ //# sourceMappingURL=inbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox.js","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * VaultSandbox Client SDK - Public API
3
+ *
4
+ * Email testing made effortless
5
+ */
6
+ export { VaultSandboxClient, InboxMonitor } from './client.js';
7
+ export { Inbox } from './inbox.js';
8
+ export { Email } from './email.js';
9
+ export type { ClientConfig, CreateInboxOptions, InboxData, SyncStatus, WaitOptions, WaitForCountOptions, IEmail, AttachmentData, RawEmail, SPFResult, DKIMResult, DMARCResult, ReverseDNSResult, AuthResultsData, AuthResults, AuthValidation, ServerInfo, Subscription, ExportedInboxData, } from './types/index.js';
10
+ export { VaultSandboxError, ApiError, NetworkError, TimeoutError, DecryptionError, SignatureVerificationError, InboxNotFoundError, EmailNotFoundError, InboxAlreadyExistsError, InvalidImportDataError, StrategyError, SSEError, } from './types/index.js';
11
+ export { generateKeypair } from './crypto/keypair.js';
12
+ export { decrypt, decryptMetadata, decryptParsed, decryptRaw } from './crypto/decrypt.js';
13
+ export { verifySignature, verifySignatureSafe } from './crypto/signature.js';
14
+ export { toBase64Url, fromBase64Url } from './crypto/utils.js';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * VaultSandbox Client SDK - Public API
3
+ *
4
+ * Email testing made effortless
5
+ */
6
+ // Main classes
7
+ export { VaultSandboxClient, InboxMonitor } from './client.js';
8
+ export { Inbox } from './inbox.js';
9
+ export { Email } from './email.js';
10
+ // Errors - all custom errors should be exported for proper error handling
11
+ export { VaultSandboxError, ApiError, NetworkError, TimeoutError, DecryptionError, SignatureVerificationError, InboxNotFoundError, EmailNotFoundError, InboxAlreadyExistsError, InvalidImportDataError, StrategyError, SSEError, } from './types/index.js';
12
+ // Crypto utilities (for advanced users)
13
+ export { generateKeypair } from './crypto/keypair.js';
14
+ export { decrypt, decryptMetadata, decryptParsed, decryptRaw } from './crypto/decrypt.js';
15
+ export { verifySignature, verifySignatureSafe } from './crypto/signature.js';
16
+ export { toBase64Url, fromBase64Url } from './crypto/utils.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAe;AACf,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAyBnC,0EAA0E;AAC1E,OAAO,EACL,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,EACtB,aAAa,EACb,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAE1B,wCAAwC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { IEmail, WaitOptions, Subscription, Keypair } from '../types/index.js';
2
+ /**
3
+ * DeliveryStrategy defines the interface for email delivery mechanisms.
4
+ * Implementations include SSE (real-time) and Polling (fallback).
5
+ */
6
+ export interface DeliveryStrategy {
7
+ /**
8
+ * Wait for an email matching the given options
9
+ * @param emailAddress - The inbox email address
10
+ * @param inboxHash - The inbox hash for SSE subscription
11
+ * @param keypair - Keypair for decryption
12
+ * @param options - Wait options including timeout and filters
13
+ * @returns Promise resolving to the matched email
14
+ */
15
+ waitForEmail(emailAddress: string, inboxHash: string, keypair: Keypair, options: WaitOptions): Promise<IEmail>;
16
+ /**
17
+ * Subscribe to new email notifications
18
+ * @param emailAddress - The inbox email address
19
+ * @param inboxHash - The inbox hash for SSE subscription
20
+ * @param keypair - Keypair for decryption
21
+ * @param callback - Function to call when new email arrives
22
+ * @returns Subscription object with unsubscribe method
23
+ */
24
+ subscribe(emailAddress: string, inboxHash: string, keypair: Keypair, callback: (email: IEmail) => void | Promise<void>): Subscription;
25
+ /**
26
+ * Close and cleanup resources
27
+ */
28
+ close(): void;
29
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=delivery-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-strategy.js","sourceRoot":"","sources":["../../src/strategies/delivery-strategy.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * PollingStrategy - Smart polling implementation with exponential backoff
3
+ */
4
+ import type { ApiClient } from '../http/api-client.js';
5
+ import type { Keypair, IEmail, WaitOptions, Subscription } from '../types/index.js';
6
+ import type { DeliveryStrategy } from './delivery-strategy.js';
7
+ export interface PollingConfig {
8
+ initialInterval?: number;
9
+ maxBackoff?: number;
10
+ backoffMultiplier?: number;
11
+ jitterFactor?: number;
12
+ }
13
+ export declare class PollingStrategy implements DeliveryStrategy {
14
+ private apiClient;
15
+ private initialInterval;
16
+ private maxBackoff;
17
+ private backoffMultiplier;
18
+ private jitterFactor;
19
+ constructor(apiClient: ApiClient, config?: PollingConfig);
20
+ /**
21
+ * Waits for an email matching the specified criteria using smart polling
22
+ */
23
+ waitForEmail(emailAddress: string, _inboxHash: string, keypair: Keypair, options?: WaitOptions): Promise<IEmail>;
24
+ /**
25
+ * Decrypts a list of email data objects
26
+ */
27
+ private decryptEmails;
28
+ /**
29
+ * Subscribe to new email notifications (polling-based)
30
+ */
31
+ subscribe(emailAddress: string, _inboxHash: string, keypair: Keypair, callback: (email: IEmail) => void | Promise<void>): Subscription;
32
+ /**
33
+ * Close and cleanup resources
34
+ */
35
+ close(): void;
36
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * PollingStrategy - Smart polling implementation with exponential backoff
3
+ */
4
+ import createDebug from 'debug';
5
+ import { TimeoutError, InboxNotFoundError } from '../types/index.js';
6
+ import { decryptEmailData, findMatchingEmail } from '../utils/email-utils.js';
7
+ import { sleep } from '../utils/sleep.js';
8
+ const debug = createDebug('vaultsandbox:polling-strategy');
9
+ export class PollingStrategy {
10
+ apiClient;
11
+ initialInterval;
12
+ maxBackoff;
13
+ backoffMultiplier;
14
+ jitterFactor;
15
+ constructor(apiClient, config = {}) {
16
+ this.apiClient = apiClient;
17
+ this.initialInterval = config.initialInterval ?? 2000;
18
+ this.maxBackoff = config.maxBackoff ?? 30000;
19
+ this.backoffMultiplier = config.backoffMultiplier ?? 1.5;
20
+ this.jitterFactor = config.jitterFactor ?? 0.3;
21
+ }
22
+ /**
23
+ * Waits for an email matching the specified criteria using smart polling
24
+ */
25
+ async waitForEmail(emailAddress, _inboxHash, keypair, options = {}) {
26
+ const timeout = options.timeout ?? 30000;
27
+ const pollInterval = options.pollInterval ?? this.initialInterval;
28
+ const startTime = Date.now();
29
+ let lastHash = null;
30
+ let currentBackoff = pollInterval;
31
+ while (Date.now() - startTime < timeout) {
32
+ try {
33
+ // Check sync status to see if there are new emails (lightweight check)
34
+ const syncStatus = await this.apiClient.getSyncStatus(emailAddress);
35
+ // If hash changed or first check, fetch and check emails
36
+ if (lastHash === null || syncStatus.emailsHash !== lastHash) {
37
+ lastHash = syncStatus.emailsHash;
38
+ if (syncStatus.emailCount > 0) {
39
+ // Hash changed - fetch full email list
40
+ const emailsData = await this.apiClient.listEmails(emailAddress);
41
+ const emails = await this.decryptEmails(emailsData, keypair, emailAddress);
42
+ const matchingEmail = findMatchingEmail(emails, options);
43
+ if (matchingEmail) {
44
+ return matchingEmail;
45
+ }
46
+ }
47
+ // Reset backoff when we detect changes
48
+ currentBackoff = pollInterval;
49
+ }
50
+ // Calculate remaining time before timeout
51
+ const remainingTime = timeout - (Date.now() - startTime);
52
+ // If we've already exceeded timeout, exit immediately
53
+ if (remainingTime <= 0) {
54
+ break;
55
+ }
56
+ // Calculate wait time with exponential backoff and jitter
57
+ const jitter = Math.random() * this.jitterFactor * currentBackoff;
58
+ const desiredWaitTime = Math.min(currentBackoff + jitter, this.maxBackoff);
59
+ // Limit sleep to remaining time to avoid overshooting timeout
60
+ const waitTime = Math.min(desiredWaitTime, remainingTime);
61
+ // Wait before next poll
62
+ await sleep(waitTime);
63
+ // Increase backoff for next iteration (if no changes detected)
64
+ if (syncStatus.emailsHash === lastHash) {
65
+ currentBackoff = Math.min(currentBackoff * this.backoffMultiplier, this.maxBackoff);
66
+ }
67
+ }
68
+ catch (error) {
69
+ // Handle 404 (inbox deleted) or other errors
70
+ if (error && typeof error === 'object' && 'statusCode' in error) {
71
+ const apiError = error;
72
+ if (apiError.statusCode === 404) {
73
+ throw new InboxNotFoundError('Inbox not found or has been deleted');
74
+ }
75
+ }
76
+ throw error;
77
+ }
78
+ }
79
+ throw new TimeoutError('No matching email received within timeout');
80
+ }
81
+ /**
82
+ * Decrypts a list of email data objects
83
+ */
84
+ async decryptEmails(emailsData, keypair, emailAddress) {
85
+ const emails = [];
86
+ for (const emailData of emailsData) {
87
+ const email = await decryptEmailData(emailData, keypair, emailAddress, this.apiClient);
88
+ emails.push(email);
89
+ }
90
+ return emails;
91
+ }
92
+ /**
93
+ * Subscribe to new email notifications (polling-based)
94
+ */
95
+ subscribe(emailAddress, _inboxHash, keypair, callback) {
96
+ let isActive = true;
97
+ const seenEmails = new Set();
98
+ // Start polling loop
99
+ const poll = async () => {
100
+ while (isActive) {
101
+ try {
102
+ const emailsData = await this.apiClient.listEmails(emailAddress);
103
+ const emails = await this.decryptEmails(emailsData, keypair, emailAddress);
104
+ // Notify about new emails we haven't seen
105
+ for (const email of emails) {
106
+ if (!seenEmails.has(email.id)) {
107
+ seenEmails.add(email.id);
108
+ try {
109
+ const result = callback(email);
110
+ // Handle case where callback returns a promise
111
+ if (result instanceof Promise) {
112
+ result.catch((error) => {
113
+ debug('Error in async subscription callback: %O', error);
114
+ });
115
+ }
116
+ }
117
+ catch (error) {
118
+ debug('Error in subscription callback: %O', error);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ catch (error) {
124
+ debug('Error polling for emails: %O', error);
125
+ }
126
+ if (isActive) {
127
+ await sleep(this.initialInterval);
128
+ }
129
+ }
130
+ };
131
+ // Start polling
132
+ poll();
133
+ return {
134
+ unsubscribe: () => {
135
+ isActive = false;
136
+ },
137
+ };
138
+ }
139
+ /**
140
+ * Close and cleanup resources
141
+ */
142
+ close() {
143
+ // Polling strategy has no persistent connections to close
144
+ }
145
+ }
146
+ //# sourceMappingURL=polling-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polling-strategy.js","sourceRoot":"","sources":["../../src/strategies/polling-strategy.ts"],"names":[],"mappings":"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"}