shipmail 0.1.0 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -15
- package/dist/index.cjs +249 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +204 -54
- package/dist/index.d.ts +204 -54
- package/dist/index.js +243 -96
- package/dist/index.js.map +1 -1
- package/package.json +9 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { timingSafeEqual, createHmac } from 'crypto';
|
|
2
|
-
|
|
3
1
|
// src/errors.ts
|
|
4
2
|
var ShipMailError = class extends Error {
|
|
5
3
|
constructor(message, options) {
|
|
@@ -25,11 +23,22 @@ var AuthorizationError = class extends ShipMailError {
|
|
|
25
23
|
};
|
|
26
24
|
var ValidationError = class extends ShipMailError {
|
|
27
25
|
constructor(message, options) {
|
|
28
|
-
super(message, {
|
|
26
|
+
super(message, {
|
|
27
|
+
status: 422,
|
|
28
|
+
type: "validation_error",
|
|
29
|
+
requestId: options?.requestId,
|
|
30
|
+
retryable: false
|
|
31
|
+
});
|
|
29
32
|
this.name = "ValidationError";
|
|
30
33
|
this.details = options?.details;
|
|
31
34
|
}
|
|
32
35
|
};
|
|
36
|
+
var QuotaExceededError = class extends ShipMailError {
|
|
37
|
+
constructor(message, requestId) {
|
|
38
|
+
super(message, { status: 403, type: "quota_exceeded", requestId, retryable: false });
|
|
39
|
+
this.name = "QuotaExceededError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
33
42
|
var NotFoundError = class extends ShipMailError {
|
|
34
43
|
constructor(message, requestId) {
|
|
35
44
|
super(message, { status: 404, type: "not_found", requestId, retryable: false });
|
|
@@ -38,7 +47,12 @@ var NotFoundError = class extends ShipMailError {
|
|
|
38
47
|
};
|
|
39
48
|
var RateLimitError = class extends ShipMailError {
|
|
40
49
|
constructor(message, options) {
|
|
41
|
-
super(message, {
|
|
50
|
+
super(message, {
|
|
51
|
+
status: 429,
|
|
52
|
+
type: "rate_limit_error",
|
|
53
|
+
requestId: options?.requestId,
|
|
54
|
+
retryable: true
|
|
55
|
+
});
|
|
42
56
|
this.name = "RateLimitError";
|
|
43
57
|
this.retryAfter = options?.retryAfter;
|
|
44
58
|
}
|
|
@@ -75,6 +89,8 @@ function mapErrorFromResponse(status, body, requestId) {
|
|
|
75
89
|
return new AuthenticationError(error.message, rid);
|
|
76
90
|
case "authorization_error":
|
|
77
91
|
return new AuthorizationError(error.message, rid);
|
|
92
|
+
case "quota_exceeded":
|
|
93
|
+
return new QuotaExceededError(error.message, rid);
|
|
78
94
|
case "validation_error":
|
|
79
95
|
return new ValidationError(error.message, { requestId: rid, details: error.details });
|
|
80
96
|
case "not_found":
|
|
@@ -86,7 +102,12 @@ function mapErrorFromResponse(status, body, requestId) {
|
|
|
86
102
|
case "internal_error":
|
|
87
103
|
return new InternalServerError(error.message, rid);
|
|
88
104
|
default:
|
|
89
|
-
return new ShipMailError(error.message, {
|
|
105
|
+
return new ShipMailError(error.message, {
|
|
106
|
+
status,
|
|
107
|
+
type: error.type,
|
|
108
|
+
requestId: rid,
|
|
109
|
+
retryable: status >= 500
|
|
110
|
+
});
|
|
90
111
|
}
|
|
91
112
|
}
|
|
92
113
|
|
|
@@ -123,21 +144,23 @@ var ApiResource = class {
|
|
|
123
144
|
|
|
124
145
|
// src/resources/domains.ts
|
|
125
146
|
var Domains = class extends ApiResource {
|
|
126
|
-
create(params) {
|
|
147
|
+
create(params, options) {
|
|
127
148
|
return this.client.request({
|
|
128
149
|
method: "POST",
|
|
129
150
|
path: "/domains",
|
|
130
|
-
body: params
|
|
151
|
+
body: params,
|
|
152
|
+
methodOptions: options
|
|
131
153
|
});
|
|
132
154
|
}
|
|
133
|
-
list(params) {
|
|
155
|
+
list(params, options) {
|
|
134
156
|
return this.client.request({
|
|
135
157
|
method: "GET",
|
|
136
158
|
path: "/domains",
|
|
137
159
|
query: {
|
|
138
160
|
cursor: params?.cursor,
|
|
139
161
|
limit: params?.limit
|
|
140
|
-
}
|
|
162
|
+
},
|
|
163
|
+
methodOptions: options
|
|
141
164
|
});
|
|
142
165
|
}
|
|
143
166
|
listAutoPaginating(params) {
|
|
@@ -145,43 +168,64 @@ var Domains = class extends ApiResource {
|
|
|
145
168
|
limit: params?.limit
|
|
146
169
|
});
|
|
147
170
|
}
|
|
148
|
-
get(id) {
|
|
171
|
+
get(id, options) {
|
|
149
172
|
return this.client.request({
|
|
150
173
|
method: "GET",
|
|
151
|
-
path: `/domains/${id}
|
|
174
|
+
path: `/domains/${encodeURIComponent(id)}`,
|
|
175
|
+
methodOptions: options
|
|
152
176
|
});
|
|
153
177
|
}
|
|
154
|
-
update(id, params) {
|
|
178
|
+
update(id, params, options) {
|
|
155
179
|
return this.client.request({
|
|
156
180
|
method: "PATCH",
|
|
157
|
-
path: `/domains/${id}`,
|
|
158
|
-
body: params
|
|
181
|
+
path: `/domains/${encodeURIComponent(id)}`,
|
|
182
|
+
body: params,
|
|
183
|
+
methodOptions: options
|
|
159
184
|
});
|
|
160
185
|
}
|
|
161
|
-
delete(id) {
|
|
186
|
+
delete(id, options) {
|
|
162
187
|
return this.client.request({
|
|
163
188
|
method: "DELETE",
|
|
164
|
-
path: `/domains/${id}
|
|
189
|
+
path: `/domains/${encodeURIComponent(id)}`,
|
|
190
|
+
methodOptions: options
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
verify(id, options) {
|
|
194
|
+
return this.client.request({
|
|
195
|
+
method: "POST",
|
|
196
|
+
path: `/domains/${encodeURIComponent(id)}/verification`,
|
|
197
|
+
methodOptions: options
|
|
165
198
|
});
|
|
166
199
|
}
|
|
167
|
-
|
|
200
|
+
search(params, options) {
|
|
168
201
|
return this.client.request({
|
|
169
202
|
method: "POST",
|
|
170
|
-
path:
|
|
203
|
+
path: "/domains/search",
|
|
204
|
+
body: params,
|
|
205
|
+
methodOptions: options
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
register(params, options) {
|
|
209
|
+
return this.client.request({
|
|
210
|
+
method: "POST",
|
|
211
|
+
path: "/domains/register",
|
|
212
|
+
body: params,
|
|
213
|
+
methodOptions: options
|
|
171
214
|
});
|
|
172
215
|
}
|
|
173
216
|
};
|
|
174
217
|
|
|
175
218
|
// src/resources/mailboxes.ts
|
|
176
219
|
var Mailboxes = class extends ApiResource {
|
|
177
|
-
create(params) {
|
|
220
|
+
create(params, options) {
|
|
178
221
|
return this.client.request({
|
|
179
222
|
method: "POST",
|
|
180
223
|
path: "/mailboxes",
|
|
181
|
-
body: params
|
|
224
|
+
body: params,
|
|
225
|
+
methodOptions: options
|
|
182
226
|
});
|
|
183
227
|
}
|
|
184
|
-
list(params) {
|
|
228
|
+
list(params, options) {
|
|
185
229
|
return this.client.request({
|
|
186
230
|
method: "GET",
|
|
187
231
|
path: "/mailboxes",
|
|
@@ -189,7 +233,8 @@ var Mailboxes = class extends ApiResource {
|
|
|
189
233
|
domain_id: params?.domain_id,
|
|
190
234
|
cursor: params?.cursor,
|
|
191
235
|
limit: params?.limit
|
|
192
|
-
}
|
|
236
|
+
},
|
|
237
|
+
methodOptions: options
|
|
193
238
|
});
|
|
194
239
|
}
|
|
195
240
|
listAutoPaginating(params) {
|
|
@@ -198,71 +243,124 @@ var Mailboxes = class extends ApiResource {
|
|
|
198
243
|
limit: params?.limit
|
|
199
244
|
});
|
|
200
245
|
}
|
|
201
|
-
get(id) {
|
|
246
|
+
get(id, options) {
|
|
202
247
|
return this.client.request({
|
|
203
248
|
method: "GET",
|
|
204
|
-
path: `/mailboxes/${id}
|
|
249
|
+
path: `/mailboxes/${encodeURIComponent(id)}`,
|
|
250
|
+
methodOptions: options
|
|
205
251
|
});
|
|
206
252
|
}
|
|
207
|
-
update(id, params) {
|
|
253
|
+
update(id, params, options) {
|
|
208
254
|
return this.client.request({
|
|
209
255
|
method: "PATCH",
|
|
210
|
-
path: `/mailboxes/${id}`,
|
|
211
|
-
body: params
|
|
256
|
+
path: `/mailboxes/${encodeURIComponent(id)}`,
|
|
257
|
+
body: params,
|
|
258
|
+
methodOptions: options
|
|
212
259
|
});
|
|
213
260
|
}
|
|
214
|
-
delete(id) {
|
|
261
|
+
delete(id, options) {
|
|
215
262
|
return this.client.request({
|
|
216
263
|
method: "DELETE",
|
|
217
|
-
path: `/mailboxes/${id}
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
uploadAvatar(id, data, contentType) {
|
|
221
|
-
return this.client.request({
|
|
222
|
-
method: "PUT",
|
|
223
|
-
path: `/mailboxes/${id}/avatar`,
|
|
224
|
-
rawBody: data,
|
|
225
|
-
contentType
|
|
264
|
+
path: `/mailboxes/${encodeURIComponent(id)}`,
|
|
265
|
+
methodOptions: options
|
|
226
266
|
});
|
|
227
267
|
}
|
|
228
|
-
|
|
268
|
+
updateAutoReply(id, params, options) {
|
|
229
269
|
return this.client.request({
|
|
230
|
-
method: "
|
|
231
|
-
path: `/mailboxes/${id}/
|
|
270
|
+
method: "PATCH",
|
|
271
|
+
path: `/mailboxes/${encodeURIComponent(id)}/auto-reply`,
|
|
272
|
+
body: params,
|
|
273
|
+
methodOptions: options
|
|
232
274
|
});
|
|
233
275
|
}
|
|
234
276
|
};
|
|
235
277
|
|
|
236
278
|
// src/resources/messages.ts
|
|
237
279
|
var Messages = class extends ApiResource {
|
|
238
|
-
send(params) {
|
|
280
|
+
send(params, options) {
|
|
239
281
|
return this.client.request({
|
|
240
282
|
method: "POST",
|
|
241
283
|
path: "/messages",
|
|
242
|
-
body: params
|
|
284
|
+
body: params,
|
|
285
|
+
methodOptions: options
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
list(params, options) {
|
|
289
|
+
return this.client.request({
|
|
290
|
+
method: "GET",
|
|
291
|
+
path: "/messages",
|
|
292
|
+
query: {
|
|
293
|
+
mailbox_id: params.mailbox_id,
|
|
294
|
+
cursor: params.cursor,
|
|
295
|
+
limit: params.limit
|
|
296
|
+
},
|
|
297
|
+
methodOptions: options
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
listAutoPaginating(params) {
|
|
301
|
+
return new Page(this.client, "/messages", {
|
|
302
|
+
mailbox_id: params.mailbox_id,
|
|
303
|
+
limit: params.limit
|
|
243
304
|
});
|
|
244
305
|
}
|
|
245
|
-
get(id) {
|
|
306
|
+
get(id, options) {
|
|
246
307
|
return this.client.request({
|
|
247
308
|
method: "GET",
|
|
248
|
-
path: `/messages/${id}
|
|
309
|
+
path: `/messages/${encodeURIComponent(id)}`,
|
|
310
|
+
methodOptions: options
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
reply(id, params, options) {
|
|
314
|
+
return this.client.request({
|
|
315
|
+
method: "POST",
|
|
316
|
+
path: `/messages/${encodeURIComponent(id)}/reply`,
|
|
317
|
+
body: params,
|
|
318
|
+
methodOptions: options
|
|
249
319
|
});
|
|
250
320
|
}
|
|
251
321
|
};
|
|
252
322
|
|
|
253
323
|
// src/resources/status.ts
|
|
254
324
|
var Status = class extends ApiResource {
|
|
255
|
-
get() {
|
|
325
|
+
get(options) {
|
|
326
|
+
return this.client.request({
|
|
327
|
+
method: "GET",
|
|
328
|
+
path: "/status",
|
|
329
|
+
methodOptions: options
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
// src/resources/suppressions.ts
|
|
335
|
+
var Suppressions = class extends ApiResource {
|
|
336
|
+
list(params, options) {
|
|
256
337
|
return this.client.request({
|
|
257
338
|
method: "GET",
|
|
258
|
-
path: "/
|
|
339
|
+
path: "/suppressions",
|
|
340
|
+
query: {
|
|
341
|
+
cursor: params?.cursor,
|
|
342
|
+
limit: params?.limit
|
|
343
|
+
},
|
|
344
|
+
methodOptions: options
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
listAutoPaginating(params) {
|
|
348
|
+
return new Page(this.client, "/suppressions", {
|
|
349
|
+
limit: params?.limit
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
remove(email, options) {
|
|
353
|
+
return this.client.request({
|
|
354
|
+
method: "DELETE",
|
|
355
|
+
path: `/suppressions/${encodeURIComponent(email)}`,
|
|
356
|
+
methodOptions: options
|
|
259
357
|
});
|
|
260
358
|
}
|
|
261
359
|
};
|
|
262
360
|
|
|
263
361
|
// src/resources/threads.ts
|
|
264
362
|
var Threads = class extends ApiResource {
|
|
265
|
-
list(params) {
|
|
363
|
+
list(params, options) {
|
|
266
364
|
return this.client.request({
|
|
267
365
|
method: "GET",
|
|
268
366
|
path: "/threads",
|
|
@@ -270,7 +368,8 @@ var Threads = class extends ApiResource {
|
|
|
270
368
|
mailbox_id: params.mailbox_id,
|
|
271
369
|
cursor: params.cursor,
|
|
272
370
|
limit: params.limit
|
|
273
|
-
}
|
|
371
|
+
},
|
|
372
|
+
methodOptions: options
|
|
274
373
|
});
|
|
275
374
|
}
|
|
276
375
|
listAutoPaginating(params) {
|
|
@@ -279,42 +378,46 @@ var Threads = class extends ApiResource {
|
|
|
279
378
|
limit: params.limit
|
|
280
379
|
});
|
|
281
380
|
}
|
|
282
|
-
get(id, params) {
|
|
381
|
+
get(id, params, options) {
|
|
283
382
|
return this.client.request({
|
|
284
383
|
method: "GET",
|
|
285
|
-
path: `/threads/${id}`,
|
|
384
|
+
path: `/threads/${encodeURIComponent(id)}`,
|
|
286
385
|
query: {
|
|
287
386
|
cursor: params?.cursor,
|
|
288
387
|
limit: params?.limit
|
|
289
|
-
}
|
|
388
|
+
},
|
|
389
|
+
methodOptions: options
|
|
290
390
|
});
|
|
291
391
|
}
|
|
292
|
-
reply(id, params) {
|
|
392
|
+
reply(id, params, options) {
|
|
293
393
|
return this.client.request({
|
|
294
394
|
method: "POST",
|
|
295
|
-
path: `/threads/${id}/reply`,
|
|
296
|
-
body: params
|
|
395
|
+
path: `/threads/${encodeURIComponent(id)}/reply`,
|
|
396
|
+
body: params,
|
|
397
|
+
methodOptions: options
|
|
297
398
|
});
|
|
298
399
|
}
|
|
299
400
|
};
|
|
300
401
|
|
|
301
402
|
// src/resources/webhooks.ts
|
|
302
403
|
var Webhooks = class extends ApiResource {
|
|
303
|
-
create(params) {
|
|
404
|
+
create(params, options) {
|
|
304
405
|
return this.client.request({
|
|
305
406
|
method: "POST",
|
|
306
407
|
path: "/webhooks",
|
|
307
|
-
body: params
|
|
408
|
+
body: params,
|
|
409
|
+
methodOptions: options
|
|
308
410
|
});
|
|
309
411
|
}
|
|
310
|
-
list(params) {
|
|
412
|
+
list(params, options) {
|
|
311
413
|
return this.client.request({
|
|
312
414
|
method: "GET",
|
|
313
415
|
path: "/webhooks",
|
|
314
416
|
query: {
|
|
315
417
|
cursor: params?.cursor,
|
|
316
418
|
limit: params?.limit
|
|
317
|
-
}
|
|
419
|
+
},
|
|
420
|
+
methodOptions: options
|
|
318
421
|
});
|
|
319
422
|
}
|
|
320
423
|
listAutoPaginating(params) {
|
|
@@ -322,69 +425,82 @@ var Webhooks = class extends ApiResource {
|
|
|
322
425
|
limit: params?.limit
|
|
323
426
|
});
|
|
324
427
|
}
|
|
325
|
-
get(id) {
|
|
428
|
+
get(id, options) {
|
|
326
429
|
return this.client.request({
|
|
327
430
|
method: "GET",
|
|
328
|
-
path: `/webhooks/${id}
|
|
431
|
+
path: `/webhooks/${encodeURIComponent(id)}`,
|
|
432
|
+
methodOptions: options
|
|
329
433
|
});
|
|
330
434
|
}
|
|
331
|
-
update(id, params) {
|
|
435
|
+
update(id, params, options) {
|
|
332
436
|
return this.client.request({
|
|
333
437
|
method: "PATCH",
|
|
334
|
-
path: `/webhooks/${id}`,
|
|
335
|
-
body: params
|
|
438
|
+
path: `/webhooks/${encodeURIComponent(id)}`,
|
|
439
|
+
body: params,
|
|
440
|
+
methodOptions: options
|
|
336
441
|
});
|
|
337
442
|
}
|
|
338
|
-
delete(id) {
|
|
443
|
+
delete(id, options) {
|
|
339
444
|
return this.client.request({
|
|
340
445
|
method: "DELETE",
|
|
341
|
-
path: `/webhooks/${id}
|
|
446
|
+
path: `/webhooks/${encodeURIComponent(id)}`,
|
|
447
|
+
methodOptions: options
|
|
342
448
|
});
|
|
343
449
|
}
|
|
344
|
-
rotateSecret(id) {
|
|
450
|
+
rotateSecret(id, options) {
|
|
345
451
|
return this.client.request({
|
|
346
452
|
method: "POST",
|
|
347
|
-
path: `/webhooks/${id}/rotate-secret
|
|
453
|
+
path: `/webhooks/${encodeURIComponent(id)}/rotate-secret`,
|
|
454
|
+
methodOptions: options
|
|
348
455
|
});
|
|
349
456
|
}
|
|
350
|
-
test(id) {
|
|
457
|
+
test(id, options) {
|
|
351
458
|
return this.client.request({
|
|
352
459
|
method: "POST",
|
|
353
|
-
path: `/webhooks/${id}/test
|
|
460
|
+
path: `/webhooks/${encodeURIComponent(id)}/test`,
|
|
461
|
+
methodOptions: options
|
|
354
462
|
});
|
|
355
463
|
}
|
|
356
|
-
listDeliveries(id, params) {
|
|
464
|
+
listDeliveries(id, params, options) {
|
|
357
465
|
return this.client.request({
|
|
358
466
|
method: "GET",
|
|
359
|
-
path: `/webhooks/${id}/deliveries`,
|
|
467
|
+
path: `/webhooks/${encodeURIComponent(id)}/deliveries`,
|
|
360
468
|
query: {
|
|
361
469
|
status: params?.status,
|
|
362
470
|
event_type: params?.event_type,
|
|
363
471
|
cursor: params?.cursor,
|
|
364
472
|
limit: params?.limit
|
|
365
|
-
}
|
|
473
|
+
},
|
|
474
|
+
methodOptions: options
|
|
366
475
|
});
|
|
367
476
|
}
|
|
368
477
|
listDeliveriesAutoPaginating(id, params) {
|
|
369
|
-
return new Page(
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
478
|
+
return new Page(
|
|
479
|
+
this.client,
|
|
480
|
+
`/webhooks/${encodeURIComponent(id)}/deliveries`,
|
|
481
|
+
{
|
|
482
|
+
status: params?.status,
|
|
483
|
+
event_type: params?.event_type,
|
|
484
|
+
limit: params?.limit
|
|
485
|
+
}
|
|
486
|
+
);
|
|
374
487
|
}
|
|
375
488
|
};
|
|
376
489
|
|
|
377
490
|
// src/version.ts
|
|
378
|
-
var VERSION = "0.1.
|
|
491
|
+
var VERSION = "0.1.19";
|
|
379
492
|
|
|
380
493
|
// src/client.ts
|
|
381
|
-
var DEFAULT_BASE_URL = "https://
|
|
494
|
+
var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
|
|
382
495
|
var DEFAULT_MAX_RETRIES = 2;
|
|
383
496
|
var DEFAULT_TIMEOUT = 3e4;
|
|
384
497
|
function isRetryableStatus(status) {
|
|
385
498
|
return status === 429 || status >= 500;
|
|
386
499
|
}
|
|
387
|
-
function calculateBackoff(attempt) {
|
|
500
|
+
function calculateBackoff(attempt, retryAfterMs) {
|
|
501
|
+
if (retryAfterMs !== void 0 && retryAfterMs > 0) {
|
|
502
|
+
return retryAfterMs;
|
|
503
|
+
}
|
|
388
504
|
const base = Math.min(2 ** attempt * 500, 8e3);
|
|
389
505
|
const jitter = Math.random() * base * 0.5;
|
|
390
506
|
return base + jitter;
|
|
@@ -397,6 +513,10 @@ function isApiErrorBody(value) {
|
|
|
397
513
|
return typeof error["type"] === "string" && typeof error["message"] === "string";
|
|
398
514
|
}
|
|
399
515
|
var ShipMailClient = class {
|
|
516
|
+
/**
|
|
517
|
+
* Create a new ShipMail client.
|
|
518
|
+
* @param config - API key string or full configuration object.
|
|
519
|
+
*/
|
|
400
520
|
constructor(config) {
|
|
401
521
|
if (typeof config === "string") {
|
|
402
522
|
this.apiKey = config;
|
|
@@ -404,16 +524,19 @@ var ShipMailClient = class {
|
|
|
404
524
|
this.maxRetries = DEFAULT_MAX_RETRIES;
|
|
405
525
|
this.timeout = DEFAULT_TIMEOUT;
|
|
406
526
|
this.fetchFn = globalThis.fetch;
|
|
527
|
+
this.defaultHeaders = {};
|
|
407
528
|
} else {
|
|
408
529
|
this.apiKey = config.apiKey;
|
|
409
530
|
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
410
531
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
411
532
|
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
412
533
|
this.fetchFn = config.fetch ?? globalThis.fetch;
|
|
534
|
+
this.defaultHeaders = config.defaultHeaders ? { ...config.defaultHeaders } : {};
|
|
413
535
|
}
|
|
414
536
|
this.domains = new Domains(this);
|
|
415
537
|
this.mailboxes = new Mailboxes(this);
|
|
416
538
|
this.messages = new Messages(this);
|
|
539
|
+
this.suppressions = new Suppressions(this);
|
|
417
540
|
this.threads = new Threads(this);
|
|
418
541
|
this.webhooks = new Webhooks(this);
|
|
419
542
|
this.status = new Status(this);
|
|
@@ -421,18 +544,25 @@ var ShipMailClient = class {
|
|
|
421
544
|
async request(options) {
|
|
422
545
|
const url = this.buildUrl(options.path, options.query);
|
|
423
546
|
let lastError;
|
|
547
|
+
const methodOpts = options.methodOptions;
|
|
424
548
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
425
549
|
if (attempt > 0) {
|
|
426
|
-
const
|
|
550
|
+
const retryAfterMs = lastError instanceof RateLimitError && lastError.retryAfter !== void 0 ? lastError.retryAfter * 1e3 : void 0;
|
|
551
|
+
const delay = calculateBackoff(attempt - 1, retryAfterMs);
|
|
427
552
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
428
553
|
}
|
|
429
554
|
let response;
|
|
430
555
|
try {
|
|
431
556
|
const headers = {
|
|
557
|
+
...this.defaultHeaders,
|
|
432
558
|
Authorization: `Bearer ${this.apiKey}`,
|
|
433
559
|
"User-Agent": `shipmail-node/${VERSION}`,
|
|
434
|
-
Accept: "application/json"
|
|
560
|
+
Accept: "application/json",
|
|
561
|
+
...methodOpts?.headers
|
|
435
562
|
};
|
|
563
|
+
if (methodOpts?.idempotencyKey) {
|
|
564
|
+
headers["Idempotency-Key"] = methodOpts.idempotencyKey;
|
|
565
|
+
}
|
|
436
566
|
let body = null;
|
|
437
567
|
if (options.rawBody !== void 0) {
|
|
438
568
|
headers["Content-Type"] = options.contentType ?? "application/octet-stream";
|
|
@@ -441,16 +571,15 @@ var ShipMailClient = class {
|
|
|
441
571
|
headers["Content-Type"] = "application/json";
|
|
442
572
|
body = JSON.stringify(options.body);
|
|
443
573
|
}
|
|
574
|
+
const effectiveTimeout = methodOpts?.timeout ?? this.timeout;
|
|
444
575
|
response = await this.fetchFn(url, {
|
|
445
576
|
method: options.method,
|
|
446
577
|
headers,
|
|
447
578
|
body,
|
|
448
|
-
signal: AbortSignal.timeout(
|
|
579
|
+
signal: methodOpts?.signal ?? AbortSignal.timeout(effectiveTimeout)
|
|
449
580
|
});
|
|
450
581
|
} catch (err) {
|
|
451
|
-
lastError = new ConnectionError(
|
|
452
|
-
err instanceof Error ? err.message : "Request failed"
|
|
453
|
-
);
|
|
582
|
+
lastError = new ConnectionError(err instanceof Error ? err.message : "Request failed");
|
|
454
583
|
if (attempt < this.maxRetries) continue;
|
|
455
584
|
throw lastError;
|
|
456
585
|
}
|
|
@@ -469,10 +598,10 @@ var ShipMailClient = class {
|
|
|
469
598
|
if (isApiErrorBody(errorBody)) {
|
|
470
599
|
lastError = mapErrorFromResponse(response.status, errorBody);
|
|
471
600
|
} else {
|
|
472
|
-
lastError = new ShipMailError(
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
);
|
|
601
|
+
lastError = new ShipMailError(`Request failed with status ${response.status}`, {
|
|
602
|
+
status: response.status,
|
|
603
|
+
retryable: isRetryableStatus(response.status)
|
|
604
|
+
});
|
|
476
605
|
}
|
|
477
606
|
if (!lastError.retryable || attempt >= this.maxRetries) {
|
|
478
607
|
throw lastError;
|
|
@@ -496,15 +625,31 @@ var ShipMailClient = class {
|
|
|
496
625
|
// src/types/common.ts
|
|
497
626
|
var WEBHOOK_EVENT_TYPES = [
|
|
498
627
|
"message.received",
|
|
499
|
-
"message.queued",
|
|
500
628
|
"message.sent",
|
|
501
629
|
"message.delivered",
|
|
502
630
|
"message.bounced",
|
|
503
631
|
"message.complained",
|
|
504
632
|
"domain.verified",
|
|
505
633
|
"domain.verification_failed",
|
|
506
|
-
"domain.degraded"
|
|
634
|
+
"domain.degraded",
|
|
635
|
+
"org.reputation_warning",
|
|
636
|
+
"org.sending_throttled",
|
|
637
|
+
"org.sending_suspended",
|
|
638
|
+
"org.reputation_recovered"
|
|
507
639
|
];
|
|
640
|
+
var DOMAIN_STATUSES = ["pending", "verifying", "verified", "degraded", "failed"];
|
|
641
|
+
var MESSAGE_STATUSES = [
|
|
642
|
+
"queued",
|
|
643
|
+
"sent",
|
|
644
|
+
"delivered",
|
|
645
|
+
"bounced",
|
|
646
|
+
"complained",
|
|
647
|
+
"failed"
|
|
648
|
+
];
|
|
649
|
+
var MESSAGE_SOURCES = ["api", "dashboard", "inbound", "smtp"];
|
|
650
|
+
var WEBHOOK_DELIVERY_STATUSES = ["pending", "delivered", "failed"];
|
|
651
|
+
|
|
652
|
+
// src/webhook-verification.ts
|
|
508
653
|
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
509
654
|
function getHeader(headers, name) {
|
|
510
655
|
if (headers instanceof Headers) {
|
|
@@ -512,12 +657,13 @@ function getHeader(headers, name) {
|
|
|
512
657
|
}
|
|
513
658
|
return headers[name] ?? headers[name.toLowerCase()];
|
|
514
659
|
}
|
|
515
|
-
function signPayload(secret, timestamp, body) {
|
|
660
|
+
async function signPayload(secret, timestamp, body) {
|
|
661
|
+
const { createHmac } = await import('crypto');
|
|
516
662
|
const payload = `v1=${timestamp}
|
|
517
663
|
${body}`;
|
|
518
664
|
return createHmac("sha256", secret).update(payload).digest("hex");
|
|
519
665
|
}
|
|
520
|
-
function verifyWebhook(body, headers, secret, options) {
|
|
666
|
+
async function verifyWebhook(body, headers, secret, options) {
|
|
521
667
|
const signature = getHeader(headers, "x-shipmail-signature");
|
|
522
668
|
const timestampStr = getHeader(headers, "x-shipmail-timestamp");
|
|
523
669
|
if (!signature) {
|
|
@@ -535,7 +681,8 @@ function verifyWebhook(body, headers, secret, options) {
|
|
|
535
681
|
if (Math.abs(now - timestamp) > tolerance) {
|
|
536
682
|
throw new WebhookVerificationError("Webhook timestamp is outside tolerance window");
|
|
537
683
|
}
|
|
538
|
-
const expected = signPayload(secret, timestamp, body);
|
|
684
|
+
const expected = await signPayload(secret, timestamp, body);
|
|
685
|
+
const { timingSafeEqual } = await import('crypto');
|
|
539
686
|
const sigBuffer = Buffer.from(signature, "hex");
|
|
540
687
|
const expectedBuffer = Buffer.from(expected, "hex");
|
|
541
688
|
if (sigBuffer.length !== expectedBuffer.length || !timingSafeEqual(sigBuffer, expectedBuffer)) {
|
|
@@ -550,6 +697,6 @@ function verifyWebhook(body, headers, secret, options) {
|
|
|
550
697
|
return parsed;
|
|
551
698
|
}
|
|
552
699
|
|
|
553
|
-
export { AuthenticationError, AuthorizationError, ConflictError, ConnectionError, InternalServerError, NotFoundError, Page, RateLimitError, ShipMailClient, ShipMailError, ValidationError, WEBHOOK_EVENT_TYPES, WebhookVerificationError, ShipMailClient as default, verifyWebhook };
|
|
700
|
+
export { AuthenticationError, AuthorizationError, ConflictError, ConnectionError, DOMAIN_STATUSES, InternalServerError, MESSAGE_SOURCES, MESSAGE_STATUSES, NotFoundError, Page, QuotaExceededError, RateLimitError, ShipMailClient, ShipMailError, ValidationError, WEBHOOK_DELIVERY_STATUSES, WEBHOOK_EVENT_TYPES, WebhookVerificationError, ShipMailClient as default, verifyWebhook };
|
|
554
701
|
//# sourceMappingURL=index.js.map
|
|
555
702
|
//# sourceMappingURL=index.js.map
|