lumail 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/cli.js +3152 -0
- package/dist/index.cjs +364 -0
- package/dist/index.js +332 -0
- package/package.json +50 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// ../../src/lib/lumail-sdk/index.ts
|
|
30
|
+
var exports_lumail_sdk = {};
|
|
31
|
+
__export(exports_lumail_sdk, {
|
|
32
|
+
LumailValidationError: () => LumailValidationError,
|
|
33
|
+
LumailRateLimitError: () => LumailRateLimitError,
|
|
34
|
+
LumailPaymentRequiredError: () => LumailPaymentRequiredError,
|
|
35
|
+
LumailNotFoundError: () => LumailNotFoundError,
|
|
36
|
+
LumailError: () => LumailError,
|
|
37
|
+
LumailAuthenticationError: () => LumailAuthenticationError,
|
|
38
|
+
Lumail: () => Lumail
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(exports_lumail_sdk);
|
|
41
|
+
|
|
42
|
+
// ../../src/lib/lumail-sdk/errors.ts
|
|
43
|
+
class LumailError extends Error {
|
|
44
|
+
status;
|
|
45
|
+
code;
|
|
46
|
+
constructor(message, status, code) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = "LumailError";
|
|
49
|
+
this.status = status;
|
|
50
|
+
this.code = code;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class LumailAuthenticationError extends LumailError {
|
|
55
|
+
constructor(message = "Invalid or missing API key") {
|
|
56
|
+
super(message, 401, "AUTHENTICATION_ERROR");
|
|
57
|
+
this.name = "LumailAuthenticationError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class LumailRateLimitError extends LumailError {
|
|
62
|
+
retryAfter;
|
|
63
|
+
constructor(message = "Rate limit exceeded", retryAfter = null) {
|
|
64
|
+
super(message, 429, "RATE_LIMIT_ERROR");
|
|
65
|
+
this.name = "LumailRateLimitError";
|
|
66
|
+
this.retryAfter = retryAfter;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class LumailValidationError extends LumailError {
|
|
71
|
+
constructor(message) {
|
|
72
|
+
super(message, 400, "VALIDATION_ERROR");
|
|
73
|
+
this.name = "LumailValidationError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class LumailNotFoundError extends LumailError {
|
|
78
|
+
constructor(message = "Resource not found") {
|
|
79
|
+
super(message, 404, "NOT_FOUND");
|
|
80
|
+
this.name = "LumailNotFoundError";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class LumailPaymentRequiredError extends LumailError {
|
|
85
|
+
constructor(message = "Plan limit reached") {
|
|
86
|
+
super(message, 402, "PLAN_LIMIT_REACHED");
|
|
87
|
+
this.name = "LumailPaymentRequiredError";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ../../src/lib/lumail-sdk/client.ts
|
|
92
|
+
var DEFAULT_BASE_URL = "https://lumail.io/api";
|
|
93
|
+
var DEFAULT_TIMEOUT = 30000;
|
|
94
|
+
var RETRY_DELAYS = [1000, 2000, 4000];
|
|
95
|
+
var IDEMPOTENT_METHODS = new Set(["GET", "PUT", "DELETE"]);
|
|
96
|
+
|
|
97
|
+
class LumailClient {
|
|
98
|
+
apiKey;
|
|
99
|
+
baseUrl;
|
|
100
|
+
constructor(apiKey, baseUrl) {
|
|
101
|
+
if (!apiKey?.trim()) {
|
|
102
|
+
throw new Error("Lumail API key is required. Get yours at lumail.io/settings");
|
|
103
|
+
}
|
|
104
|
+
this.apiKey = apiKey;
|
|
105
|
+
this.baseUrl = (baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
106
|
+
}
|
|
107
|
+
async request(method, path, options) {
|
|
108
|
+
const url = this.buildUrl(path, options?.params);
|
|
109
|
+
const headers = {
|
|
110
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
111
|
+
"Content-Type": "application/json"
|
|
112
|
+
};
|
|
113
|
+
const isIdempotent = IDEMPOTENT_METHODS.has(method.toUpperCase());
|
|
114
|
+
let lastError = null;
|
|
115
|
+
const maxRetries = isIdempotent ? RETRY_DELAYS.length : 0;
|
|
116
|
+
for (let attempt = 0;attempt <= maxRetries; attempt++) {
|
|
117
|
+
try {
|
|
118
|
+
const signal = options?.signal ?? AbortSignal.timeout(DEFAULT_TIMEOUT);
|
|
119
|
+
const response = await fetch(url, {
|
|
120
|
+
method,
|
|
121
|
+
headers,
|
|
122
|
+
body: options?.body ? JSON.stringify(options.body) : undefined,
|
|
123
|
+
signal
|
|
124
|
+
});
|
|
125
|
+
if (response.ok) {
|
|
126
|
+
const data = await response.json();
|
|
127
|
+
if (data.success === false) {
|
|
128
|
+
throw new LumailError(data.message ?? "Request failed", response.status, data.code);
|
|
129
|
+
}
|
|
130
|
+
return data;
|
|
131
|
+
}
|
|
132
|
+
if (response.status === 429 && isIdempotent && attempt < maxRetries) {
|
|
133
|
+
await sleep(parseRetryAfter(response, RETRY_DELAYS[attempt]));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
throw await this.handleErrorResponse(response);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (error instanceof LumailError) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
lastError = error;
|
|
142
|
+
const isNetworkError = error instanceof TypeError || error.name === "AbortError";
|
|
143
|
+
if (isNetworkError && isIdempotent && attempt < maxRetries) {
|
|
144
|
+
await sleep(RETRY_DELAYS[attempt]);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
throw lastError ?? new LumailError("Request failed after retries", 500);
|
|
151
|
+
}
|
|
152
|
+
buildUrl(path, params) {
|
|
153
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
154
|
+
if (params) {
|
|
155
|
+
for (const [key, value] of Object.entries(params)) {
|
|
156
|
+
if (value !== undefined) {
|
|
157
|
+
url.searchParams.set(key, String(value));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return url.toString();
|
|
162
|
+
}
|
|
163
|
+
async handleErrorResponse(response) {
|
|
164
|
+
let body = {};
|
|
165
|
+
try {
|
|
166
|
+
body = await response.json();
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
const message = body.message ?? body.error ?? response.statusText;
|
|
170
|
+
const code = body.code;
|
|
171
|
+
switch (response.status) {
|
|
172
|
+
case 401:
|
|
173
|
+
return new LumailAuthenticationError(message);
|
|
174
|
+
case 402:
|
|
175
|
+
return new LumailPaymentRequiredError(message);
|
|
176
|
+
case 404:
|
|
177
|
+
return new LumailNotFoundError(message);
|
|
178
|
+
case 429: {
|
|
179
|
+
const retryAfter = parseRetryAfter(response, null);
|
|
180
|
+
return new LumailRateLimitError(message, retryAfter);
|
|
181
|
+
}
|
|
182
|
+
default:
|
|
183
|
+
if (response.status >= 400 && response.status < 500) {
|
|
184
|
+
return new LumailValidationError(message);
|
|
185
|
+
}
|
|
186
|
+
return new LumailError(message, response.status, code);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function parseRetryAfter(response, fallback) {
|
|
191
|
+
const header = response.headers.get("Retry-After");
|
|
192
|
+
if (!header)
|
|
193
|
+
return fallback;
|
|
194
|
+
const seconds = Number(header);
|
|
195
|
+
if (!Number.isNaN(seconds))
|
|
196
|
+
return seconds * 1000;
|
|
197
|
+
const date = new Date(header).getTime();
|
|
198
|
+
if (!Number.isNaN(date))
|
|
199
|
+
return Math.max(0, date - Date.now());
|
|
200
|
+
return fallback;
|
|
201
|
+
}
|
|
202
|
+
async function sleep(ms) {
|
|
203
|
+
if (ms === null || ms <= 0)
|
|
204
|
+
return;
|
|
205
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ../../src/lib/lumail-sdk/resources/campaigns.ts
|
|
209
|
+
class Campaigns {
|
|
210
|
+
client;
|
|
211
|
+
constructor(client) {
|
|
212
|
+
this.client = client;
|
|
213
|
+
}
|
|
214
|
+
async list(params) {
|
|
215
|
+
return this.client.request("GET", "/v1/campaigns", {
|
|
216
|
+
params
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
async create(params) {
|
|
220
|
+
return this.client.request("POST", "/v1/campaigns", {
|
|
221
|
+
body: params
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async get(campaignId) {
|
|
225
|
+
return this.client.request("GET", `/v1/campaigns/${encodeURIComponent(campaignId)}`);
|
|
226
|
+
}
|
|
227
|
+
async update(campaignId, params) {
|
|
228
|
+
return this.client.request("PATCH", `/v1/campaigns/${encodeURIComponent(campaignId)}`, { body: params });
|
|
229
|
+
}
|
|
230
|
+
async delete(campaignId) {
|
|
231
|
+
return this.client.request("DELETE", `/v1/campaigns/${encodeURIComponent(campaignId)}`);
|
|
232
|
+
}
|
|
233
|
+
async send(campaignId, params) {
|
|
234
|
+
return this.client.request("POST", `/v1/campaigns/${encodeURIComponent(campaignId)}/send`, { body: params ?? {} });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ../../src/lib/lumail-sdk/resources/emails.ts
|
|
239
|
+
class Emails {
|
|
240
|
+
client;
|
|
241
|
+
constructor(client) {
|
|
242
|
+
this.client = client;
|
|
243
|
+
}
|
|
244
|
+
async send(params) {
|
|
245
|
+
return this.client.request("POST", "/v1/emails", {
|
|
246
|
+
body: params
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async verify(params) {
|
|
250
|
+
return this.client.request("POST", "/v1/emails/verify", {
|
|
251
|
+
body: params
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ../../src/lib/lumail-sdk/resources/events.ts
|
|
257
|
+
class Events {
|
|
258
|
+
client;
|
|
259
|
+
constructor(client) {
|
|
260
|
+
this.client = client;
|
|
261
|
+
}
|
|
262
|
+
async create(params) {
|
|
263
|
+
return this.client.request("POST", "/v1/events", {
|
|
264
|
+
body: params
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ../../src/lib/lumail-sdk/resources/subscribers.ts
|
|
270
|
+
class Subscribers {
|
|
271
|
+
client;
|
|
272
|
+
constructor(client) {
|
|
273
|
+
this.client = client;
|
|
274
|
+
}
|
|
275
|
+
async create(params) {
|
|
276
|
+
return this.client.request("POST", "/v1/subscribers", {
|
|
277
|
+
body: params
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
async get(idOrEmail) {
|
|
281
|
+
return this.client.request("GET", `/v1/subscribers/${encodeURIComponent(idOrEmail)}`);
|
|
282
|
+
}
|
|
283
|
+
async update(idOrEmail, params) {
|
|
284
|
+
return this.client.request("PATCH", `/v1/subscribers/${encodeURIComponent(idOrEmail)}`, { body: params });
|
|
285
|
+
}
|
|
286
|
+
async delete(idOrEmail) {
|
|
287
|
+
return this.client.request("DELETE", `/v1/subscribers/${encodeURIComponent(idOrEmail)}`);
|
|
288
|
+
}
|
|
289
|
+
async unsubscribe(idOrEmail) {
|
|
290
|
+
return this.client.request("POST", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/unsubscribe`);
|
|
291
|
+
}
|
|
292
|
+
async addTags(idOrEmail, tags) {
|
|
293
|
+
return this.client.request("POST", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/tags`, { body: { tags } });
|
|
294
|
+
}
|
|
295
|
+
async removeTags(idOrEmail, tags) {
|
|
296
|
+
return this.client.request("DELETE", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/tags`, { params: { tags: JSON.stringify(tags) } });
|
|
297
|
+
}
|
|
298
|
+
async listEvents(idOrEmail, params) {
|
|
299
|
+
return this.client.request("GET", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/events`, {
|
|
300
|
+
params: {
|
|
301
|
+
...params,
|
|
302
|
+
eventTypes: params?.eventTypes ? JSON.stringify(params.eventTypes) : undefined
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ../../src/lib/lumail-sdk/resources/tags.ts
|
|
309
|
+
class Tags {
|
|
310
|
+
client;
|
|
311
|
+
constructor(client) {
|
|
312
|
+
this.client = client;
|
|
313
|
+
}
|
|
314
|
+
async list() {
|
|
315
|
+
return this.client.request("GET", "/v1/tags");
|
|
316
|
+
}
|
|
317
|
+
async create(params) {
|
|
318
|
+
return this.client.request("POST", "/v1/tags", {
|
|
319
|
+
body: params
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
async get(idOrName) {
|
|
323
|
+
return this.client.request("GET", `/v1/tags/${encodeURIComponent(idOrName)}`);
|
|
324
|
+
}
|
|
325
|
+
async update(idOrName, params) {
|
|
326
|
+
return this.client.request("PATCH", `/v1/tags/${encodeURIComponent(idOrName)}`, { body: params });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ../../src/lib/lumail-sdk/resources/tools.ts
|
|
331
|
+
class Tools {
|
|
332
|
+
client;
|
|
333
|
+
constructor(client) {
|
|
334
|
+
this.client = client;
|
|
335
|
+
}
|
|
336
|
+
async list() {
|
|
337
|
+
return this.client.request("GET", "/v2/tools");
|
|
338
|
+
}
|
|
339
|
+
async get(toolName) {
|
|
340
|
+
return this.client.request("GET", `/v2/tools/${encodeURIComponent(toolName)}`);
|
|
341
|
+
}
|
|
342
|
+
async run(toolName, params) {
|
|
343
|
+
return this.client.request("POST", `/v2/tools/${encodeURIComponent(toolName)}`, { body: params ?? {} });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// ../../src/lib/lumail-sdk/index.ts
|
|
348
|
+
class Lumail {
|
|
349
|
+
subscribers;
|
|
350
|
+
campaigns;
|
|
351
|
+
emails;
|
|
352
|
+
tags;
|
|
353
|
+
events;
|
|
354
|
+
tools;
|
|
355
|
+
constructor(options) {
|
|
356
|
+
const client = new LumailClient(options.apiKey, options.baseUrl);
|
|
357
|
+
this.subscribers = new Subscribers(client);
|
|
358
|
+
this.campaigns = new Campaigns(client);
|
|
359
|
+
this.emails = new Emails(client);
|
|
360
|
+
this.tags = new Tags(client);
|
|
361
|
+
this.events = new Events(client);
|
|
362
|
+
this.tools = new Tools(client);
|
|
363
|
+
}
|
|
364
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// ../../src/lib/lumail-sdk/errors.ts
|
|
2
|
+
class LumailError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
constructor(message, status, code) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "LumailError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class LumailAuthenticationError extends LumailError {
|
|
14
|
+
constructor(message = "Invalid or missing API key") {
|
|
15
|
+
super(message, 401, "AUTHENTICATION_ERROR");
|
|
16
|
+
this.name = "LumailAuthenticationError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class LumailRateLimitError extends LumailError {
|
|
21
|
+
retryAfter;
|
|
22
|
+
constructor(message = "Rate limit exceeded", retryAfter = null) {
|
|
23
|
+
super(message, 429, "RATE_LIMIT_ERROR");
|
|
24
|
+
this.name = "LumailRateLimitError";
|
|
25
|
+
this.retryAfter = retryAfter;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class LumailValidationError extends LumailError {
|
|
30
|
+
constructor(message) {
|
|
31
|
+
super(message, 400, "VALIDATION_ERROR");
|
|
32
|
+
this.name = "LumailValidationError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class LumailNotFoundError extends LumailError {
|
|
37
|
+
constructor(message = "Resource not found") {
|
|
38
|
+
super(message, 404, "NOT_FOUND");
|
|
39
|
+
this.name = "LumailNotFoundError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class LumailPaymentRequiredError extends LumailError {
|
|
44
|
+
constructor(message = "Plan limit reached") {
|
|
45
|
+
super(message, 402, "PLAN_LIMIT_REACHED");
|
|
46
|
+
this.name = "LumailPaymentRequiredError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ../../src/lib/lumail-sdk/client.ts
|
|
51
|
+
var DEFAULT_BASE_URL = "https://lumail.io/api";
|
|
52
|
+
var DEFAULT_TIMEOUT = 30000;
|
|
53
|
+
var RETRY_DELAYS = [1000, 2000, 4000];
|
|
54
|
+
var IDEMPOTENT_METHODS = new Set(["GET", "PUT", "DELETE"]);
|
|
55
|
+
|
|
56
|
+
class LumailClient {
|
|
57
|
+
apiKey;
|
|
58
|
+
baseUrl;
|
|
59
|
+
constructor(apiKey, baseUrl) {
|
|
60
|
+
if (!apiKey?.trim()) {
|
|
61
|
+
throw new Error("Lumail API key is required. Get yours at lumail.io/settings");
|
|
62
|
+
}
|
|
63
|
+
this.apiKey = apiKey;
|
|
64
|
+
this.baseUrl = (baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
65
|
+
}
|
|
66
|
+
async request(method, path, options) {
|
|
67
|
+
const url = this.buildUrl(path, options?.params);
|
|
68
|
+
const headers = {
|
|
69
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
70
|
+
"Content-Type": "application/json"
|
|
71
|
+
};
|
|
72
|
+
const isIdempotent = IDEMPOTENT_METHODS.has(method.toUpperCase());
|
|
73
|
+
let lastError = null;
|
|
74
|
+
const maxRetries = isIdempotent ? RETRY_DELAYS.length : 0;
|
|
75
|
+
for (let attempt = 0;attempt <= maxRetries; attempt++) {
|
|
76
|
+
try {
|
|
77
|
+
const signal = options?.signal ?? AbortSignal.timeout(DEFAULT_TIMEOUT);
|
|
78
|
+
const response = await fetch(url, {
|
|
79
|
+
method,
|
|
80
|
+
headers,
|
|
81
|
+
body: options?.body ? JSON.stringify(options.body) : undefined,
|
|
82
|
+
signal
|
|
83
|
+
});
|
|
84
|
+
if (response.ok) {
|
|
85
|
+
const data = await response.json();
|
|
86
|
+
if (data.success === false) {
|
|
87
|
+
throw new LumailError(data.message ?? "Request failed", response.status, data.code);
|
|
88
|
+
}
|
|
89
|
+
return data;
|
|
90
|
+
}
|
|
91
|
+
if (response.status === 429 && isIdempotent && attempt < maxRetries) {
|
|
92
|
+
await sleep(parseRetryAfter(response, RETRY_DELAYS[attempt]));
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
throw await this.handleErrorResponse(response);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (error instanceof LumailError) {
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
lastError = error;
|
|
101
|
+
const isNetworkError = error instanceof TypeError || error.name === "AbortError";
|
|
102
|
+
if (isNetworkError && isIdempotent && attempt < maxRetries) {
|
|
103
|
+
await sleep(RETRY_DELAYS[attempt]);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw lastError ?? new LumailError("Request failed after retries", 500);
|
|
110
|
+
}
|
|
111
|
+
buildUrl(path, params) {
|
|
112
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
113
|
+
if (params) {
|
|
114
|
+
for (const [key, value] of Object.entries(params)) {
|
|
115
|
+
if (value !== undefined) {
|
|
116
|
+
url.searchParams.set(key, String(value));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return url.toString();
|
|
121
|
+
}
|
|
122
|
+
async handleErrorResponse(response) {
|
|
123
|
+
let body = {};
|
|
124
|
+
try {
|
|
125
|
+
body = await response.json();
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
const message = body.message ?? body.error ?? response.statusText;
|
|
129
|
+
const code = body.code;
|
|
130
|
+
switch (response.status) {
|
|
131
|
+
case 401:
|
|
132
|
+
return new LumailAuthenticationError(message);
|
|
133
|
+
case 402:
|
|
134
|
+
return new LumailPaymentRequiredError(message);
|
|
135
|
+
case 404:
|
|
136
|
+
return new LumailNotFoundError(message);
|
|
137
|
+
case 429: {
|
|
138
|
+
const retryAfter = parseRetryAfter(response, null);
|
|
139
|
+
return new LumailRateLimitError(message, retryAfter);
|
|
140
|
+
}
|
|
141
|
+
default:
|
|
142
|
+
if (response.status >= 400 && response.status < 500) {
|
|
143
|
+
return new LumailValidationError(message);
|
|
144
|
+
}
|
|
145
|
+
return new LumailError(message, response.status, code);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function parseRetryAfter(response, fallback) {
|
|
150
|
+
const header = response.headers.get("Retry-After");
|
|
151
|
+
if (!header)
|
|
152
|
+
return fallback;
|
|
153
|
+
const seconds = Number(header);
|
|
154
|
+
if (!Number.isNaN(seconds))
|
|
155
|
+
return seconds * 1000;
|
|
156
|
+
const date = new Date(header).getTime();
|
|
157
|
+
if (!Number.isNaN(date))
|
|
158
|
+
return Math.max(0, date - Date.now());
|
|
159
|
+
return fallback;
|
|
160
|
+
}
|
|
161
|
+
async function sleep(ms) {
|
|
162
|
+
if (ms === null || ms <= 0)
|
|
163
|
+
return;
|
|
164
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ../../src/lib/lumail-sdk/resources/campaigns.ts
|
|
168
|
+
class Campaigns {
|
|
169
|
+
client;
|
|
170
|
+
constructor(client) {
|
|
171
|
+
this.client = client;
|
|
172
|
+
}
|
|
173
|
+
async list(params) {
|
|
174
|
+
return this.client.request("GET", "/v1/campaigns", {
|
|
175
|
+
params
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
async create(params) {
|
|
179
|
+
return this.client.request("POST", "/v1/campaigns", {
|
|
180
|
+
body: params
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async get(campaignId) {
|
|
184
|
+
return this.client.request("GET", `/v1/campaigns/${encodeURIComponent(campaignId)}`);
|
|
185
|
+
}
|
|
186
|
+
async update(campaignId, params) {
|
|
187
|
+
return this.client.request("PATCH", `/v1/campaigns/${encodeURIComponent(campaignId)}`, { body: params });
|
|
188
|
+
}
|
|
189
|
+
async delete(campaignId) {
|
|
190
|
+
return this.client.request("DELETE", `/v1/campaigns/${encodeURIComponent(campaignId)}`);
|
|
191
|
+
}
|
|
192
|
+
async send(campaignId, params) {
|
|
193
|
+
return this.client.request("POST", `/v1/campaigns/${encodeURIComponent(campaignId)}/send`, { body: params ?? {} });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ../../src/lib/lumail-sdk/resources/emails.ts
|
|
198
|
+
class Emails {
|
|
199
|
+
client;
|
|
200
|
+
constructor(client) {
|
|
201
|
+
this.client = client;
|
|
202
|
+
}
|
|
203
|
+
async send(params) {
|
|
204
|
+
return this.client.request("POST", "/v1/emails", {
|
|
205
|
+
body: params
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async verify(params) {
|
|
209
|
+
return this.client.request("POST", "/v1/emails/verify", {
|
|
210
|
+
body: params
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ../../src/lib/lumail-sdk/resources/events.ts
|
|
216
|
+
class Events {
|
|
217
|
+
client;
|
|
218
|
+
constructor(client) {
|
|
219
|
+
this.client = client;
|
|
220
|
+
}
|
|
221
|
+
async create(params) {
|
|
222
|
+
return this.client.request("POST", "/v1/events", {
|
|
223
|
+
body: params
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ../../src/lib/lumail-sdk/resources/subscribers.ts
|
|
229
|
+
class Subscribers {
|
|
230
|
+
client;
|
|
231
|
+
constructor(client) {
|
|
232
|
+
this.client = client;
|
|
233
|
+
}
|
|
234
|
+
async create(params) {
|
|
235
|
+
return this.client.request("POST", "/v1/subscribers", {
|
|
236
|
+
body: params
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
async get(idOrEmail) {
|
|
240
|
+
return this.client.request("GET", `/v1/subscribers/${encodeURIComponent(idOrEmail)}`);
|
|
241
|
+
}
|
|
242
|
+
async update(idOrEmail, params) {
|
|
243
|
+
return this.client.request("PATCH", `/v1/subscribers/${encodeURIComponent(idOrEmail)}`, { body: params });
|
|
244
|
+
}
|
|
245
|
+
async delete(idOrEmail) {
|
|
246
|
+
return this.client.request("DELETE", `/v1/subscribers/${encodeURIComponent(idOrEmail)}`);
|
|
247
|
+
}
|
|
248
|
+
async unsubscribe(idOrEmail) {
|
|
249
|
+
return this.client.request("POST", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/unsubscribe`);
|
|
250
|
+
}
|
|
251
|
+
async addTags(idOrEmail, tags) {
|
|
252
|
+
return this.client.request("POST", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/tags`, { body: { tags } });
|
|
253
|
+
}
|
|
254
|
+
async removeTags(idOrEmail, tags) {
|
|
255
|
+
return this.client.request("DELETE", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/tags`, { params: { tags: JSON.stringify(tags) } });
|
|
256
|
+
}
|
|
257
|
+
async listEvents(idOrEmail, params) {
|
|
258
|
+
return this.client.request("GET", `/v1/subscribers/${encodeURIComponent(idOrEmail)}/events`, {
|
|
259
|
+
params: {
|
|
260
|
+
...params,
|
|
261
|
+
eventTypes: params?.eventTypes ? JSON.stringify(params.eventTypes) : undefined
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ../../src/lib/lumail-sdk/resources/tags.ts
|
|
268
|
+
class Tags {
|
|
269
|
+
client;
|
|
270
|
+
constructor(client) {
|
|
271
|
+
this.client = client;
|
|
272
|
+
}
|
|
273
|
+
async list() {
|
|
274
|
+
return this.client.request("GET", "/v1/tags");
|
|
275
|
+
}
|
|
276
|
+
async create(params) {
|
|
277
|
+
return this.client.request("POST", "/v1/tags", {
|
|
278
|
+
body: params
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
async get(idOrName) {
|
|
282
|
+
return this.client.request("GET", `/v1/tags/${encodeURIComponent(idOrName)}`);
|
|
283
|
+
}
|
|
284
|
+
async update(idOrName, params) {
|
|
285
|
+
return this.client.request("PATCH", `/v1/tags/${encodeURIComponent(idOrName)}`, { body: params });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ../../src/lib/lumail-sdk/resources/tools.ts
|
|
290
|
+
class Tools {
|
|
291
|
+
client;
|
|
292
|
+
constructor(client) {
|
|
293
|
+
this.client = client;
|
|
294
|
+
}
|
|
295
|
+
async list() {
|
|
296
|
+
return this.client.request("GET", "/v2/tools");
|
|
297
|
+
}
|
|
298
|
+
async get(toolName) {
|
|
299
|
+
return this.client.request("GET", `/v2/tools/${encodeURIComponent(toolName)}`);
|
|
300
|
+
}
|
|
301
|
+
async run(toolName, params) {
|
|
302
|
+
return this.client.request("POST", `/v2/tools/${encodeURIComponent(toolName)}`, { body: params ?? {} });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ../../src/lib/lumail-sdk/index.ts
|
|
307
|
+
class Lumail {
|
|
308
|
+
subscribers;
|
|
309
|
+
campaigns;
|
|
310
|
+
emails;
|
|
311
|
+
tags;
|
|
312
|
+
events;
|
|
313
|
+
tools;
|
|
314
|
+
constructor(options) {
|
|
315
|
+
const client = new LumailClient(options.apiKey, options.baseUrl);
|
|
316
|
+
this.subscribers = new Subscribers(client);
|
|
317
|
+
this.campaigns = new Campaigns(client);
|
|
318
|
+
this.emails = new Emails(client);
|
|
319
|
+
this.tags = new Tags(client);
|
|
320
|
+
this.events = new Events(client);
|
|
321
|
+
this.tools = new Tools(client);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
export {
|
|
325
|
+
LumailValidationError,
|
|
326
|
+
LumailRateLimitError,
|
|
327
|
+
LumailPaymentRequiredError,
|
|
328
|
+
LumailNotFoundError,
|
|
329
|
+
LumailError,
|
|
330
|
+
LumailAuthenticationError,
|
|
331
|
+
Lumail
|
|
332
|
+
};
|