@topmail/sdk 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/dist/index.js ADDED
@@ -0,0 +1,614 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthenticationError: () => AuthenticationError,
24
+ Automations: () => Automations,
25
+ Campaigns: () => Campaigns,
26
+ Contacts: () => Contacts,
27
+ Conversions: () => Conversions,
28
+ Domains: () => Domains,
29
+ Email: () => Email,
30
+ ForbiddenError: () => ForbiddenError,
31
+ Health: () => Health,
32
+ HttpClient: () => HttpClient,
33
+ Lists: () => Lists,
34
+ NotFoundError: () => NotFoundError,
35
+ RateLimitError: () => RateLimitError,
36
+ Segments: () => Segments,
37
+ ServerError: () => ServerError,
38
+ Suppressions: () => Suppressions,
39
+ Tags: () => Tags,
40
+ Templates: () => Templates,
41
+ TopMail: () => TopMail,
42
+ TopMailError: () => TopMailError,
43
+ Tracking: () => Tracking,
44
+ ValidationError: () => ValidationError,
45
+ Webhooks: () => Webhooks
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+
49
+ // src/errors.ts
50
+ var TopMailError = class extends Error {
51
+ constructor(message, code, statusCode) {
52
+ super(message);
53
+ this.name = "TopMailError";
54
+ this.code = code;
55
+ this.statusCode = statusCode;
56
+ }
57
+ };
58
+ var ValidationError = class extends TopMailError {
59
+ constructor(message, code = "validation_error") {
60
+ super(message, code, 400);
61
+ this.name = "ValidationError";
62
+ }
63
+ };
64
+ var AuthenticationError = class extends TopMailError {
65
+ constructor(message, code = "authentication_error") {
66
+ super(message, code, 401);
67
+ this.name = "AuthenticationError";
68
+ }
69
+ };
70
+ var ForbiddenError = class extends TopMailError {
71
+ constructor(message, code = "forbidden") {
72
+ super(message, code, 403);
73
+ this.name = "ForbiddenError";
74
+ }
75
+ };
76
+ var NotFoundError = class extends TopMailError {
77
+ constructor(message, code = "not_found") {
78
+ super(message, code, 404);
79
+ this.name = "NotFoundError";
80
+ }
81
+ };
82
+ var RateLimitError = class extends TopMailError {
83
+ constructor(message, retryAfter = null, code = "rate_limit_exceeded") {
84
+ super(message, code, 429);
85
+ this.name = "RateLimitError";
86
+ this.retryAfter = retryAfter;
87
+ }
88
+ };
89
+ var ServerError = class extends TopMailError {
90
+ constructor(message, statusCode = 500, code = "server_error") {
91
+ super(message, code, statusCode);
92
+ this.name = "ServerError";
93
+ }
94
+ };
95
+
96
+ // src/client.ts
97
+ var DEFAULT_MAX_RETRIES = 3;
98
+ var INITIAL_RETRY_DELAY_MS = 1e3;
99
+ var HttpClient = class {
100
+ constructor(options) {
101
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
102
+ this.apiKey = options.apiKey;
103
+ this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
104
+ }
105
+ async get(path, params) {
106
+ const url = this.buildUrl(path, params);
107
+ return this.request(url, { method: "GET" });
108
+ }
109
+ async post(path, body) {
110
+ const url = this.buildUrl(path);
111
+ return this.request(url, {
112
+ method: "POST",
113
+ body: body !== void 0 ? JSON.stringify(body) : void 0
114
+ });
115
+ }
116
+ async put(path, body) {
117
+ const url = this.buildUrl(path);
118
+ return this.request(url, {
119
+ method: "PUT",
120
+ body: body !== void 0 ? JSON.stringify(body) : void 0
121
+ });
122
+ }
123
+ async patch(path, body) {
124
+ const url = this.buildUrl(path);
125
+ return this.request(url, {
126
+ method: "PATCH",
127
+ body: body !== void 0 ? JSON.stringify(body) : void 0
128
+ });
129
+ }
130
+ async delete(path, body) {
131
+ const url = this.buildUrl(path);
132
+ return this.request(url, {
133
+ method: "DELETE",
134
+ body: body !== void 0 ? JSON.stringify(body) : void 0
135
+ });
136
+ }
137
+ buildUrl(path, params) {
138
+ const url = new URL(`${this.baseUrl}${path}`);
139
+ if (params) {
140
+ for (const [key, value] of Object.entries(params)) {
141
+ if (value !== void 0 && value !== null) {
142
+ url.searchParams.set(key, String(value));
143
+ }
144
+ }
145
+ }
146
+ return url.toString();
147
+ }
148
+ async request(url, init) {
149
+ const headers = {
150
+ "Authorization": `Bearer ${this.apiKey}`,
151
+ "Content-Type": "application/json"
152
+ };
153
+ let lastError;
154
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
155
+ if (attempt > 0) {
156
+ const delay = this.getRetryDelay(attempt, lastError);
157
+ await this.sleep(delay);
158
+ }
159
+ let response;
160
+ try {
161
+ response = await fetch(url, { ...init, headers });
162
+ } catch (err) {
163
+ lastError = err instanceof Error ? err : new Error(String(err));
164
+ continue;
165
+ }
166
+ if (response.ok) {
167
+ if (response.status === 204) {
168
+ return void 0;
169
+ }
170
+ return await response.json();
171
+ }
172
+ let errorBody;
173
+ try {
174
+ errorBody = await response.json();
175
+ } catch {
176
+ }
177
+ const errorMessage = errorBody?.error?.message ?? response.statusText;
178
+ const errorCode = errorBody?.error?.code ?? "unknown_error";
179
+ if (response.status === 429 || response.status >= 500) {
180
+ if (response.status === 429) {
181
+ const retryAfter = this.parseRetryAfter(response);
182
+ lastError = new RateLimitError(errorMessage, retryAfter, errorCode);
183
+ } else {
184
+ lastError = new ServerError(errorMessage, response.status, errorCode);
185
+ }
186
+ if (attempt < this.maxRetries) {
187
+ continue;
188
+ }
189
+ throw lastError;
190
+ }
191
+ throw this.createError(response.status, errorMessage, errorCode);
192
+ }
193
+ throw lastError ?? new TopMailError("Request failed", "unknown_error", 0);
194
+ }
195
+ createError(status, message, code) {
196
+ switch (status) {
197
+ case 400:
198
+ return new ValidationError(message, code);
199
+ case 401:
200
+ return new AuthenticationError(message, code);
201
+ case 403:
202
+ return new ForbiddenError(message, code);
203
+ case 404:
204
+ return new NotFoundError(message, code);
205
+ case 429:
206
+ return new RateLimitError(message, null, code);
207
+ default:
208
+ if (status >= 500) {
209
+ return new ServerError(message, status, code);
210
+ }
211
+ return new TopMailError(message, code, status);
212
+ }
213
+ }
214
+ getRetryDelay(attempt, lastError) {
215
+ if (lastError instanceof RateLimitError && lastError.retryAfter !== null) {
216
+ return lastError.retryAfter * 1e3;
217
+ }
218
+ return INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt - 1);
219
+ }
220
+ parseRetryAfter(response) {
221
+ const header = response.headers.get("retry-after");
222
+ if (!header) return null;
223
+ const seconds = Number(header);
224
+ return isNaN(seconds) ? null : seconds;
225
+ }
226
+ sleep(ms) {
227
+ return new Promise((resolve) => setTimeout(resolve, ms));
228
+ }
229
+ };
230
+
231
+ // src/resources/contacts.ts
232
+ var Contacts = class {
233
+ constructor(client) {
234
+ this.client = client;
235
+ }
236
+ async list(params) {
237
+ return this.client.get("/v1/contacts", params);
238
+ }
239
+ async get(id) {
240
+ return this.client.get(`/v1/contacts/${id}`);
241
+ }
242
+ async create(data) {
243
+ return this.client.post("/v1/contacts", data);
244
+ }
245
+ async update(id, data) {
246
+ return this.client.patch(`/v1/contacts/${id}`, data);
247
+ }
248
+ async delete(id) {
249
+ await this.client.delete(`/v1/contacts/${id}`);
250
+ }
251
+ };
252
+
253
+ // src/resources/lists.ts
254
+ var ListMembers = class {
255
+ constructor(client) {
256
+ this.client = client;
257
+ }
258
+ async list(listId, params) {
259
+ return this.client.get(
260
+ `/v1/lists/${listId}/members`,
261
+ params
262
+ );
263
+ }
264
+ async add(listId, contactIds) {
265
+ return this.client.post(
266
+ `/v1/lists/${listId}/members`,
267
+ { contact_ids: contactIds }
268
+ );
269
+ }
270
+ async remove(listId, contactIds) {
271
+ await this.client.delete(`/v1/lists/${listId}/members`, { contact_ids: contactIds });
272
+ }
273
+ };
274
+ var Lists = class {
275
+ constructor(client) {
276
+ this.client = client;
277
+ this.members = new ListMembers(client);
278
+ }
279
+ async list(params) {
280
+ return this.client.get("/v1/lists", params);
281
+ }
282
+ async get(id) {
283
+ return this.client.get(`/v1/lists/${id}`);
284
+ }
285
+ async create(data) {
286
+ return this.client.post("/v1/lists", data);
287
+ }
288
+ async update(id, data) {
289
+ return this.client.patch(`/v1/lists/${id}`, data);
290
+ }
291
+ async delete(id) {
292
+ await this.client.delete(`/v1/lists/${id}`);
293
+ }
294
+ };
295
+
296
+ // src/resources/campaigns.ts
297
+ var Campaigns = class {
298
+ constructor(client) {
299
+ this.client = client;
300
+ }
301
+ async list(params) {
302
+ return this.client.get("/v1/campaigns", params);
303
+ }
304
+ async get(id) {
305
+ return this.client.get(`/v1/campaigns/${id}`);
306
+ }
307
+ };
308
+
309
+ // src/resources/templates.ts
310
+ var Templates = class {
311
+ constructor(client) {
312
+ this.client = client;
313
+ }
314
+ async list(params) {
315
+ return this.client.get("/v1/templates", params);
316
+ }
317
+ async get(id) {
318
+ return this.client.get(`/v1/templates/${id}`);
319
+ }
320
+ async create(data) {
321
+ return this.client.post("/v1/templates", data);
322
+ }
323
+ };
324
+
325
+ // src/resources/email.ts
326
+ var Email = class {
327
+ constructor(client) {
328
+ this.client = client;
329
+ }
330
+ async send(data) {
331
+ return this.client.post("/v1/email/send", data);
332
+ }
333
+ async batch(data) {
334
+ return this.client.post("/v1/email/batch", data);
335
+ }
336
+ async batchStatus(batchId) {
337
+ return this.client.get(`/v1/email/batch/${batchId}`);
338
+ }
339
+ async messageStatus(messageId) {
340
+ return this.client.get(`/v1/email/${messageId}/status`);
341
+ }
342
+ };
343
+
344
+ // src/resources/suppressions.ts
345
+ var Suppressions = class {
346
+ constructor(client) {
347
+ this.client = client;
348
+ }
349
+ async list(params) {
350
+ return this.client.get("/v1/suppressions", params);
351
+ }
352
+ async add(data) {
353
+ return this.client.post("/v1/suppressions", data);
354
+ }
355
+ async remove(email) {
356
+ await this.client.delete(`/v1/suppressions/${encodeURIComponent(email)}`);
357
+ }
358
+ };
359
+
360
+ // src/resources/webhooks.ts
361
+ var Webhooks = class {
362
+ constructor(client) {
363
+ this.client = client;
364
+ }
365
+ async subscribe(data) {
366
+ return this.client.post("/v1/webhooks/triggers", data);
367
+ }
368
+ async unsubscribe(id) {
369
+ await this.client.delete(`/v1/webhooks/triggers?id=${id}`);
370
+ }
371
+ async test(id) {
372
+ return this.client.post(`/v1/webhooks/${id}/test`);
373
+ }
374
+ };
375
+
376
+ // src/resources/tracking.ts
377
+ var Tracking = class {
378
+ constructor(client) {
379
+ this.client = client;
380
+ }
381
+ async productView(data) {
382
+ return this.client.post("/v1/track/product-view", data);
383
+ }
384
+ };
385
+
386
+ // src/resources/conversions.ts
387
+ var Conversions = class {
388
+ constructor(client) {
389
+ this.client = client;
390
+ }
391
+ async list(params) {
392
+ return this.client.get("/v1/conversions", params);
393
+ }
394
+ async create(data) {
395
+ return this.client.post("/v1/conversions", data);
396
+ }
397
+ };
398
+
399
+ // src/resources/segments.ts
400
+ var Segments = class {
401
+ constructor(client) {
402
+ this.client = client;
403
+ }
404
+ async list(params) {
405
+ return this.client.get("/v1/segments", params);
406
+ }
407
+ async get(id) {
408
+ return this.client.get(`/v1/segments/${id}`);
409
+ }
410
+ async create(data) {
411
+ return this.client.post("/v1/segments", data);
412
+ }
413
+ async update(id, data) {
414
+ return this.client.patch(`/v1/segments/${id}`, data);
415
+ }
416
+ async delete(id) {
417
+ await this.client.delete(`/v1/segments/${id}`);
418
+ }
419
+ async estimateCount(id) {
420
+ return this.client.post(`/v1/segments/${id}/estimate`);
421
+ }
422
+ async listContacts(id, params) {
423
+ return this.client.get(`/v1/segments/${id}/contacts`, params);
424
+ }
425
+ };
426
+
427
+ // src/resources/tags.ts
428
+ var TagContacts = class {
429
+ constructor(client) {
430
+ this.client = client;
431
+ }
432
+ async list(tagId, params) {
433
+ return this.client.get(
434
+ `/v1/tags/${tagId}/contacts`,
435
+ params
436
+ );
437
+ }
438
+ async assign(tagId, contactIds) {
439
+ return this.client.post(
440
+ `/v1/tags/${tagId}/contacts`,
441
+ { contact_ids: contactIds }
442
+ );
443
+ }
444
+ async remove(tagId, contactIds) {
445
+ return this.client.delete(
446
+ `/v1/tags/${tagId}/contacts`,
447
+ { contact_ids: contactIds }
448
+ );
449
+ }
450
+ };
451
+ var Tags = class {
452
+ constructor(client) {
453
+ this.client = client;
454
+ this.contacts = new TagContacts(client);
455
+ }
456
+ async list(params) {
457
+ return this.client.get("/v1/tags", params);
458
+ }
459
+ async get(id) {
460
+ return this.client.get(`/v1/tags/${id}`);
461
+ }
462
+ async create(data) {
463
+ return this.client.post("/v1/tags", data);
464
+ }
465
+ async update(id, data) {
466
+ return this.client.patch(`/v1/tags/${id}`, data);
467
+ }
468
+ async delete(id) {
469
+ await this.client.delete(`/v1/tags/${id}`);
470
+ }
471
+ };
472
+
473
+ // src/resources/automations.ts
474
+ var Automations = class {
475
+ constructor(client) {
476
+ this.client = client;
477
+ }
478
+ async create(data) {
479
+ return this.client.post("/v1/automations", data);
480
+ }
481
+ async list(params) {
482
+ return this.client.get("/v1/automations", params);
483
+ }
484
+ async get(id) {
485
+ return this.client.get(`/v1/automations/${id}`);
486
+ }
487
+ async update(id, data) {
488
+ return this.client.patch(`/v1/automations/${id}`, data);
489
+ }
490
+ async activate(id) {
491
+ return this.update(id, { status: "active" });
492
+ }
493
+ async pause(id) {
494
+ return this.update(id, { status: "paused" });
495
+ }
496
+ async delete(id) {
497
+ await this.client.delete(`/v1/automations/${id}`);
498
+ }
499
+ async addStep(id, data) {
500
+ return this.client.post(`/v1/automations/${id}/steps`, data);
501
+ }
502
+ async updateStep(automationId, stepId, data) {
503
+ return this.client.patch(`/v1/automations/${automationId}/steps/${stepId}`, data);
504
+ }
505
+ async deleteStep(automationId, stepId) {
506
+ await this.client.delete(`/v1/automations/${automationId}/steps/${stepId}`);
507
+ }
508
+ async batchUpdateSteps(id, data) {
509
+ return this.client.put(`/v1/automations/${id}/steps`, data);
510
+ }
511
+ async trigger(id, data) {
512
+ return this.client.post(`/v1/automations/${id}/trigger`, data);
513
+ }
514
+ async listRuns(id, params) {
515
+ return this.client.get(
516
+ `/v1/automations/${id}/runs`,
517
+ params
518
+ );
519
+ }
520
+ async cancelRun(automationId, runId) {
521
+ return this.client.post(
522
+ `/v1/automations/${automationId}/runs/${runId}/cancel`,
523
+ {}
524
+ );
525
+ }
526
+ };
527
+
528
+ // src/resources/domains.ts
529
+ var Domains = class {
530
+ constructor(client) {
531
+ this.client = client;
532
+ }
533
+ async list() {
534
+ return this.client.get("/v1/domains");
535
+ }
536
+ async get(id) {
537
+ return this.client.get(`/v1/domains/${id}`);
538
+ }
539
+ async create(data) {
540
+ return this.client.post("/v1/domains", data);
541
+ }
542
+ async delete(id) {
543
+ await this.client.delete(`/v1/domains/${id}`);
544
+ }
545
+ async verify(id) {
546
+ return this.client.post(`/v1/domains/${id}/verify`);
547
+ }
548
+ };
549
+
550
+ // src/resources/health.ts
551
+ var Health = class {
552
+ constructor(client) {
553
+ this.client = client;
554
+ }
555
+ async check() {
556
+ return this.client.get("/v1/health");
557
+ }
558
+ };
559
+
560
+ // src/index.ts
561
+ var DEFAULT_BASE_URL = "https://api.topmail.so/api";
562
+ var TopMail = class {
563
+ constructor(apiKey, options) {
564
+ if (!apiKey) {
565
+ throw new Error("API key is required");
566
+ }
567
+ this.isSandbox = apiKey.startsWith("tm_test_");
568
+ const client = new HttpClient({
569
+ baseUrl: options?.baseUrl ?? DEFAULT_BASE_URL,
570
+ apiKey
571
+ });
572
+ this.contacts = new Contacts(client);
573
+ this.lists = new Lists(client);
574
+ this.campaigns = new Campaigns(client);
575
+ this.templates = new Templates(client);
576
+ this.email = new Email(client);
577
+ this.suppressions = new Suppressions(client);
578
+ this.webhooks = new Webhooks(client);
579
+ this.tracking = new Tracking(client);
580
+ this.conversions = new Conversions(client);
581
+ this.segments = new Segments(client);
582
+ this.tags = new Tags(client);
583
+ this.automations = new Automations(client);
584
+ this.domains = new Domains(client);
585
+ this.health = new Health(client);
586
+ }
587
+ };
588
+ // Annotate the CommonJS export names for ESM import in node:
589
+ 0 && (module.exports = {
590
+ AuthenticationError,
591
+ Automations,
592
+ Campaigns,
593
+ Contacts,
594
+ Conversions,
595
+ Domains,
596
+ Email,
597
+ ForbiddenError,
598
+ Health,
599
+ HttpClient,
600
+ Lists,
601
+ NotFoundError,
602
+ RateLimitError,
603
+ Segments,
604
+ ServerError,
605
+ Suppressions,
606
+ Tags,
607
+ Templates,
608
+ TopMail,
609
+ TopMailError,
610
+ Tracking,
611
+ ValidationError,
612
+ Webhooks
613
+ });
614
+ //# sourceMappingURL=index.js.map