verifymailapi 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 +160 -0
- package/dist/index.cjs +402 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +327 -0
- package/dist/index.d.ts +327 -0
- package/dist/index.js +366 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var VerifyMailError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
status;
|
|
5
|
+
requestId;
|
|
6
|
+
docsUrl;
|
|
7
|
+
body;
|
|
8
|
+
constructor(message, opts = {}) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "VerifyMailError";
|
|
11
|
+
this.code = opts.code ?? "verifymail_error";
|
|
12
|
+
this.status = opts.status ?? 0;
|
|
13
|
+
this.requestId = opts.requestId;
|
|
14
|
+
this.docsUrl = opts.docsUrl;
|
|
15
|
+
this.body = opts.body;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var InvalidApiKeyError = class extends VerifyMailError {
|
|
19
|
+
constructor(opts) {
|
|
20
|
+
super("API key is missing or invalid.", opts);
|
|
21
|
+
this.name = "InvalidApiKeyError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var QuotaExceededError = class extends VerifyMailError {
|
|
25
|
+
upgradeUrl;
|
|
26
|
+
constructor(opts) {
|
|
27
|
+
super("Out of credits. Buy a bundle to keep going.", opts);
|
|
28
|
+
this.name = "QuotaExceededError";
|
|
29
|
+
this.upgradeUrl = opts.body?.upgrade_url;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var RateLimitError = class extends VerifyMailError {
|
|
33
|
+
retryAfter;
|
|
34
|
+
limit;
|
|
35
|
+
resetAt;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
super(`Rate limit hit; retry after ${opts.retryAfter}s.`, opts);
|
|
38
|
+
this.name = "RateLimitError";
|
|
39
|
+
this.retryAfter = opts.retryAfter;
|
|
40
|
+
this.limit = opts.body?.limit;
|
|
41
|
+
this.resetAt = opts.body?.reset_at;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var IdempotencyConflictError = class extends VerifyMailError {
|
|
45
|
+
constructor(opts) {
|
|
46
|
+
super(
|
|
47
|
+
"Idempotency-Key was reused with a different request body. Use a new key or resend the original payload.",
|
|
48
|
+
opts
|
|
49
|
+
);
|
|
50
|
+
this.name = "IdempotencyConflictError";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var ValidationError = class extends VerifyMailError {
|
|
54
|
+
constructor(message, opts) {
|
|
55
|
+
super(message, opts);
|
|
56
|
+
this.name = "ValidationError";
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var ServiceDegradedError = class extends VerifyMailError {
|
|
60
|
+
constructor(opts) {
|
|
61
|
+
super("A component is degraded; retry shortly.", opts);
|
|
62
|
+
this.name = "ServiceDegradedError";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function errorFromResponse(status, body, retryAfterHeader) {
|
|
66
|
+
const envelope = body && typeof body === "object" && "error" in body ? body.error : void 0;
|
|
67
|
+
const code = envelope?.code ?? "verifymail_error";
|
|
68
|
+
const opts = {
|
|
69
|
+
code,
|
|
70
|
+
status,
|
|
71
|
+
requestId: envelope?.request_id,
|
|
72
|
+
docsUrl: envelope?.docs_url,
|
|
73
|
+
body: envelope
|
|
74
|
+
};
|
|
75
|
+
if (status === 401) return new InvalidApiKeyError(opts);
|
|
76
|
+
if (status === 402) return new QuotaExceededError(opts);
|
|
77
|
+
if (status === 409 && code === "invalid_idempotency_key")
|
|
78
|
+
return new IdempotencyConflictError(opts);
|
|
79
|
+
if (status === 422) return new ValidationError(envelope?.message ?? "Validation error.", opts);
|
|
80
|
+
if (status === 429) {
|
|
81
|
+
const retryAfter = Number(retryAfterHeader ?? envelope?.limit ?? 1);
|
|
82
|
+
return new RateLimitError({ ...opts, retryAfter: Number.isFinite(retryAfter) ? retryAfter : 1 });
|
|
83
|
+
}
|
|
84
|
+
if (status === 503 || status === 504) return new ServiceDegradedError(opts);
|
|
85
|
+
return new VerifyMailError(envelope?.message ?? `HTTP ${status}`, opts);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/client.ts
|
|
89
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
90
|
+
function uuidv4() {
|
|
91
|
+
const c = globalThis.crypto;
|
|
92
|
+
if (c?.randomUUID) return c.randomUUID();
|
|
93
|
+
const buf = new Uint8Array(16);
|
|
94
|
+
for (let i = 0; i < 16; i++) buf[i] = Math.floor(Math.random() * 256);
|
|
95
|
+
buf[6] = buf[6] & 15 | 64;
|
|
96
|
+
buf[8] = buf[8] & 63 | 128;
|
|
97
|
+
const hex = Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
98
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
99
|
+
}
|
|
100
|
+
var HttpClient = class {
|
|
101
|
+
apiKey;
|
|
102
|
+
baseUrl;
|
|
103
|
+
retries;
|
|
104
|
+
timeoutMs;
|
|
105
|
+
fetchImpl;
|
|
106
|
+
defaultRiskProfile;
|
|
107
|
+
constructor(opts) {
|
|
108
|
+
if (!opts.apiKey) throw new VerifyMailError("apiKey is required.");
|
|
109
|
+
this.apiKey = opts.apiKey;
|
|
110
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.verifymailapi.com").replace(/\/+$/, "");
|
|
111
|
+
this.retries = opts.retries ?? 2;
|
|
112
|
+
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
113
|
+
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
114
|
+
this.defaultRiskProfile = opts.riskProfile;
|
|
115
|
+
if (!this.fetchImpl) {
|
|
116
|
+
throw new VerifyMailError(
|
|
117
|
+
"No fetch available. Pass `fetch` in the options, or use Node 18+."
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Build the headers shared by every request. */
|
|
122
|
+
buildHeaders(opts) {
|
|
123
|
+
const h = new Headers(opts.headers);
|
|
124
|
+
h.set("X-API-Key", this.apiKey);
|
|
125
|
+
h.set("Accept", "application/json");
|
|
126
|
+
h.set("User-Agent", "verifymailapi-js/0.1.0");
|
|
127
|
+
if (opts.body !== void 0) h.set("Content-Type", "application/json");
|
|
128
|
+
const profile = opts.riskProfile ?? this.defaultRiskProfile;
|
|
129
|
+
if (profile) h.set("X-Risk-Profile", profile);
|
|
130
|
+
if (opts.idempotencyKey) {
|
|
131
|
+
h.set(
|
|
132
|
+
"Idempotency-Key",
|
|
133
|
+
typeof opts.idempotencyKey === "string" ? opts.idempotencyKey : uuidv4()
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
return h;
|
|
137
|
+
}
|
|
138
|
+
buildUrl(path, query) {
|
|
139
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
140
|
+
if (query) {
|
|
141
|
+
for (const [k, v] of Object.entries(query)) {
|
|
142
|
+
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return url.toString();
|
|
146
|
+
}
|
|
147
|
+
/** Send and decode a JSON request. Retries on 429 / 5xx up to `retries` times. */
|
|
148
|
+
async json(opts) {
|
|
149
|
+
const raw = await this.raw(opts);
|
|
150
|
+
if (raw.status === 204) return void 0;
|
|
151
|
+
const text = await raw.text();
|
|
152
|
+
try {
|
|
153
|
+
return JSON.parse(text);
|
|
154
|
+
} catch {
|
|
155
|
+
throw new VerifyMailError(`Non-JSON response from ${opts.path}.`, {
|
|
156
|
+
status: raw.status
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Send a request and return the raw Response. Handles retries + error mapping.
|
|
162
|
+
* Used internally; exposed for the streaming bulk method to consume the body.
|
|
163
|
+
*/
|
|
164
|
+
async raw(opts) {
|
|
165
|
+
const url = this.buildUrl(opts.path, opts.query);
|
|
166
|
+
const headers = this.buildHeaders(opts);
|
|
167
|
+
const body = opts.body !== void 0 ? JSON.stringify(opts.body) : void 0;
|
|
168
|
+
const method = opts.method ?? (body ? "POST" : "GET");
|
|
169
|
+
const maxTries = opts.noRetry ? 1 : this.retries + 1;
|
|
170
|
+
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
171
|
+
let lastError;
|
|
172
|
+
for (let attempt = 0; attempt < maxTries; attempt++) {
|
|
173
|
+
const controller = new AbortController();
|
|
174
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
175
|
+
let res;
|
|
176
|
+
try {
|
|
177
|
+
res = await this.fetchImpl(url, {
|
|
178
|
+
method,
|
|
179
|
+
headers,
|
|
180
|
+
body,
|
|
181
|
+
signal: controller.signal
|
|
182
|
+
});
|
|
183
|
+
} catch (err2) {
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
lastError = new VerifyMailError(
|
|
186
|
+
err2 instanceof Error ? err2.message : "Network error",
|
|
187
|
+
{ code: "network_error" }
|
|
188
|
+
);
|
|
189
|
+
if (attempt < maxTries - 1) {
|
|
190
|
+
await sleep(backoffMs(attempt));
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
throw lastError;
|
|
194
|
+
}
|
|
195
|
+
clearTimeout(timer);
|
|
196
|
+
if (res.ok) return res;
|
|
197
|
+
let parsed = void 0;
|
|
198
|
+
try {
|
|
199
|
+
parsed = await res.clone().json();
|
|
200
|
+
} catch {
|
|
201
|
+
}
|
|
202
|
+
const err = errorFromResponse(res.status, parsed, res.headers.get("Retry-After"));
|
|
203
|
+
const isRetryable = !opts.noRetry && RETRYABLE_STATUS.has(res.status) && attempt < maxTries - 1;
|
|
204
|
+
if (isRetryable) {
|
|
205
|
+
const wait = err instanceof RateLimitError ? err.retryAfter * 1e3 : err instanceof ServiceDegradedError ? backoffMs(attempt) : backoffMs(attempt);
|
|
206
|
+
await sleep(wait);
|
|
207
|
+
lastError = err;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
throw err;
|
|
211
|
+
}
|
|
212
|
+
throw lastError ?? new VerifyMailError("Request failed after retries.");
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
function sleep(ms) {
|
|
216
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
217
|
+
}
|
|
218
|
+
function backoffMs(attempt) {
|
|
219
|
+
return Math.min(250 * Math.pow(3, attempt), 1e4);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/webhooks.ts
|
|
223
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
224
|
+
function verifyWebhook(rawBody, signatureHeader, secret) {
|
|
225
|
+
if (!signatureHeader) return false;
|
|
226
|
+
const body = typeof rawBody === "string" ? Buffer.from(rawBody, "utf8") : Buffer.from(rawBody);
|
|
227
|
+
const expected = "sha256=" + createHmac("sha256", secret).update(body).digest("hex");
|
|
228
|
+
const a = Buffer.from(signatureHeader);
|
|
229
|
+
const b = Buffer.from(expected);
|
|
230
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/index.ts
|
|
234
|
+
var VerifyMail = class {
|
|
235
|
+
http;
|
|
236
|
+
constructor(opts) {
|
|
237
|
+
this.http = new HttpClient(opts);
|
|
238
|
+
}
|
|
239
|
+
/** Check a single email. Charges 1 credit. */
|
|
240
|
+
check(email, opts = {}) {
|
|
241
|
+
return this.http.json({
|
|
242
|
+
path: "/v1/check",
|
|
243
|
+
body: { email },
|
|
244
|
+
idempotencyKey: opts.idempotencyKey,
|
|
245
|
+
riskProfile: opts.riskProfile
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/** Check a domain only (no local part). Charges 1 credit. */
|
|
249
|
+
checkDomain(domain, opts = {}) {
|
|
250
|
+
return this.http.json({
|
|
251
|
+
path: "/v1/check/domain",
|
|
252
|
+
body: { domain },
|
|
253
|
+
idempotencyKey: opts.idempotencyKey,
|
|
254
|
+
riskProfile: opts.riskProfile
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/** Bulk check 1–100 emails. Charges N credits up front (all-or-nothing). */
|
|
258
|
+
checkBulk(emails, opts = {}) {
|
|
259
|
+
if (emails.length === 0 || emails.length > 100) {
|
|
260
|
+
throw new RangeError("checkBulk requires 1\u2013100 emails.");
|
|
261
|
+
}
|
|
262
|
+
return this.http.json({
|
|
263
|
+
path: "/v1/check/bulk",
|
|
264
|
+
body: { emails },
|
|
265
|
+
idempotencyKey: opts.idempotencyKey,
|
|
266
|
+
riskProfile: opts.riskProfile
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Stream bulk-check results as each row completes. Calls `onEvent` once
|
|
271
|
+
* per result (in finish-order) plus once with a final `{event: "summary"}`.
|
|
272
|
+
*
|
|
273
|
+
* await vm.checkBulkStream(emails, (e) => {
|
|
274
|
+
* if ("event" in e) console.log("done", e);
|
|
275
|
+
* else processRow(e.index, e.result);
|
|
276
|
+
* });
|
|
277
|
+
*/
|
|
278
|
+
async checkBulkStream(emails, onEvent, opts = {}) {
|
|
279
|
+
if (emails.length === 0) throw new RangeError("checkBulkStream needs at least one email.");
|
|
280
|
+
const req = {
|
|
281
|
+
path: "/v1/check/bulk/stream",
|
|
282
|
+
body: { emails },
|
|
283
|
+
riskProfile: opts.riskProfile,
|
|
284
|
+
// Streaming requests aren't safe to auto-retry — would re-charge credits
|
|
285
|
+
// and re-stream rows. Customer must retry explicitly.
|
|
286
|
+
noRetry: true
|
|
287
|
+
};
|
|
288
|
+
const res = await this.http.raw(req);
|
|
289
|
+
if (!res.body) throw new Error("Streaming response had no body.");
|
|
290
|
+
const reader = res.body.getReader();
|
|
291
|
+
const decoder = new TextDecoder();
|
|
292
|
+
let buf = "";
|
|
293
|
+
while (true) {
|
|
294
|
+
const { value, done } = await reader.read();
|
|
295
|
+
if (done) break;
|
|
296
|
+
buf += decoder.decode(value, { stream: true });
|
|
297
|
+
let nl;
|
|
298
|
+
while ((nl = buf.indexOf("\n")) !== -1) {
|
|
299
|
+
const line = buf.slice(0, nl).trim();
|
|
300
|
+
buf = buf.slice(nl + 1);
|
|
301
|
+
if (!line) continue;
|
|
302
|
+
try {
|
|
303
|
+
await onEvent(JSON.parse(line));
|
|
304
|
+
} catch (err) {
|
|
305
|
+
throw new Error(`Failed to parse stream line: ${line}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const tail = buf.trim();
|
|
310
|
+
if (tail) await onEvent(JSON.parse(tail));
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Async deep check. Returns 202 immediately with a preliminary verdict;
|
|
314
|
+
* VerifyMail POSTs the final result to your webhook URL once the deep
|
|
315
|
+
* SMTP probe completes. Verify the signature with `verifyWebhook()` in
|
|
316
|
+
* your handler before trusting the payload.
|
|
317
|
+
*/
|
|
318
|
+
checkAsync(args, opts = {}) {
|
|
319
|
+
return this.http.json({
|
|
320
|
+
path: "/v1/check/async",
|
|
321
|
+
body: {
|
|
322
|
+
email: args.email,
|
|
323
|
+
webhook_url: args.webhookUrl,
|
|
324
|
+
webhook_secret: args.webhookSecret
|
|
325
|
+
},
|
|
326
|
+
idempotencyKey: opts.idempotencyKey,
|
|
327
|
+
riskProfile: opts.riskProfile
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
/** File a /v1/report for a domain outcome (feedback loop). */
|
|
331
|
+
report(req) {
|
|
332
|
+
return this.http.json({
|
|
333
|
+
path: "/v1/report",
|
|
334
|
+
body: req
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
/** Programmatic equivalent of the dashboard's Usage summary. */
|
|
338
|
+
usage() {
|
|
339
|
+
return this.http.json({
|
|
340
|
+
path: "/v1/usage/me",
|
|
341
|
+
method: "GET"
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/** Component health (Redis / Postgres / DNS). Always returns 200. */
|
|
345
|
+
status() {
|
|
346
|
+
return this.http.json({
|
|
347
|
+
path: "/v1/status",
|
|
348
|
+
method: "GET"
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
var index_default = VerifyMail;
|
|
353
|
+
export {
|
|
354
|
+
IdempotencyConflictError,
|
|
355
|
+
InvalidApiKeyError,
|
|
356
|
+
QuotaExceededError,
|
|
357
|
+
RateLimitError,
|
|
358
|
+
ServiceDegradedError,
|
|
359
|
+
ValidationError,
|
|
360
|
+
VerifyMail,
|
|
361
|
+
VerifyMailError,
|
|
362
|
+
index_default as default,
|
|
363
|
+
errorFromResponse,
|
|
364
|
+
verifyWebhook
|
|
365
|
+
};
|
|
366
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/webhooks.ts","../src/index.ts"],"sourcesContent":["/**\n * Error class hierarchy. All HTTP errors from the API are translated into one\n * of these — customers can `instanceof` them to branch cleanly:\n *\n * try { await vm.check(email) }\n * catch (e) {\n * if (e instanceof QuotaExceededError) return showBilling();\n * if (e instanceof RateLimitError) return retryLater(e.retryAfter);\n * if (e instanceof VerifyMailError) return logAndShowGeneric(e);\n * throw e;\n * }\n */\n\nexport interface ErrorBody {\n code: string;\n http_status: number;\n message: string;\n request_id?: string;\n docs_url?: string;\n // Rate-limit-specific\n limit?: number;\n reset_at?: string;\n // Quota-specific\n upgrade_url?: string;\n}\n\nexport class VerifyMailError extends Error {\n readonly code: string;\n readonly status: number;\n readonly requestId: string | undefined;\n readonly docsUrl: string | undefined;\n readonly body: ErrorBody | undefined;\n\n constructor(message: string, opts: {\n code?: string;\n status?: number;\n requestId?: string;\n docsUrl?: string;\n body?: ErrorBody;\n } = {}) {\n super(message);\n this.name = \"VerifyMailError\";\n this.code = opts.code ?? \"verifymail_error\";\n this.status = opts.status ?? 0;\n this.requestId = opts.requestId;\n this.docsUrl = opts.docsUrl;\n this.body = opts.body;\n }\n}\n\nexport class InvalidApiKeyError extends VerifyMailError {\n constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>) {\n super(\"API key is missing or invalid.\", opts);\n this.name = \"InvalidApiKeyError\";\n }\n}\n\nexport class QuotaExceededError extends VerifyMailError {\n readonly upgradeUrl: string | undefined;\n constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>) {\n super(\"Out of credits. Buy a bundle to keep going.\", opts);\n this.name = \"QuotaExceededError\";\n this.upgradeUrl = opts.body?.upgrade_url;\n }\n}\n\nexport class RateLimitError extends VerifyMailError {\n readonly retryAfter: number;\n readonly limit: number | undefined;\n readonly resetAt: string | undefined;\n\n constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]> & {\n retryAfter: number;\n }) {\n super(`Rate limit hit; retry after ${opts.retryAfter}s.`, opts);\n this.name = \"RateLimitError\";\n this.retryAfter = opts.retryAfter;\n this.limit = opts.body?.limit;\n this.resetAt = opts.body?.reset_at;\n }\n}\n\nexport class IdempotencyConflictError extends VerifyMailError {\n constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>) {\n super(\n \"Idempotency-Key was reused with a different request body. Use a new key or resend the original payload.\",\n opts,\n );\n this.name = \"IdempotencyConflictError\";\n }\n}\n\nexport class ValidationError extends VerifyMailError {\n constructor(message: string, opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>) {\n super(message, opts);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ServiceDegradedError extends VerifyMailError {\n constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>) {\n super(\"A component is degraded; retry shortly.\", opts);\n this.name = \"ServiceDegradedError\";\n }\n}\n\n/**\n * Map an HTTP response to the right error class. The backend's error envelope\n * is `{ error: { code, http_status, message, ... } }`.\n */\nexport function errorFromResponse(\n status: number,\n body: { error?: ErrorBody } | unknown,\n retryAfterHeader?: string | null,\n): VerifyMailError {\n const envelope =\n body && typeof body === \"object\" && \"error\" in body\n ? (body as { error?: ErrorBody }).error\n : undefined;\n const code = envelope?.code ?? \"verifymail_error\";\n const opts = {\n code,\n status,\n requestId: envelope?.request_id,\n docsUrl: envelope?.docs_url,\n body: envelope,\n };\n\n if (status === 401) return new InvalidApiKeyError(opts);\n if (status === 402) return new QuotaExceededError(opts);\n if (status === 409 && code === \"invalid_idempotency_key\")\n return new IdempotencyConflictError(opts);\n if (status === 422) return new ValidationError(envelope?.message ?? \"Validation error.\", opts);\n if (status === 429) {\n const retryAfter = Number(retryAfterHeader ?? envelope?.limit ?? 1);\n return new RateLimitError({ ...opts, retryAfter: Number.isFinite(retryAfter) ? retryAfter : 1 });\n }\n if (status === 503 || status === 504) return new ServiceDegradedError(opts);\n return new VerifyMailError(envelope?.message ?? `HTTP ${status}`, opts);\n}\n","import { errorFromResponse, RateLimitError, ServiceDegradedError, VerifyMailError } from \"./errors.js\";\n\nexport interface ClientOptions {\n apiKey: string;\n /** Defaults to https://api.verifymailapi.com */\n baseUrl?: string;\n /** Max retry attempts on retryable failures (429, 5xx). Default 2 (so up to 3 total tries). */\n retries?: number;\n /** Per-request timeout in ms. Default 30000. */\n timeoutMs?: number;\n /** Override fetch — useful for tests or non-Node runtimes. */\n fetch?: typeof fetch;\n /** Default risk profile sent as X-Risk-Profile on every call (overridable per request). */\n riskProfile?: \"strict\" | \"balanced\" | \"permissive\";\n}\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\";\n path: string;\n query?: Record<string, string | number | undefined>;\n body?: unknown;\n headers?: Record<string, string>;\n /** Provide an Idempotency-Key for POSTs. Auto-generated UUID if `true`. */\n idempotencyKey?: string | boolean;\n /** Override the default risk profile for this call. */\n riskProfile?: \"strict\" | \"balanced\" | \"permissive\";\n /** Skip retry on transient errors for this call. */\n noRetry?: boolean;\n /** Override timeout for this call. */\n timeoutMs?: number;\n}\n\nconst RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);\n\nfunction uuidv4(): string {\n // Node 19+ has globalThis.crypto.randomUUID. Polyfill for older Node.\n const c = globalThis.crypto;\n if (c?.randomUUID) return c.randomUUID();\n const buf = new Uint8Array(16);\n for (let i = 0; i < 16; i++) buf[i] = Math.floor(Math.random() * 256);\n buf[6] = (buf[6]! & 0x0f) | 0x40;\n buf[8] = (buf[8]! & 0x3f) | 0x80;\n const hex = Array.from(buf, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly retries: number;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n private readonly defaultRiskProfile: string | undefined;\n\n constructor(opts: ClientOptions) {\n if (!opts.apiKey) throw new VerifyMailError(\"apiKey is required.\");\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? \"https://api.verifymailapi.com\").replace(/\\/+$/, \"\");\n this.retries = opts.retries ?? 2;\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.fetchImpl = opts.fetch ?? globalThis.fetch;\n this.defaultRiskProfile = opts.riskProfile;\n if (!this.fetchImpl) {\n throw new VerifyMailError(\n \"No fetch available. Pass `fetch` in the options, or use Node 18+.\",\n );\n }\n }\n\n /** Build the headers shared by every request. */\n private buildHeaders(opts: RequestOptions): Headers {\n const h = new Headers(opts.headers);\n h.set(\"X-API-Key\", this.apiKey);\n h.set(\"Accept\", \"application/json\");\n h.set(\"User-Agent\", \"verifymailapi-js/0.1.0\");\n if (opts.body !== undefined) h.set(\"Content-Type\", \"application/json\");\n\n const profile = opts.riskProfile ?? this.defaultRiskProfile;\n if (profile) h.set(\"X-Risk-Profile\", profile);\n\n if (opts.idempotencyKey) {\n h.set(\n \"Idempotency-Key\",\n typeof opts.idempotencyKey === \"string\" ? opts.idempotencyKey : uuidv4(),\n );\n }\n return h;\n }\n\n private buildUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(`${this.baseUrl}${path}`);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n }\n\n /** Send and decode a JSON request. Retries on 429 / 5xx up to `retries` times. */\n async json<T>(opts: RequestOptions): Promise<T> {\n const raw = await this.raw(opts);\n if (raw.status === 204) return undefined as T;\n const text = await raw.text();\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new VerifyMailError(`Non-JSON response from ${opts.path}.`, {\n status: raw.status,\n });\n }\n }\n\n /**\n * Send a request and return the raw Response. Handles retries + error mapping.\n * Used internally; exposed for the streaming bulk method to consume the body.\n */\n async raw(opts: RequestOptions): Promise<Response> {\n const url = this.buildUrl(opts.path, opts.query);\n const headers = this.buildHeaders(opts);\n const body = opts.body !== undefined ? JSON.stringify(opts.body) : undefined;\n const method = opts.method ?? (body ? \"POST\" : \"GET\");\n const maxTries = opts.noRetry ? 1 : this.retries + 1;\n const timeoutMs = opts.timeoutMs ?? this.timeoutMs;\n\n let lastError: VerifyMailError | undefined;\n for (let attempt = 0; attempt < maxTries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n let res: Response;\n try {\n res = await this.fetchImpl(url, {\n method,\n headers,\n body,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n // Network-level failure — retry if attempts remain.\n lastError = new VerifyMailError(\n err instanceof Error ? err.message : \"Network error\",\n { code: \"network_error\" },\n );\n if (attempt < maxTries - 1) {\n await sleep(backoffMs(attempt));\n continue;\n }\n throw lastError;\n }\n clearTimeout(timer);\n\n if (res.ok) return res;\n\n // Parse error body (best-effort) so we can build a typed error.\n let parsed: unknown = undefined;\n try {\n parsed = await res.clone().json();\n } catch {\n /* ignore non-JSON error bodies */\n }\n const err = errorFromResponse(res.status, parsed, res.headers.get(\"Retry-After\"));\n\n const isRetryable =\n !opts.noRetry &&\n RETRYABLE_STATUS.has(res.status) &&\n attempt < maxTries - 1;\n\n if (isRetryable) {\n const wait =\n err instanceof RateLimitError\n ? err.retryAfter * 1000\n : err instanceof ServiceDegradedError\n ? backoffMs(attempt)\n : backoffMs(attempt);\n await sleep(wait);\n lastError = err;\n continue;\n }\n\n throw err;\n }\n\n throw lastError ?? new VerifyMailError(\"Request failed after retries.\");\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction backoffMs(attempt: number): number {\n // 250ms, 750ms, 2.25s — typical exponential with a small jitter floor.\n return Math.min(250 * Math.pow(3, attempt), 10_000);\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\n/**\n * Verify an incoming webhook signature from a `/v1/check/async` completion.\n *\n * const ok = verifyWebhook(rawBody, req.header(\"X-VerifyMail-Signature\"), secret);\n * if (!ok) return res.status(401).end();\n *\n * Pass the *raw* request body bytes — not the parsed JSON. In Express:\n * app.post(\"/webhook\", express.raw({ type: \"application/json\" }), handler)\n */\nexport function verifyWebhook(\n rawBody: Buffer | Uint8Array | string,\n signatureHeader: string | null | undefined,\n secret: string,\n): boolean {\n if (!signatureHeader) return false;\n const body =\n typeof rawBody === \"string\" ? Buffer.from(rawBody, \"utf8\") : Buffer.from(rawBody);\n const expected =\n \"sha256=\" + createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n const a = Buffer.from(signatureHeader);\n const b = Buffer.from(expected);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n","/**\n * Official SDK for the VerifyMail API.\n *\n * import { VerifyMail } from \"verifymailapi\";\n * const vm = new VerifyMail({ apiKey: process.env.VERIFYMAIL_KEY! });\n * const r = await vm.check(\"user@example.com\");\n * if (r.verdict.recommendation === \"block\") { ... }\n *\n * Docs: https://verifymailapi.com/docs\n */\n\nimport { HttpClient, type ClientOptions, type RequestOptions } from \"./client.js\";\nimport type {\n AsyncCheckResponse,\n BulkCheckResponse,\n BulkStreamEvent,\n CheckResponse,\n ReportRequest,\n ReportResponse,\n StatusResponse,\n UsageMeResponse,\n} from \"./types.js\";\n\nexport * from \"./types.js\";\nexport * from \"./errors.js\";\nexport { verifyWebhook } from \"./webhooks.js\";\n\nexport interface CheckOptions {\n /** Override the SDK-wide risk profile for this call. */\n riskProfile?: \"strict\" | \"balanced\" | \"permissive\";\n /** Make the call idempotent. Pass `true` to auto-generate a UUID, or a fixed string. */\n idempotencyKey?: string | boolean;\n}\n\nexport interface AsyncCheckArgs {\n email: string;\n webhookUrl: string;\n /** Optional HMAC-SHA256 key used to sign the final webhook payload. */\n webhookSecret?: string;\n}\n\nexport class VerifyMail {\n private readonly http: HttpClient;\n\n constructor(opts: ClientOptions) {\n this.http = new HttpClient(opts);\n }\n\n /** Check a single email. Charges 1 credit. */\n check(email: string, opts: CheckOptions = {}): Promise<CheckResponse> {\n return this.http.json<CheckResponse>({\n path: \"/v1/check\",\n body: { email },\n idempotencyKey: opts.idempotencyKey,\n riskProfile: opts.riskProfile,\n });\n }\n\n /** Check a domain only (no local part). Charges 1 credit. */\n checkDomain(domain: string, opts: CheckOptions = {}): Promise<CheckResponse> {\n return this.http.json<CheckResponse>({\n path: \"/v1/check/domain\",\n body: { domain },\n idempotencyKey: opts.idempotencyKey,\n riskProfile: opts.riskProfile,\n });\n }\n\n /** Bulk check 1–100 emails. Charges N credits up front (all-or-nothing). */\n checkBulk(emails: string[], opts: CheckOptions = {}): Promise<BulkCheckResponse> {\n if (emails.length === 0 || emails.length > 100) {\n throw new RangeError(\"checkBulk requires 1–100 emails.\");\n }\n return this.http.json<BulkCheckResponse>({\n path: \"/v1/check/bulk\",\n body: { emails },\n idempotencyKey: opts.idempotencyKey,\n riskProfile: opts.riskProfile,\n });\n }\n\n /**\n * Stream bulk-check results as each row completes. Calls `onEvent` once\n * per result (in finish-order) plus once with a final `{event: \"summary\"}`.\n *\n * await vm.checkBulkStream(emails, (e) => {\n * if (\"event\" in e) console.log(\"done\", e);\n * else processRow(e.index, e.result);\n * });\n */\n async checkBulkStream(\n emails: string[],\n onEvent: (e: BulkStreamEvent) => void | Promise<void>,\n opts: Omit<CheckOptions, \"idempotencyKey\"> = {},\n ): Promise<void> {\n if (emails.length === 0) throw new RangeError(\"checkBulkStream needs at least one email.\");\n\n const req: RequestOptions = {\n path: \"/v1/check/bulk/stream\",\n body: { emails },\n riskProfile: opts.riskProfile,\n // Streaming requests aren't safe to auto-retry — would re-charge credits\n // and re-stream rows. Customer must retry explicitly.\n noRetry: true,\n };\n const res = await this.http.raw(req);\n if (!res.body) throw new Error(\"Streaming response had no body.\");\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buf = \"\";\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n let nl: number;\n // Drain complete lines; keep the partial tail in buf for the next chunk.\n while ((nl = buf.indexOf(\"\\n\")) !== -1) {\n const line = buf.slice(0, nl).trim();\n buf = buf.slice(nl + 1);\n if (!line) continue;\n try {\n await onEvent(JSON.parse(line) as BulkStreamEvent);\n } catch (err) {\n throw new Error(`Failed to parse stream line: ${line}`);\n }\n }\n }\n // Final flush in case the server didn't terminate with newline.\n const tail = buf.trim();\n if (tail) await onEvent(JSON.parse(tail) as BulkStreamEvent);\n }\n\n /**\n * Async deep check. Returns 202 immediately with a preliminary verdict;\n * VerifyMail POSTs the final result to your webhook URL once the deep\n * SMTP probe completes. Verify the signature with `verifyWebhook()` in\n * your handler before trusting the payload.\n */\n checkAsync(args: AsyncCheckArgs, opts: CheckOptions = {}): Promise<AsyncCheckResponse> {\n return this.http.json<AsyncCheckResponse>({\n path: \"/v1/check/async\",\n body: {\n email: args.email,\n webhook_url: args.webhookUrl,\n webhook_secret: args.webhookSecret,\n },\n idempotencyKey: opts.idempotencyKey,\n riskProfile: opts.riskProfile,\n });\n }\n\n /** File a /v1/report for a domain outcome (feedback loop). */\n report(req: ReportRequest): Promise<ReportResponse> {\n return this.http.json<ReportResponse>({\n path: \"/v1/report\",\n body: req,\n });\n }\n\n /** Programmatic equivalent of the dashboard's Usage summary. */\n usage(): Promise<UsageMeResponse> {\n return this.http.json<UsageMeResponse>({\n path: \"/v1/usage/me\",\n method: \"GET\",\n });\n }\n\n /** Component health (Redis / Postgres / DNS). Always returns 200. */\n status(): Promise<StatusResponse> {\n return this.http.json<StatusResponse>({\n path: \"/v1/status\",\n method: \"GET\",\n });\n }\n}\n\nexport default VerifyMail;\n"],"mappings":"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","names":["err"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "verifymailapi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official SDK for the VerifyMail API — disposable, throwaway, and abusive email detection.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://verifymailapi.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/jt1402/verifymail-js.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/jt1402/verifymail-js/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"email",
|
|
16
|
+
"verification",
|
|
17
|
+
"validation",
|
|
18
|
+
"disposable",
|
|
19
|
+
"throwaway",
|
|
20
|
+
"signup",
|
|
21
|
+
"fraud",
|
|
22
|
+
"verifymail"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.cjs",
|
|
26
|
+
"module": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.cjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"dev": "tsup --watch",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"test": "node --test --import=tsx test/**/*.test.ts",
|
|
45
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^20.11.0",
|
|
52
|
+
"tsup": "^8.0.0",
|
|
53
|
+
"tsx": "^4.7.0",
|
|
54
|
+
"typescript": "^5.4.0"
|
|
55
|
+
}
|
|
56
|
+
}
|