@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.
- package/LICENSE +21 -0
- package/README.md +612 -0
- package/dist/client.d.ts +231 -0
- package/dist/client.js +432 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto/constants.d.ts +13 -0
- package/dist/crypto/constants.js +14 -0
- package/dist/crypto/constants.js.map +1 -0
- package/dist/crypto/decrypt.d.ts +41 -0
- package/dist/crypto/decrypt.js +112 -0
- package/dist/crypto/decrypt.js.map +1 -0
- package/dist/crypto/keypair.d.ts +39 -0
- package/dist/crypto/keypair.js +109 -0
- package/dist/crypto/keypair.js.map +1 -0
- package/dist/crypto/signature.d.ts +28 -0
- package/dist/crypto/signature.js +89 -0
- package/dist/crypto/signature.js.map +1 -0
- package/dist/crypto/utils.d.ts +28 -0
- package/dist/crypto/utils.js +60 -0
- package/dist/crypto/utils.js.map +1 -0
- package/dist/email.d.ts +63 -0
- package/dist/email.js +186 -0
- package/dist/email.js.map +1 -0
- package/dist/http/api-client.d.ts +145 -0
- package/dist/http/api-client.js +242 -0
- package/dist/http/api-client.js.map +1 -0
- package/dist/inbox.d.ts +120 -0
- package/dist/inbox.js +243 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/strategies/delivery-strategy.d.ts +29 -0
- package/dist/strategies/delivery-strategy.js +2 -0
- package/dist/strategies/delivery-strategy.js.map +1 -0
- package/dist/strategies/polling-strategy.d.ts +36 -0
- package/dist/strategies/polling-strategy.js +146 -0
- package/dist/strategies/polling-strategy.js.map +1 -0
- package/dist/strategies/sse-strategy.d.ts +49 -0
- package/dist/strategies/sse-strategy.js +266 -0
- package/dist/strategies/sse-strategy.js.map +1 -0
- package/dist/types/index.d.ts +434 -0
- package/dist/types/index.js +127 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/email-utils.d.ts +19 -0
- package/dist/utils/email-utils.js +92 -0
- package/dist/utils/email-utils.js.map +1 -0
- package/dist/utils/sleep.d.ts +6 -0
- package/dist/utils/sleep.js +9 -0
- package/dist/utils/sleep.js.map +1 -0
- package/package.json +85 -0
package/dist/inbox.d.ts
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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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"}
|