shipmail 0.1.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 +223 -0
- package/dist/index.cjs +573 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +346 -0
- package/dist/index.d.ts +346 -0
- package/dist/index.js +555 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var crypto = require('crypto');
|
|
6
|
+
|
|
7
|
+
// src/errors.ts
|
|
8
|
+
var ShipMailError = class extends Error {
|
|
9
|
+
constructor(message, options) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "ShipMailError";
|
|
12
|
+
this.status = options?.status;
|
|
13
|
+
this.type = options?.type;
|
|
14
|
+
this.requestId = options?.requestId;
|
|
15
|
+
this.retryable = options?.retryable ?? false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var AuthenticationError = class extends ShipMailError {
|
|
19
|
+
constructor(message, requestId) {
|
|
20
|
+
super(message, { status: 401, type: "authentication_error", requestId, retryable: false });
|
|
21
|
+
this.name = "AuthenticationError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var AuthorizationError = class extends ShipMailError {
|
|
25
|
+
constructor(message, requestId) {
|
|
26
|
+
super(message, { status: 403, type: "authorization_error", requestId, retryable: false });
|
|
27
|
+
this.name = "AuthorizationError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var ValidationError = class extends ShipMailError {
|
|
31
|
+
constructor(message, options) {
|
|
32
|
+
super(message, { status: 422, type: "validation_error", requestId: options?.requestId, retryable: false });
|
|
33
|
+
this.name = "ValidationError";
|
|
34
|
+
this.details = options?.details;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var NotFoundError = class extends ShipMailError {
|
|
38
|
+
constructor(message, requestId) {
|
|
39
|
+
super(message, { status: 404, type: "not_found", requestId, retryable: false });
|
|
40
|
+
this.name = "NotFoundError";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var RateLimitError = class extends ShipMailError {
|
|
44
|
+
constructor(message, options) {
|
|
45
|
+
super(message, { status: 429, type: "rate_limit_error", requestId: options?.requestId, retryable: true });
|
|
46
|
+
this.name = "RateLimitError";
|
|
47
|
+
this.retryAfter = options?.retryAfter;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var ConflictError = class extends ShipMailError {
|
|
51
|
+
constructor(message, requestId) {
|
|
52
|
+
super(message, { status: 409, type: "conflict", requestId, retryable: false });
|
|
53
|
+
this.name = "ConflictError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var InternalServerError = class extends ShipMailError {
|
|
57
|
+
constructor(message, requestId) {
|
|
58
|
+
super(message, { status: 500, type: "internal_error", requestId, retryable: true });
|
|
59
|
+
this.name = "InternalServerError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var ConnectionError = class extends ShipMailError {
|
|
63
|
+
constructor(message) {
|
|
64
|
+
super(message, { retryable: true });
|
|
65
|
+
this.name = "ConnectionError";
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var WebhookVerificationError = class extends ShipMailError {
|
|
69
|
+
constructor(message) {
|
|
70
|
+
super(message, { retryable: false });
|
|
71
|
+
this.name = "WebhookVerificationError";
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
function mapErrorFromResponse(status, body, requestId) {
|
|
75
|
+
const error = body.error;
|
|
76
|
+
const rid = error.request_id;
|
|
77
|
+
switch (error.type) {
|
|
78
|
+
case "authentication_error":
|
|
79
|
+
return new AuthenticationError(error.message, rid);
|
|
80
|
+
case "authorization_error":
|
|
81
|
+
return new AuthorizationError(error.message, rid);
|
|
82
|
+
case "validation_error":
|
|
83
|
+
return new ValidationError(error.message, { requestId: rid, details: error.details });
|
|
84
|
+
case "not_found":
|
|
85
|
+
return new NotFoundError(error.message, rid);
|
|
86
|
+
case "rate_limit_error":
|
|
87
|
+
return new RateLimitError(error.message, { requestId: rid, retryAfter: error.retry_after });
|
|
88
|
+
case "conflict":
|
|
89
|
+
return new ConflictError(error.message, rid);
|
|
90
|
+
case "internal_error":
|
|
91
|
+
return new InternalServerError(error.message, rid);
|
|
92
|
+
default:
|
|
93
|
+
return new ShipMailError(error.message, { status, type: error.type, requestId: rid, retryable: status >= 500 });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/pagination.ts
|
|
98
|
+
var Page = class {
|
|
99
|
+
constructor(client, path, query) {
|
|
100
|
+
this.client = client;
|
|
101
|
+
this.path = path;
|
|
102
|
+
this.query = query;
|
|
103
|
+
}
|
|
104
|
+
async *[Symbol.asyncIterator]() {
|
|
105
|
+
let cursor;
|
|
106
|
+
do {
|
|
107
|
+
const response = await this.client.request({
|
|
108
|
+
method: "GET",
|
|
109
|
+
path: this.path,
|
|
110
|
+
query: { ...this.query, cursor }
|
|
111
|
+
});
|
|
112
|
+
for (const item of response.data) {
|
|
113
|
+
yield item;
|
|
114
|
+
}
|
|
115
|
+
cursor = response.pagination.next_cursor ?? void 0;
|
|
116
|
+
if (!response.pagination.has_more) break;
|
|
117
|
+
} while (cursor);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/resource.ts
|
|
122
|
+
var ApiResource = class {
|
|
123
|
+
constructor(client) {
|
|
124
|
+
this.client = client;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// src/resources/domains.ts
|
|
129
|
+
var Domains = class extends ApiResource {
|
|
130
|
+
create(params) {
|
|
131
|
+
return this.client.request({
|
|
132
|
+
method: "POST",
|
|
133
|
+
path: "/domains",
|
|
134
|
+
body: params
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
list(params) {
|
|
138
|
+
return this.client.request({
|
|
139
|
+
method: "GET",
|
|
140
|
+
path: "/domains",
|
|
141
|
+
query: {
|
|
142
|
+
cursor: params?.cursor,
|
|
143
|
+
limit: params?.limit
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
listAutoPaginating(params) {
|
|
148
|
+
return new Page(this.client, "/domains", {
|
|
149
|
+
limit: params?.limit
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
get(id) {
|
|
153
|
+
return this.client.request({
|
|
154
|
+
method: "GET",
|
|
155
|
+
path: `/domains/${id}`
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
update(id, params) {
|
|
159
|
+
return this.client.request({
|
|
160
|
+
method: "PATCH",
|
|
161
|
+
path: `/domains/${id}`,
|
|
162
|
+
body: params
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
delete(id) {
|
|
166
|
+
return this.client.request({
|
|
167
|
+
method: "DELETE",
|
|
168
|
+
path: `/domains/${id}`
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
verify(id) {
|
|
172
|
+
return this.client.request({
|
|
173
|
+
method: "POST",
|
|
174
|
+
path: `/domains/${id}/verification`
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// src/resources/mailboxes.ts
|
|
180
|
+
var Mailboxes = class extends ApiResource {
|
|
181
|
+
create(params) {
|
|
182
|
+
return this.client.request({
|
|
183
|
+
method: "POST",
|
|
184
|
+
path: "/mailboxes",
|
|
185
|
+
body: params
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
list(params) {
|
|
189
|
+
return this.client.request({
|
|
190
|
+
method: "GET",
|
|
191
|
+
path: "/mailboxes",
|
|
192
|
+
query: {
|
|
193
|
+
domain_id: params?.domain_id,
|
|
194
|
+
cursor: params?.cursor,
|
|
195
|
+
limit: params?.limit
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
listAutoPaginating(params) {
|
|
200
|
+
return new Page(this.client, "/mailboxes", {
|
|
201
|
+
domain_id: params?.domain_id,
|
|
202
|
+
limit: params?.limit
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
get(id) {
|
|
206
|
+
return this.client.request({
|
|
207
|
+
method: "GET",
|
|
208
|
+
path: `/mailboxes/${id}`
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
update(id, params) {
|
|
212
|
+
return this.client.request({
|
|
213
|
+
method: "PATCH",
|
|
214
|
+
path: `/mailboxes/${id}`,
|
|
215
|
+
body: params
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
delete(id) {
|
|
219
|
+
return this.client.request({
|
|
220
|
+
method: "DELETE",
|
|
221
|
+
path: `/mailboxes/${id}`
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
uploadAvatar(id, data, contentType) {
|
|
225
|
+
return this.client.request({
|
|
226
|
+
method: "PUT",
|
|
227
|
+
path: `/mailboxes/${id}/avatar`,
|
|
228
|
+
rawBody: data,
|
|
229
|
+
contentType
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
deleteAvatar(id) {
|
|
233
|
+
return this.client.request({
|
|
234
|
+
method: "DELETE",
|
|
235
|
+
path: `/mailboxes/${id}/avatar`
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/resources/messages.ts
|
|
241
|
+
var Messages = class extends ApiResource {
|
|
242
|
+
send(params) {
|
|
243
|
+
return this.client.request({
|
|
244
|
+
method: "POST",
|
|
245
|
+
path: "/messages",
|
|
246
|
+
body: params
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
get(id) {
|
|
250
|
+
return this.client.request({
|
|
251
|
+
method: "GET",
|
|
252
|
+
path: `/messages/${id}`
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// src/resources/status.ts
|
|
258
|
+
var Status = class extends ApiResource {
|
|
259
|
+
get() {
|
|
260
|
+
return this.client.request({
|
|
261
|
+
method: "GET",
|
|
262
|
+
path: "/status"
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// src/resources/threads.ts
|
|
268
|
+
var Threads = class extends ApiResource {
|
|
269
|
+
list(params) {
|
|
270
|
+
return this.client.request({
|
|
271
|
+
method: "GET",
|
|
272
|
+
path: "/threads",
|
|
273
|
+
query: {
|
|
274
|
+
mailbox_id: params.mailbox_id,
|
|
275
|
+
cursor: params.cursor,
|
|
276
|
+
limit: params.limit
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
listAutoPaginating(params) {
|
|
281
|
+
return new Page(this.client, "/threads", {
|
|
282
|
+
mailbox_id: params.mailbox_id,
|
|
283
|
+
limit: params.limit
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
get(id, params) {
|
|
287
|
+
return this.client.request({
|
|
288
|
+
method: "GET",
|
|
289
|
+
path: `/threads/${id}`,
|
|
290
|
+
query: {
|
|
291
|
+
cursor: params?.cursor,
|
|
292
|
+
limit: params?.limit
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
reply(id, params) {
|
|
297
|
+
return this.client.request({
|
|
298
|
+
method: "POST",
|
|
299
|
+
path: `/threads/${id}/reply`,
|
|
300
|
+
body: params
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/resources/webhooks.ts
|
|
306
|
+
var Webhooks = class extends ApiResource {
|
|
307
|
+
create(params) {
|
|
308
|
+
return this.client.request({
|
|
309
|
+
method: "POST",
|
|
310
|
+
path: "/webhooks",
|
|
311
|
+
body: params
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
list(params) {
|
|
315
|
+
return this.client.request({
|
|
316
|
+
method: "GET",
|
|
317
|
+
path: "/webhooks",
|
|
318
|
+
query: {
|
|
319
|
+
cursor: params?.cursor,
|
|
320
|
+
limit: params?.limit
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
listAutoPaginating(params) {
|
|
325
|
+
return new Page(this.client, "/webhooks", {
|
|
326
|
+
limit: params?.limit
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
get(id) {
|
|
330
|
+
return this.client.request({
|
|
331
|
+
method: "GET",
|
|
332
|
+
path: `/webhooks/${id}`
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
update(id, params) {
|
|
336
|
+
return this.client.request({
|
|
337
|
+
method: "PATCH",
|
|
338
|
+
path: `/webhooks/${id}`,
|
|
339
|
+
body: params
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
delete(id) {
|
|
343
|
+
return this.client.request({
|
|
344
|
+
method: "DELETE",
|
|
345
|
+
path: `/webhooks/${id}`
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
rotateSecret(id) {
|
|
349
|
+
return this.client.request({
|
|
350
|
+
method: "POST",
|
|
351
|
+
path: `/webhooks/${id}/rotate-secret`
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
test(id) {
|
|
355
|
+
return this.client.request({
|
|
356
|
+
method: "POST",
|
|
357
|
+
path: `/webhooks/${id}/test`
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
listDeliveries(id, params) {
|
|
361
|
+
return this.client.request({
|
|
362
|
+
method: "GET",
|
|
363
|
+
path: `/webhooks/${id}/deliveries`,
|
|
364
|
+
query: {
|
|
365
|
+
status: params?.status,
|
|
366
|
+
event_type: params?.event_type,
|
|
367
|
+
cursor: params?.cursor,
|
|
368
|
+
limit: params?.limit
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
listDeliveriesAutoPaginating(id, params) {
|
|
373
|
+
return new Page(this.client, `/webhooks/${id}/deliveries`, {
|
|
374
|
+
status: params?.status,
|
|
375
|
+
event_type: params?.event_type,
|
|
376
|
+
limit: params?.limit
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/version.ts
|
|
382
|
+
var VERSION = "0.1.0";
|
|
383
|
+
|
|
384
|
+
// src/client.ts
|
|
385
|
+
var DEFAULT_BASE_URL = "https://api.shipmail.to/v1";
|
|
386
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
387
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
388
|
+
function isRetryableStatus(status) {
|
|
389
|
+
return status === 429 || status >= 500;
|
|
390
|
+
}
|
|
391
|
+
function calculateBackoff(attempt) {
|
|
392
|
+
const base = Math.min(2 ** attempt * 500, 8e3);
|
|
393
|
+
const jitter = Math.random() * base * 0.5;
|
|
394
|
+
return base + jitter;
|
|
395
|
+
}
|
|
396
|
+
function isApiErrorBody(value) {
|
|
397
|
+
if (typeof value !== "object" || value === null) return false;
|
|
398
|
+
const obj = value;
|
|
399
|
+
if (typeof obj["error"] !== "object" || obj["error"] === null) return false;
|
|
400
|
+
const error = obj["error"];
|
|
401
|
+
return typeof error["type"] === "string" && typeof error["message"] === "string";
|
|
402
|
+
}
|
|
403
|
+
var ShipMailClient = class {
|
|
404
|
+
constructor(config) {
|
|
405
|
+
if (typeof config === "string") {
|
|
406
|
+
this.apiKey = config;
|
|
407
|
+
this.baseUrl = DEFAULT_BASE_URL;
|
|
408
|
+
this.maxRetries = DEFAULT_MAX_RETRIES;
|
|
409
|
+
this.timeout = DEFAULT_TIMEOUT;
|
|
410
|
+
this.fetchFn = globalThis.fetch;
|
|
411
|
+
} else {
|
|
412
|
+
this.apiKey = config.apiKey;
|
|
413
|
+
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
414
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
415
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
416
|
+
this.fetchFn = config.fetch ?? globalThis.fetch;
|
|
417
|
+
}
|
|
418
|
+
this.domains = new Domains(this);
|
|
419
|
+
this.mailboxes = new Mailboxes(this);
|
|
420
|
+
this.messages = new Messages(this);
|
|
421
|
+
this.threads = new Threads(this);
|
|
422
|
+
this.webhooks = new Webhooks(this);
|
|
423
|
+
this.status = new Status(this);
|
|
424
|
+
}
|
|
425
|
+
async request(options) {
|
|
426
|
+
const url = this.buildUrl(options.path, options.query);
|
|
427
|
+
let lastError;
|
|
428
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
429
|
+
if (attempt > 0) {
|
|
430
|
+
const delay = calculateBackoff(attempt - 1);
|
|
431
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
432
|
+
}
|
|
433
|
+
let response;
|
|
434
|
+
try {
|
|
435
|
+
const headers = {
|
|
436
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
437
|
+
"User-Agent": `shipmail-node/${VERSION}`,
|
|
438
|
+
Accept: "application/json"
|
|
439
|
+
};
|
|
440
|
+
let body = null;
|
|
441
|
+
if (options.rawBody !== void 0) {
|
|
442
|
+
headers["Content-Type"] = options.contentType ?? "application/octet-stream";
|
|
443
|
+
body = new Blob([options.rawBody]);
|
|
444
|
+
} else if (options.body !== void 0) {
|
|
445
|
+
headers["Content-Type"] = "application/json";
|
|
446
|
+
body = JSON.stringify(options.body);
|
|
447
|
+
}
|
|
448
|
+
response = await this.fetchFn(url, {
|
|
449
|
+
method: options.method,
|
|
450
|
+
headers,
|
|
451
|
+
body,
|
|
452
|
+
signal: AbortSignal.timeout(this.timeout)
|
|
453
|
+
});
|
|
454
|
+
} catch (err) {
|
|
455
|
+
lastError = new ConnectionError(
|
|
456
|
+
err instanceof Error ? err.message : "Request failed"
|
|
457
|
+
);
|
|
458
|
+
if (attempt < this.maxRetries) continue;
|
|
459
|
+
throw lastError;
|
|
460
|
+
}
|
|
461
|
+
if (response.status === 204) {
|
|
462
|
+
return void 0;
|
|
463
|
+
}
|
|
464
|
+
if (response.ok) {
|
|
465
|
+
return await response.json();
|
|
466
|
+
}
|
|
467
|
+
let errorBody;
|
|
468
|
+
try {
|
|
469
|
+
errorBody = await response.json();
|
|
470
|
+
} catch {
|
|
471
|
+
errorBody = null;
|
|
472
|
+
}
|
|
473
|
+
if (isApiErrorBody(errorBody)) {
|
|
474
|
+
lastError = mapErrorFromResponse(response.status, errorBody);
|
|
475
|
+
} else {
|
|
476
|
+
lastError = new ShipMailError(
|
|
477
|
+
`Request failed with status ${response.status}`,
|
|
478
|
+
{ status: response.status, retryable: isRetryableStatus(response.status) }
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
if (!lastError.retryable || attempt >= this.maxRetries) {
|
|
482
|
+
throw lastError;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
throw lastError ?? new ShipMailError("Request failed after retries");
|
|
486
|
+
}
|
|
487
|
+
buildUrl(path, query) {
|
|
488
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
489
|
+
if (query) {
|
|
490
|
+
for (const [key, value] of Object.entries(query)) {
|
|
491
|
+
if (value !== void 0) {
|
|
492
|
+
url.searchParams.set(key, String(value));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return url.toString();
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/types/common.ts
|
|
501
|
+
var WEBHOOK_EVENT_TYPES = [
|
|
502
|
+
"message.received",
|
|
503
|
+
"message.queued",
|
|
504
|
+
"message.sent",
|
|
505
|
+
"message.delivered",
|
|
506
|
+
"message.bounced",
|
|
507
|
+
"message.complained",
|
|
508
|
+
"domain.verified",
|
|
509
|
+
"domain.verification_failed",
|
|
510
|
+
"domain.degraded"
|
|
511
|
+
];
|
|
512
|
+
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
513
|
+
function getHeader(headers, name) {
|
|
514
|
+
if (headers instanceof Headers) {
|
|
515
|
+
return headers.get(name) ?? void 0;
|
|
516
|
+
}
|
|
517
|
+
return headers[name] ?? headers[name.toLowerCase()];
|
|
518
|
+
}
|
|
519
|
+
function signPayload(secret, timestamp, body) {
|
|
520
|
+
const payload = `v1=${timestamp}
|
|
521
|
+
${body}`;
|
|
522
|
+
return crypto.createHmac("sha256", secret).update(payload).digest("hex");
|
|
523
|
+
}
|
|
524
|
+
function verifyWebhook(body, headers, secret, options) {
|
|
525
|
+
const signature = getHeader(headers, "x-shipmail-signature");
|
|
526
|
+
const timestampStr = getHeader(headers, "x-shipmail-timestamp");
|
|
527
|
+
if (!signature) {
|
|
528
|
+
throw new WebhookVerificationError("Missing X-ShipMail-Signature header");
|
|
529
|
+
}
|
|
530
|
+
if (!timestampStr) {
|
|
531
|
+
throw new WebhookVerificationError("Missing X-ShipMail-Timestamp header");
|
|
532
|
+
}
|
|
533
|
+
const timestamp = parseInt(timestampStr, 10);
|
|
534
|
+
if (isNaN(timestamp)) {
|
|
535
|
+
throw new WebhookVerificationError("Invalid X-ShipMail-Timestamp header");
|
|
536
|
+
}
|
|
537
|
+
const tolerance = options?.toleranceInSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
538
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
539
|
+
if (Math.abs(now - timestamp) > tolerance) {
|
|
540
|
+
throw new WebhookVerificationError("Webhook timestamp is outside tolerance window");
|
|
541
|
+
}
|
|
542
|
+
const expected = signPayload(secret, timestamp, body);
|
|
543
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
544
|
+
const expectedBuffer = Buffer.from(expected, "hex");
|
|
545
|
+
if (sigBuffer.length !== expectedBuffer.length || !crypto.timingSafeEqual(sigBuffer, expectedBuffer)) {
|
|
546
|
+
throw new WebhookVerificationError("Webhook signature verification failed");
|
|
547
|
+
}
|
|
548
|
+
let parsed;
|
|
549
|
+
try {
|
|
550
|
+
parsed = JSON.parse(body);
|
|
551
|
+
} catch {
|
|
552
|
+
throw new WebhookVerificationError("Invalid webhook payload: not valid JSON");
|
|
553
|
+
}
|
|
554
|
+
return parsed;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
exports.AuthenticationError = AuthenticationError;
|
|
558
|
+
exports.AuthorizationError = AuthorizationError;
|
|
559
|
+
exports.ConflictError = ConflictError;
|
|
560
|
+
exports.ConnectionError = ConnectionError;
|
|
561
|
+
exports.InternalServerError = InternalServerError;
|
|
562
|
+
exports.NotFoundError = NotFoundError;
|
|
563
|
+
exports.Page = Page;
|
|
564
|
+
exports.RateLimitError = RateLimitError;
|
|
565
|
+
exports.ShipMailClient = ShipMailClient;
|
|
566
|
+
exports.ShipMailError = ShipMailError;
|
|
567
|
+
exports.ValidationError = ValidationError;
|
|
568
|
+
exports.WEBHOOK_EVENT_TYPES = WEBHOOK_EVENT_TYPES;
|
|
569
|
+
exports.WebhookVerificationError = WebhookVerificationError;
|
|
570
|
+
exports.default = ShipMailClient;
|
|
571
|
+
exports.verifyWebhook = verifyWebhook;
|
|
572
|
+
//# sourceMappingURL=index.cjs.map
|
|
573
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/pagination.ts","../src/resource.ts","../src/resources/domains.ts","../src/resources/mailboxes.ts","../src/resources/messages.ts","../src/resources/status.ts","../src/resources/threads.ts","../src/resources/webhooks.ts","../src/version.ts","../src/client.ts","../src/types/common.ts","../src/webhook-verification.ts"],"names":["createHmac","timingSafeEqual"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ApiErrorBody, ErrorType } from \"./types/common.js\";\n\nexport class ShipMailError extends Error {\n readonly status: number | undefined;\n readonly type: ErrorType | undefined;\n readonly requestId: string | undefined;\n readonly retryable: boolean;\n\n constructor(\n message: string,\n options?: {\n readonly status?: number | undefined;\n readonly type?: ErrorType | undefined;\n readonly requestId?: string | undefined;\n readonly retryable?: boolean | undefined;\n },\n ) {\n super(message);\n this.name = \"ShipMailError\";\n this.status = options?.status;\n this.type = options?.type;\n this.requestId = options?.requestId;\n this.retryable = options?.retryable ?? false;\n }\n}\n\nexport class AuthenticationError extends ShipMailError {\n constructor(message: string, requestId?: string) {\n super(message, { status: 401, type: \"authentication_error\", requestId, retryable: false });\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class AuthorizationError extends ShipMailError {\n constructor(message: string, requestId?: string) {\n super(message, { status: 403, type: \"authorization_error\", requestId, retryable: false });\n this.name = \"AuthorizationError\";\n }\n}\n\nexport class ValidationError extends ShipMailError {\n readonly details: readonly { readonly field: string; readonly message: string }[] | undefined;\n\n constructor(\n message: string,\n options?: {\n readonly requestId?: string | undefined;\n readonly details?:\n | readonly { readonly field: string; readonly message: string }[]\n | undefined;\n },\n ) {\n super(message, { status: 422, type: \"validation_error\", requestId: options?.requestId, retryable: false });\n this.name = \"ValidationError\";\n this.details = options?.details;\n }\n}\n\nexport class NotFoundError extends ShipMailError {\n constructor(message: string, requestId?: string) {\n super(message, { status: 404, type: \"not_found\", requestId, retryable: false });\n this.name = \"NotFoundError\";\n }\n}\n\nexport class RateLimitError extends ShipMailError {\n readonly retryAfter: number | undefined;\n\n constructor(message: string, options?: { readonly requestId?: string | undefined; readonly retryAfter?: number | undefined }) {\n super(message, { status: 429, type: \"rate_limit_error\", requestId: options?.requestId, retryable: true });\n this.name = \"RateLimitError\";\n this.retryAfter = options?.retryAfter;\n }\n}\n\nexport class ConflictError extends ShipMailError {\n constructor(message: string, requestId?: string) {\n super(message, { status: 409, type: \"conflict\", requestId, retryable: false });\n this.name = \"ConflictError\";\n }\n}\n\nexport class InternalServerError extends ShipMailError {\n constructor(message: string, requestId?: string) {\n super(message, { status: 500, type: \"internal_error\", requestId, retryable: true });\n this.name = \"InternalServerError\";\n }\n}\n\nexport class ConnectionError extends ShipMailError {\n constructor(message: string) {\n super(message, { retryable: true });\n this.name = \"ConnectionError\";\n }\n}\n\nexport class WebhookVerificationError extends ShipMailError {\n constructor(message: string) {\n super(message, { retryable: false });\n this.name = \"WebhookVerificationError\";\n }\n}\n\nexport function mapErrorFromResponse(status: number, body: ApiErrorBody, requestId?: string): ShipMailError {\n const error = body.error;\n const rid = requestId ?? error.request_id;\n\n switch (error.type) {\n case \"authentication_error\":\n return new AuthenticationError(error.message, rid);\n case \"authorization_error\":\n return new AuthorizationError(error.message, rid);\n case \"validation_error\":\n return new ValidationError(error.message, { requestId: rid, details: error.details });\n case \"not_found\":\n return new NotFoundError(error.message, rid);\n case \"rate_limit_error\":\n return new RateLimitError(error.message, { requestId: rid, retryAfter: error.retry_after });\n case \"conflict\":\n return new ConflictError(error.message, rid);\n case \"internal_error\":\n return new InternalServerError(error.message, rid);\n default:\n return new ShipMailError(error.message, { status, type: error.type, requestId: rid, retryable: status >= 500 });\n }\n}\n","import type { ShipMailClient } from \"./client.js\";\nimport type { PaginatedResponse } from \"./types/common.js\";\n\nexport class Page<T> implements AsyncIterable<T> {\n private readonly client: ShipMailClient;\n private readonly path: string;\n private readonly query: Record<string, string | number | boolean | undefined>;\n\n constructor(\n client: ShipMailClient,\n path: string,\n query: Record<string, string | number | boolean | undefined>,\n ) {\n this.client = client;\n this.path = path;\n this.query = query;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n let cursor: string | undefined;\n\n do {\n const response = await this.client.request<PaginatedResponse<T>>({\n method: \"GET\",\n path: this.path,\n query: { ...this.query, cursor },\n });\n\n for (const item of response.data) {\n yield item;\n }\n\n cursor = response.pagination.next_cursor ?? undefined;\n if (!response.pagination.has_more) break;\n } while (cursor);\n }\n}\n","import type { ShipMailClient } from \"./client.js\";\n\nexport abstract class ApiResource {\n protected readonly client: ShipMailClient;\n\n constructor(client: ShipMailClient) {\n this.client = client;\n }\n}\n","import { Page } from \"../pagination.js\";\nimport { ApiResource } from \"../resource.js\";\nimport type { PaginatedResponse } from \"../types/common.js\";\nimport type {\n CreateDomainParams,\n Domain,\n DomainVerificationResult,\n ListDomainsParams,\n UpdateDomainParams,\n} from \"../types/domain.js\";\n\nexport class Domains extends ApiResource {\n create(params: CreateDomainParams): Promise<Domain> {\n return this.client.request<Domain>({\n method: \"POST\",\n path: \"/domains\",\n body: params,\n });\n }\n\n list(params?: ListDomainsParams): Promise<PaginatedResponse<Domain>> {\n return this.client.request<PaginatedResponse<Domain>>({\n method: \"GET\",\n path: \"/domains\",\n query: {\n cursor: params?.cursor,\n limit: params?.limit,\n },\n });\n }\n\n listAutoPaginating(params?: Omit<ListDomainsParams, \"cursor\">): Page<Domain> {\n return new Page<Domain>(this.client, \"/domains\", {\n limit: params?.limit,\n });\n }\n\n get(id: string): Promise<Domain> {\n return this.client.request<Domain>({\n method: \"GET\",\n path: `/domains/${id}`,\n });\n }\n\n update(id: string, params: UpdateDomainParams): Promise<Domain> {\n return this.client.request<Domain>({\n method: \"PATCH\",\n path: `/domains/${id}`,\n body: params,\n });\n }\n\n delete(id: string): Promise<void> {\n return this.client.request<void>({\n method: \"DELETE\",\n path: `/domains/${id}`,\n });\n }\n\n verify(id: string): Promise<DomainVerificationResult> {\n return this.client.request<DomainVerificationResult>({\n method: \"POST\",\n path: `/domains/${id}/verification`,\n });\n }\n}\n","import { Page } from \"../pagination.js\";\nimport { ApiResource } from \"../resource.js\";\nimport type { PaginatedResponse } from \"../types/common.js\";\nimport type {\n CreateMailboxParams,\n ListMailboxesParams,\n Mailbox,\n UpdateMailboxParams,\n UploadAvatarResponse,\n} from \"../types/mailbox.js\";\n\nexport class Mailboxes extends ApiResource {\n create(params: CreateMailboxParams): Promise<Mailbox> {\n return this.client.request<Mailbox>({\n method: \"POST\",\n path: \"/mailboxes\",\n body: params,\n });\n }\n\n list(params?: ListMailboxesParams): Promise<PaginatedResponse<Mailbox>> {\n return this.client.request<PaginatedResponse<Mailbox>>({\n method: \"GET\",\n path: \"/mailboxes\",\n query: {\n domain_id: params?.domain_id,\n cursor: params?.cursor,\n limit: params?.limit,\n },\n });\n }\n\n listAutoPaginating(params?: Omit<ListMailboxesParams, \"cursor\">): Page<Mailbox> {\n return new Page<Mailbox>(this.client, \"/mailboxes\", {\n domain_id: params?.domain_id,\n limit: params?.limit,\n });\n }\n\n get(id: string): Promise<Mailbox> {\n return this.client.request<Mailbox>({\n method: \"GET\",\n path: `/mailboxes/${id}`,\n });\n }\n\n update(id: string, params: UpdateMailboxParams): Promise<Mailbox> {\n return this.client.request<Mailbox>({\n method: \"PATCH\",\n path: `/mailboxes/${id}`,\n body: params,\n });\n }\n\n delete(id: string): Promise<void> {\n return this.client.request<void>({\n method: \"DELETE\",\n path: `/mailboxes/${id}`,\n });\n }\n\n uploadAvatar(id: string, data: ArrayBuffer, contentType: string): Promise<UploadAvatarResponse> {\n return this.client.request<UploadAvatarResponse>({\n method: \"PUT\",\n path: `/mailboxes/${id}/avatar`,\n rawBody: data,\n contentType,\n });\n }\n\n deleteAvatar(id: string): Promise<void> {\n return this.client.request<void>({\n method: \"DELETE\",\n path: `/mailboxes/${id}/avatar`,\n });\n }\n}\n","import { ApiResource } from \"../resource.js\";\nimport type { Message, SendMessageParams } from \"../types/message.js\";\n\nexport class Messages extends ApiResource {\n send(params: SendMessageParams): Promise<Message> {\n return this.client.request<Message>({\n method: \"POST\",\n path: \"/messages\",\n body: params,\n });\n }\n\n get(id: string): Promise<Message> {\n return this.client.request<Message>({\n method: \"GET\",\n path: `/messages/${id}`,\n });\n }\n}\n","import { ApiResource } from \"../resource.js\";\nimport type { StatusResponse } from \"../types/common.js\";\n\nexport class Status extends ApiResource {\n get(): Promise<StatusResponse> {\n return this.client.request<StatusResponse>({\n method: \"GET\",\n path: \"/status\",\n });\n }\n}\n","import { Page } from \"../pagination.js\";\nimport { ApiResource } from \"../resource.js\";\nimport type { PaginatedResponse } from \"../types/common.js\";\nimport type { Message } from \"../types/message.js\";\nimport type { GetThreadParams, ListThreadsParams, ReplyToThreadParams } from \"../types/thread.js\";\n\nexport class Threads extends ApiResource {\n list(params: ListThreadsParams): Promise<PaginatedResponse<Message>> {\n return this.client.request<PaginatedResponse<Message>>({\n method: \"GET\",\n path: \"/threads\",\n query: {\n mailbox_id: params.mailbox_id,\n cursor: params.cursor,\n limit: params.limit,\n },\n });\n }\n\n listAutoPaginating(params: Omit<ListThreadsParams, \"cursor\">): Page<Message> {\n return new Page<Message>(this.client, \"/threads\", {\n mailbox_id: params.mailbox_id,\n limit: params.limit,\n });\n }\n\n get(id: string, params?: GetThreadParams): Promise<PaginatedResponse<Message>> {\n return this.client.request<PaginatedResponse<Message>>({\n method: \"GET\",\n path: `/threads/${id}`,\n query: {\n cursor: params?.cursor,\n limit: params?.limit,\n },\n });\n }\n\n reply(id: string, params: ReplyToThreadParams): Promise<Message> {\n return this.client.request<Message>({\n method: \"POST\",\n path: `/threads/${id}/reply`,\n body: params,\n });\n }\n}\n","import { Page } from \"../pagination.js\";\nimport { ApiResource } from \"../resource.js\";\nimport type { PaginatedResponse } from \"../types/common.js\";\nimport type {\n CreateWebhookParams,\n ListDeliveriesParams,\n ListWebhooksParams,\n RotateSecretResponse,\n TestWebhookResponse,\n UpdateWebhookParams,\n Webhook,\n WebhookDelivery,\n WebhookWithSecret,\n} from \"../types/webhook.js\";\n\nexport class Webhooks extends ApiResource {\n create(params: CreateWebhookParams): Promise<WebhookWithSecret> {\n return this.client.request<WebhookWithSecret>({\n method: \"POST\",\n path: \"/webhooks\",\n body: params,\n });\n }\n\n list(params?: ListWebhooksParams): Promise<PaginatedResponse<Webhook>> {\n return this.client.request<PaginatedResponse<Webhook>>({\n method: \"GET\",\n path: \"/webhooks\",\n query: {\n cursor: params?.cursor,\n limit: params?.limit,\n },\n });\n }\n\n listAutoPaginating(params?: Omit<ListWebhooksParams, \"cursor\">): Page<Webhook> {\n return new Page<Webhook>(this.client, \"/webhooks\", {\n limit: params?.limit,\n });\n }\n\n get(id: string): Promise<Webhook> {\n return this.client.request<Webhook>({\n method: \"GET\",\n path: `/webhooks/${id}`,\n });\n }\n\n update(id: string, params: UpdateWebhookParams): Promise<Webhook> {\n return this.client.request<Webhook>({\n method: \"PATCH\",\n path: `/webhooks/${id}`,\n body: params,\n });\n }\n\n delete(id: string): Promise<void> {\n return this.client.request<void>({\n method: \"DELETE\",\n path: `/webhooks/${id}`,\n });\n }\n\n rotateSecret(id: string): Promise<RotateSecretResponse> {\n return this.client.request<RotateSecretResponse>({\n method: \"POST\",\n path: `/webhooks/${id}/rotate-secret`,\n });\n }\n\n test(id: string): Promise<TestWebhookResponse> {\n return this.client.request<TestWebhookResponse>({\n method: \"POST\",\n path: `/webhooks/${id}/test`,\n });\n }\n\n listDeliveries(id: string, params?: ListDeliveriesParams): Promise<PaginatedResponse<WebhookDelivery>> {\n return this.client.request<PaginatedResponse<WebhookDelivery>>({\n method: \"GET\",\n path: `/webhooks/${id}/deliveries`,\n query: {\n status: params?.status,\n event_type: params?.event_type,\n cursor: params?.cursor,\n limit: params?.limit,\n },\n });\n }\n\n listDeliveriesAutoPaginating(id: string, params?: Omit<ListDeliveriesParams, \"cursor\">): Page<WebhookDelivery> {\n return new Page<WebhookDelivery>(this.client, `/webhooks/${id}/deliveries`, {\n status: params?.status,\n event_type: params?.event_type,\n limit: params?.limit,\n });\n }\n}\n","export const VERSION = \"0.1.0\";\n","import { ConnectionError, mapErrorFromResponse, ShipMailError } from \"./errors.js\";\nimport { Domains } from \"./resources/domains.js\";\nimport { Mailboxes } from \"./resources/mailboxes.js\";\nimport { Messages } from \"./resources/messages.js\";\nimport { Status } from \"./resources/status.js\";\nimport { Threads } from \"./resources/threads.js\";\nimport { Webhooks } from \"./resources/webhooks.js\";\nimport type { ApiErrorBody, ShipMailConfig } from \"./types/common.js\";\nimport { VERSION } from \"./version.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.shipmail.to/v1\";\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_TIMEOUT = 30_000;\n\nfunction isRetryableStatus(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction calculateBackoff(attempt: number): number {\n const base = Math.min(2 ** attempt * 500, 8000);\n const jitter = Math.random() * base * 0.5;\n return base + jitter;\n}\n\nfunction isApiErrorBody(value: unknown): value is ApiErrorBody {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n if (typeof obj[\"error\"] !== \"object\" || obj[\"error\"] === null) return false;\n const error = obj[\"error\"] as Record<string, unknown>;\n return typeof error[\"type\"] === \"string\" && typeof error[\"message\"] === \"string\";\n}\n\nexport type RequestOptions = {\n readonly method: string;\n readonly path: string;\n readonly body?: unknown | undefined;\n readonly query?: Record<string, string | number | boolean | undefined> | undefined;\n readonly rawBody?: ArrayBuffer | undefined;\n readonly contentType?: string | undefined;\n};\n\nexport class ShipMailClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly maxRetries: number;\n private readonly timeout: number;\n private readonly fetchFn: typeof fetch;\n\n readonly domains: Domains;\n readonly mailboxes: Mailboxes;\n readonly messages: Messages;\n readonly threads: Threads;\n readonly webhooks: Webhooks;\n readonly status: Status;\n\n constructor(config: string | ShipMailConfig) {\n if (typeof config === \"string\") {\n this.apiKey = config;\n this.baseUrl = DEFAULT_BASE_URL;\n this.maxRetries = DEFAULT_MAX_RETRIES;\n this.timeout = DEFAULT_TIMEOUT;\n this.fetchFn = globalThis.fetch;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT;\n this.fetchFn = config.fetch ?? globalThis.fetch;\n }\n\n this.domains = new Domains(this);\n this.mailboxes = new Mailboxes(this);\n this.messages = new Messages(this);\n this.threads = new Threads(this);\n this.webhooks = new Webhooks(this);\n this.status = new Status(this);\n }\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = this.buildUrl(options.path, options.query);\n let lastError: ShipMailError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = calculateBackoff(attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n\n let response: Response;\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": `shipmail-node/${VERSION}`,\n Accept: \"application/json\",\n };\n\n let body: BodyInit | null = null;\n if (options.rawBody !== undefined) {\n headers[\"Content-Type\"] = options.contentType ?? \"application/octet-stream\";\n body = new Blob([options.rawBody]);\n } else if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n body = JSON.stringify(options.body);\n }\n\n response = await this.fetchFn(url, {\n method: options.method,\n headers,\n body,\n signal: AbortSignal.timeout(this.timeout),\n });\n } catch (err) {\n lastError = new ConnectionError(\n err instanceof Error ? err.message : \"Request failed\",\n );\n if (attempt < this.maxRetries) continue;\n throw lastError;\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n let errorBody: unknown;\n try {\n errorBody = await response.json();\n } catch {\n errorBody = null;\n }\n\n if (isApiErrorBody(errorBody)) {\n lastError = mapErrorFromResponse(response.status, errorBody);\n } else {\n lastError = new ShipMailError(\n `Request failed with status ${response.status}`,\n { status: response.status, retryable: isRetryableStatus(response.status) },\n );\n }\n\n if (!lastError.retryable || attempt >= this.maxRetries) {\n throw lastError;\n }\n }\n\n throw lastError ?? new ShipMailError(\"Request failed after retries\");\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n }\n}\n","export type ShipMailConfig = {\n readonly apiKey: string;\n readonly baseUrl?: string | undefined;\n readonly maxRetries?: number | undefined;\n readonly timeout?: number | undefined;\n readonly fetch?: typeof fetch | undefined;\n};\n\nexport type PaginationParams = {\n readonly cursor?: string | undefined;\n readonly limit?: number | undefined;\n};\n\nexport type PaginatedResponse<T> = {\n readonly data: readonly T[];\n readonly pagination: {\n readonly next_cursor: string | null;\n readonly has_more: boolean;\n };\n};\n\nexport type ErrorType =\n | \"validation_error\"\n | \"authentication_error\"\n | \"authorization_error\"\n | \"not_found\"\n | \"rate_limit_error\"\n | \"conflict\"\n | \"internal_error\";\n\nexport type ApiErrorBody = {\n readonly error: {\n readonly type: ErrorType;\n readonly message: string;\n readonly request_id?: string | undefined;\n readonly details?: readonly { readonly field: string; readonly message: string }[] | undefined;\n readonly retry_after?: number | undefined;\n };\n};\n\nexport type EmailRecipient = {\n readonly address: string;\n readonly name?: string | null | undefined;\n};\n\nexport const WEBHOOK_EVENT_TYPES = [\n \"message.received\",\n \"message.queued\",\n \"message.sent\",\n \"message.delivered\",\n \"message.bounced\",\n \"message.complained\",\n \"domain.verified\",\n \"domain.verification_failed\",\n \"domain.degraded\",\n] as const;\n\nexport type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number];\n\nexport type StatusResponse = {\n readonly status: string;\n readonly version: string;\n readonly time: string;\n readonly request_id: string;\n};\n","import { createHmac, timingSafeEqual } from \"crypto\";\n\nimport { WebhookVerificationError } from \"./errors.js\";\nimport type { WebhookEvent } from \"./types/webhook.js\";\n\nconst DEFAULT_TOLERANCE_SECONDS = 300; // 5 minutes\n\ntype WebhookHeaders = {\n readonly \"x-shipmail-signature\"?: string;\n readonly \"x-shipmail-timestamp\"?: string;\n readonly \"x-shipmail-event-id\"?: string;\n readonly [key: string]: string | undefined;\n};\n\nfunction getHeader(headers: WebhookHeaders | Headers, name: string): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined;\n }\n return headers[name] ?? headers[name.toLowerCase()];\n}\n\nfunction signPayload(secret: string, timestamp: number, body: string): string {\n const payload = `v1=${timestamp}\\n${body}`;\n return createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n}\n\nexport function verifyWebhook(\n body: string,\n headers: WebhookHeaders | Headers,\n secret: string,\n options?: { readonly toleranceInSeconds?: number | undefined },\n): WebhookEvent {\n const signature = getHeader(headers, \"x-shipmail-signature\");\n const timestampStr = getHeader(headers, \"x-shipmail-timestamp\");\n\n if (!signature) {\n throw new WebhookVerificationError(\"Missing X-ShipMail-Signature header\");\n }\n if (!timestampStr) {\n throw new WebhookVerificationError(\"Missing X-ShipMail-Timestamp header\");\n }\n\n const timestamp = parseInt(timestampStr, 10);\n if (isNaN(timestamp)) {\n throw new WebhookVerificationError(\"Invalid X-ShipMail-Timestamp header\");\n }\n\n const tolerance = options?.toleranceInSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > tolerance) {\n throw new WebhookVerificationError(\"Webhook timestamp is outside tolerance window\");\n }\n\n const expected = signPayload(secret, timestamp, body);\n\n const sigBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expected, \"hex\");\n\n if (sigBuffer.length !== expectedBuffer.length || !timingSafeEqual(sigBuffer, expectedBuffer)) {\n throw new WebhookVerificationError(\"Webhook signature verification failed\");\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new WebhookVerificationError(\"Invalid webhook payload: not valid JSON\");\n }\n\n return parsed as WebhookEvent;\n}\n"]}
|