sadasend 0.0.0-stage → 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 +527 -2
- package/dist/client.d.ts +452 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +266 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +123 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +176 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/retry.d.ts +42 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +30 -0
- package/dist/retry.js.map +1 -0
- package/dist/webhooks.d.ts +71 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +96 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +73 -4
package/dist/client.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { ConnectionError, SadaSendError, isRetryable, toError, } from './errors.js';
|
|
2
|
+
import { DEFAULT_RETRY, delayFor, sleep } from './retry.js';
|
|
3
|
+
const VERSION = '0.1.0';
|
|
4
|
+
/**
|
|
5
|
+
* `process.env`, read without assuming it exists.
|
|
6
|
+
*
|
|
7
|
+
* This package runs in Cloudflare Workers, Vercel Edge and the browser, where
|
|
8
|
+
* there is no `process` at all — and it is compiled without Node or Bun's
|
|
9
|
+
* ambient types on purpose, so nothing here can quietly depend on a global the
|
|
10
|
+
* customer's runtime does not have.
|
|
11
|
+
*/
|
|
12
|
+
const env = (name) => globalThis
|
|
13
|
+
.process?.env?.[name];
|
|
14
|
+
export class SadaSend {
|
|
15
|
+
#apiKey;
|
|
16
|
+
#baseUrl;
|
|
17
|
+
#timeoutMs;
|
|
18
|
+
#retry;
|
|
19
|
+
#fetch;
|
|
20
|
+
#channel;
|
|
21
|
+
#source;
|
|
22
|
+
#agentName;
|
|
23
|
+
constructor(apiKeyOrOptions, options = {}) {
|
|
24
|
+
const opts = typeof apiKeyOrOptions === 'object' && apiKeyOrOptions !== null
|
|
25
|
+
? apiKeyOrOptions
|
|
26
|
+
: options;
|
|
27
|
+
const key = (typeof apiKeyOrOptions === 'string' ? apiKeyOrOptions : undefined)
|
|
28
|
+
?? opts.apiKey
|
|
29
|
+
?? env('SADASEND_API_KEY');
|
|
30
|
+
if (!key) {
|
|
31
|
+
throw new Error('No API key. Pass one to `new SadaSend(key)` or set SADASEND_API_KEY. '
|
|
32
|
+
+ 'Keys are created in the dashboard under Keys and shown once.');
|
|
33
|
+
}
|
|
34
|
+
this.#apiKey = key;
|
|
35
|
+
this.#baseUrl = (opts.baseUrl ?? env('SADASEND_BASE_URL') ?? 'https://api.sadasend.com')
|
|
36
|
+
.replace(/\/+$/, '');
|
|
37
|
+
this.#timeoutMs = opts.timeoutMs ?? 30_000;
|
|
38
|
+
this.#retry = { ...DEFAULT_RETRY, ...opts.retry };
|
|
39
|
+
this.#fetch = opts.fetch ?? globalThis.fetch;
|
|
40
|
+
this.#channel = opts.channel ?? env('SADASEND_CHANNEL');
|
|
41
|
+
this.#source = opts.source ?? env('SADASEND_SOURCE');
|
|
42
|
+
this.#agentName = opts.agentName ?? env('SADASEND_AGENT_NAME');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Send an email.
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* const r = await sadasend.emails.send({ from, to, subject, html });
|
|
49
|
+
* if (!r.ok) return console.error(r.error.message);
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* `r.status` is `'pending_approval'` when the key is in approval mode — the
|
|
53
|
+
* message is real and waiting for a person, not lost. Treating that as a
|
|
54
|
+
* success is correct: the send was accepted.
|
|
55
|
+
*/
|
|
56
|
+
emails = {
|
|
57
|
+
send: async (input) => {
|
|
58
|
+
const { idempotencyKey, channel, source, agentName, agent_name, headers, ...rest } = input;
|
|
59
|
+
const resolvedChannel = channel ?? this.#channel;
|
|
60
|
+
const resolvedSource = source ?? this.#source;
|
|
61
|
+
const resolvedAgent = agentName ?? agent_name ?? this.#agentName;
|
|
62
|
+
const outgoingHeaders = { ...(headers ?? {}) };
|
|
63
|
+
if (resolvedAgent)
|
|
64
|
+
outgoingHeaders['x-sadasend-agent'] = resolvedAgent;
|
|
65
|
+
if (resolvedSource)
|
|
66
|
+
outgoingHeaders['x-sadasend-source'] = resolvedSource;
|
|
67
|
+
const r = await this.#request('POST', '/emails', {
|
|
68
|
+
headers: outgoingHeaders,
|
|
69
|
+
body: {
|
|
70
|
+
...rest,
|
|
71
|
+
...(resolvedChannel ? { channel: resolvedChannel } : {}),
|
|
72
|
+
...(resolvedSource ? { source: resolvedSource } : {}),
|
|
73
|
+
...(resolvedAgent ? { agent_name: resolvedAgent } : {}),
|
|
74
|
+
to: Array.isArray(rest.to) ? rest.to : [rest.to],
|
|
75
|
+
scheduledAt: rest.scheduledAt instanceof Date ? rest.scheduledAt.toISOString() : rest.scheduledAt,
|
|
76
|
+
},
|
|
77
|
+
// Generated when absent, which is the point: without one, a retry
|
|
78
|
+
// after a timeout is a second email to a real person.
|
|
79
|
+
idempotencyKey: idempotencyKey ?? crypto.randomUUID(),
|
|
80
|
+
});
|
|
81
|
+
return r.ok ? { ok: true, ...r.data } : r;
|
|
82
|
+
},
|
|
83
|
+
batch: async (items, options = {}) => {
|
|
84
|
+
const body = {
|
|
85
|
+
emails: items.map((item) => {
|
|
86
|
+
const { idempotencyKey, channel, source, agentName, agent_name, ...rest } = item;
|
|
87
|
+
const resolvedChannel = channel ?? this.#channel;
|
|
88
|
+
const resolvedSource = source ?? this.#source;
|
|
89
|
+
const resolvedAgent = agentName ?? agent_name ?? this.#agentName;
|
|
90
|
+
return {
|
|
91
|
+
...rest,
|
|
92
|
+
...(resolvedChannel ? { channel: resolvedChannel } : {}),
|
|
93
|
+
...(resolvedSource ? { source: resolvedSource } : {}),
|
|
94
|
+
...(resolvedAgent ? { agent_name: resolvedAgent } : {}),
|
|
95
|
+
to: Array.isArray(rest.to) ? rest.to : [rest.to],
|
|
96
|
+
scheduledAt: rest.scheduledAt instanceof Date ? rest.scheduledAt.toISOString() : rest.scheduledAt,
|
|
97
|
+
};
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
return this.#request('POST', '/emails/batch', {
|
|
101
|
+
body,
|
|
102
|
+
idempotencyKey: options.idempotencyKey ?? crypto.randomUUID(),
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
get: async (id) => {
|
|
106
|
+
const r = await this.#request('GET', `/emails/${encodeURIComponent(id)}`);
|
|
107
|
+
return r.ok ? { ok: true, data: normalise(r.data) } : r;
|
|
108
|
+
},
|
|
109
|
+
resend: (id, options = {}) => this.#request('POST', `/emails/${encodeURIComponent(id)}/resend`, {
|
|
110
|
+
idempotencyKey: options.idempotencyKey ?? crypto.randomUUID(),
|
|
111
|
+
}),
|
|
112
|
+
list: async (params = {}) => {
|
|
113
|
+
const { agentName, agent_name, ...rest } = params;
|
|
114
|
+
const r = await this.#request('GET', `/emails${query({ ...rest, ...(agentName || agent_name ? { agent_name: agentName ?? agent_name } : {}) })}`);
|
|
115
|
+
return r.ok
|
|
116
|
+
? { ok: true, data: { ...r.data, messages: r.data.messages.map(normalise) } }
|
|
117
|
+
: r;
|
|
118
|
+
},
|
|
119
|
+
cancel: (id) => this.#request('DELETE', `/emails/${encodeURIComponent(id)}`),
|
|
120
|
+
};
|
|
121
|
+
account = {
|
|
122
|
+
get: () => this.#request('GET', '/account'),
|
|
123
|
+
stats: (params = {}) => this.#request('GET', `/account/stats${query(params)}`),
|
|
124
|
+
volume: (params = {}) => this.#request('GET', `/account/volume${query(params)}`),
|
|
125
|
+
checklist: () => this.#request('GET', '/account/checklist'),
|
|
126
|
+
circuitBreakers: () => this.#request('GET', '/account/circuit-breakers'),
|
|
127
|
+
staffAccess: (params = {}) => this.#request('GET', `/account/staff-access${query(params)}`),
|
|
128
|
+
};
|
|
129
|
+
domains = {
|
|
130
|
+
list: () => this.#request('GET', '/domains'),
|
|
131
|
+
records: (id) => this.#request('GET', `/domains/${encodeURIComponent(id)}/records`),
|
|
132
|
+
verify: (id) => this.#request('POST', `/domains/${encodeURIComponent(id)}/verify`),
|
|
133
|
+
};
|
|
134
|
+
suppressions = {
|
|
135
|
+
list: (params = {}) => this.#request('GET', `/suppressions${query(params)}`),
|
|
136
|
+
add: (address, reason = 'manual') => this.#request('POST', '/suppressions', { body: { address, reason } }),
|
|
137
|
+
};
|
|
138
|
+
templates = {
|
|
139
|
+
list: () => this.#request('GET', '/templates'),
|
|
140
|
+
get: (id) => this.#request('GET', `/templates/${encodeURIComponent(id)}`),
|
|
141
|
+
render: (id, variables = {}) => this.#request('POST', `/templates/${encodeURIComponent(id)}/render`, { body: { variables } }),
|
|
142
|
+
test: (id, options) => this.#request('POST', `/templates/${encodeURIComponent(id)}/test`, { body: options }),
|
|
143
|
+
};
|
|
144
|
+
keys = {
|
|
145
|
+
list: () => this.#request('GET', '/keys'),
|
|
146
|
+
approvals: () => this.#request('GET', '/keys/approvals'),
|
|
147
|
+
};
|
|
148
|
+
support = {
|
|
149
|
+
tickets: (params = {}) => this.#request('GET', `/support/tickets${query(params)}`),
|
|
150
|
+
ticket: (id) => this.#request('GET', `/support/tickets/${encodeURIComponent(id)}`),
|
|
151
|
+
};
|
|
152
|
+
team = {
|
|
153
|
+
get: () => this.#request('GET', '/team'),
|
|
154
|
+
};
|
|
155
|
+
tools = {
|
|
156
|
+
list: () => this.#request('GET', '/tools'),
|
|
157
|
+
check: (check, subject, selector) => this.#request('POST', `/tools/${encodeURIComponent(check)}`, { body: { subject, selector } }),
|
|
158
|
+
};
|
|
159
|
+
webhooks = {
|
|
160
|
+
list: () => this.#request('GET', '/webhooks'),
|
|
161
|
+
deliveries: (id, params = {}) => this.#request('GET', `/webhooks/${encodeURIComponent(id)}/deliveries${query(params)}`),
|
|
162
|
+
};
|
|
163
|
+
/* ------------------------------------------------------------ transport */
|
|
164
|
+
async #request(method, path, opts = {}) {
|
|
165
|
+
const url = `${this.#baseUrl}${path}`;
|
|
166
|
+
const headers = {
|
|
167
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
168
|
+
'user-agent': `sadasend-js/${VERSION}`,
|
|
169
|
+
...(this.#agentName ? { 'x-sadasend-agent': this.#agentName } : {}),
|
|
170
|
+
...(this.#source ? { 'x-sadasend-source': this.#source } : {}),
|
|
171
|
+
...(opts.headers ?? {}),
|
|
172
|
+
};
|
|
173
|
+
if (opts.body !== undefined)
|
|
174
|
+
headers['content-type'] = 'application/json';
|
|
175
|
+
// The same key on every attempt, which is what makes retrying safe. A key
|
|
176
|
+
// regenerated per attempt is no key at all.
|
|
177
|
+
if (opts.idempotencyKey)
|
|
178
|
+
headers['idempotency-key'] = opts.idempotencyKey;
|
|
179
|
+
const payload = opts.body === undefined ? undefined : JSON.stringify(opts.body);
|
|
180
|
+
let lastConnectionFault;
|
|
181
|
+
for (let attempt = 1;; attempt++) {
|
|
182
|
+
let response;
|
|
183
|
+
try {
|
|
184
|
+
response = await this.#fetch(url, {
|
|
185
|
+
method,
|
|
186
|
+
headers,
|
|
187
|
+
body: payload,
|
|
188
|
+
signal: AbortSignal.timeout(this.#timeoutMs),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (cause) {
|
|
192
|
+
/**
|
|
193
|
+
* No answer. Retried like a 5xx — with the idempotency key intact, so
|
|
194
|
+
* an attempt that did reach the server returns its original result
|
|
195
|
+
* instead of sending twice.
|
|
196
|
+
*/
|
|
197
|
+
lastConnectionFault = cause;
|
|
198
|
+
if (attempt > this.#retry.maxRetries) {
|
|
199
|
+
throw new ConnectionError(`Could not reach ${this.#baseUrl} after ${attempt} attempt${attempt === 1 ? '' : 's'}.`, cause, attempt);
|
|
200
|
+
}
|
|
201
|
+
await sleep(delayFor(attempt, new SadaSendError('connection', 0, ''), this.#retry) ?? 0);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const text = await response.text();
|
|
205
|
+
const body = parseJson(text);
|
|
206
|
+
if (response.ok)
|
|
207
|
+
return { ok: true, data: body };
|
|
208
|
+
const error = toError(response.status, body, retryAfterSeconds(response));
|
|
209
|
+
if (!isRetryable(error) || attempt > this.#retry.maxRetries)
|
|
210
|
+
return { ok: false, error };
|
|
211
|
+
const wait = delayFor(attempt, error, this.#retry);
|
|
212
|
+
// `null` means the policy declined — a `Retry-After` longer than we will
|
|
213
|
+
// block for. The error carries the header, so the caller can schedule it.
|
|
214
|
+
if (wait === null)
|
|
215
|
+
return { ok: false, error };
|
|
216
|
+
await sleep(wait);
|
|
217
|
+
}
|
|
218
|
+
// Unreachable; the loop returns or throws. Referenced so a future edit that
|
|
219
|
+
// breaks out of the loop fails to compile rather than returning undefined.
|
|
220
|
+
void lastConnectionFault;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* `to` is a union on the wire: the API returns a bare string for one recipient
|
|
225
|
+
* and an array for several (`m.to.length === 1 ? m.to[0] : m.to`). The contract
|
|
226
|
+
* fixed that shape from a UI that only ever renders one, and the dashboard
|
|
227
|
+
* consumes it as it is — so it is not the SDK's place to change the wire.
|
|
228
|
+
*
|
|
229
|
+
* It *is* the SDK's place not to pass the wart on. A union-typed field is a
|
|
230
|
+
* paper cut at every call site, and the bug it causes is silent: `to[0]` on a
|
|
231
|
+
* single-recipient message returns `"d"`. Always an array here.
|
|
232
|
+
*/
|
|
233
|
+
function normalise(m) {
|
|
234
|
+
return { ...m, to: Array.isArray(m.to) ? m.to : [m.to] };
|
|
235
|
+
}
|
|
236
|
+
function parseJson(text) {
|
|
237
|
+
try {
|
|
238
|
+
const v = JSON.parse(text);
|
|
239
|
+
return v !== null && typeof v === 'object' ? v : { value: v };
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// A proxy's HTML error page, or an empty 502. Kept so the error message can
|
|
243
|
+
// show what actually arrived rather than "unexpected token < in JSON".
|
|
244
|
+
return { error: 'invalid_response', message: text.slice(0, 200) || 'The API returned an empty body.' };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function retryAfterSeconds(r) {
|
|
248
|
+
const raw = r.headers.get('retry-after');
|
|
249
|
+
if (!raw)
|
|
250
|
+
return undefined;
|
|
251
|
+
const n = Number(raw);
|
|
252
|
+
if (Number.isFinite(n))
|
|
253
|
+
return n;
|
|
254
|
+
// The header may also be an HTTP-date. Rare from our API, valid per RFC 9110.
|
|
255
|
+
const at = Date.parse(raw);
|
|
256
|
+
return Number.isNaN(at) ? undefined : Math.max(0, Math.ceil((at - Date.now()) / 1000));
|
|
257
|
+
}
|
|
258
|
+
function query(params) {
|
|
259
|
+
const q = new URLSearchParams();
|
|
260
|
+
for (const [k, v] of Object.entries(params))
|
|
261
|
+
if (v !== undefined)
|
|
262
|
+
q.set(k, String(v));
|
|
263
|
+
const s = q.toString();
|
|
264
|
+
return s ? `?${s}` : '';
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An error class per failure mode, and every one of them carries the fix.
|
|
3
|
+
*
|
|
4
|
+
* The standard is the one the free tools hold themselves to: a message that
|
|
5
|
+
* says what is wrong and nothing about what to do is a message that generates a
|
|
6
|
+
* support ticket. `DomainNotVerifiedError` carries the DNS records that are
|
|
7
|
+
* missing, because the person reading it is about to go and look them up.
|
|
8
|
+
*
|
|
9
|
+
* These are **not thrown** for guardrail refusals. A refusal is the product
|
|
10
|
+
* working — an agent stopped from mailing someone it should not — and throwing
|
|
11
|
+
* turns the normal case into an exception. They arrive inside the result union,
|
|
12
|
+
* where `instanceof` narrows them and the compiler makes you handle them.
|
|
13
|
+
*/
|
|
14
|
+
/** The DNS record shape `GET /domains/:id/records` and this error both use. */
|
|
15
|
+
export type DnsRecord = {
|
|
16
|
+
type: string;
|
|
17
|
+
host: string;
|
|
18
|
+
value: string;
|
|
19
|
+
verdict?: 'pass' | 'fail' | 'pending' | 'inconclusive';
|
|
20
|
+
note?: string;
|
|
21
|
+
};
|
|
22
|
+
export declare class SadaSendError extends Error {
|
|
23
|
+
/** The machine-readable code. Stable; the message is not. */
|
|
24
|
+
readonly code: string;
|
|
25
|
+
readonly status: number;
|
|
26
|
+
/** `https://sadasend.com/docs/errors#<code>`, sent by the API. */
|
|
27
|
+
readonly docs?: string;
|
|
28
|
+
/** The whole body, for codes newer than this SDK. */
|
|
29
|
+
readonly body: Record<string, unknown>;
|
|
30
|
+
constructor(code: string, status: number, message: string, body?: Record<string, unknown>);
|
|
31
|
+
}
|
|
32
|
+
/** The key is not valid, or was revoked. Nothing to retry. */
|
|
33
|
+
export declare class AuthenticationError extends SadaSendError {
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The key has scopes, and `send` is not among them.
|
|
37
|
+
*
|
|
38
|
+
* Deliberately not retryable and deliberately not fixable in code: widening a
|
|
39
|
+
* key is a decision someone makes in the dashboard, on purpose.
|
|
40
|
+
*/
|
|
41
|
+
export declare class InsufficientScopeError extends SadaSendError {
|
|
42
|
+
}
|
|
43
|
+
/** The `from` address did not parse as an email address. */
|
|
44
|
+
export declare class InvalidFromError extends SadaSendError {
|
|
45
|
+
}
|
|
46
|
+
export declare class DomainNotFoundError extends SadaSendError {
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The domain exists but has not passed DNS verification — and the records are
|
|
50
|
+
* attached, so the fix is in the error rather than a page away.
|
|
51
|
+
*/
|
|
52
|
+
export declare class DomainNotVerifiedError extends SadaSendError {
|
|
53
|
+
get records(): DnsRecord[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The guardrail that makes an agent safe to hand a key to. The allowlist is on
|
|
57
|
+
* the error because the interesting question is always "what *is* it allowed to
|
|
58
|
+
* mail, then".
|
|
59
|
+
*/
|
|
60
|
+
export declare class RecipientNotAllowlistedError extends SadaSendError {
|
|
61
|
+
get recipient(): string | undefined;
|
|
62
|
+
get allowlist(): string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The address is on the suppression list. The reason carries a judgement the
|
|
66
|
+
* caller should not make on its own: `unsubscribe` is a person's decision, and
|
|
67
|
+
* `hard_bounce` is an address that does not exist. Neither is "retry later",
|
|
68
|
+
* which is why this is not retryable.
|
|
69
|
+
*/
|
|
70
|
+
export declare class RecipientSuppressedError extends SadaSendError {
|
|
71
|
+
get recipient(): string | undefined;
|
|
72
|
+
get reason(): 'hard_bounce' | 'complaint' | 'unsubscribe' | 'manual' | undefined;
|
|
73
|
+
}
|
|
74
|
+
/** The same key with a different body. The first request stands. */
|
|
75
|
+
export declare class IdempotencyKeyReusedError extends SadaSendError {
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The first request with this key has not finished. Retrying returns *its*
|
|
79
|
+
* result rather than sending twice, so this one **is** retryable — and the
|
|
80
|
+
* client does retry it, which is the whole point of sending the key.
|
|
81
|
+
*/
|
|
82
|
+
export declare class IdempotencyInProgressError extends SadaSendError {
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Rate limited — by this key's own limit, or by the account-wide throttle that
|
|
86
|
+
* a bounce or complaint rate above the published threshold applies.
|
|
87
|
+
*
|
|
88
|
+
* `retryAfterSeconds` comes from the `Retry-After` header the API already
|
|
89
|
+
* sends. The client waits exactly that long rather than guessing, because a
|
|
90
|
+
* guess that is too short is what turns a limit into an outage.
|
|
91
|
+
*/
|
|
92
|
+
export declare class RateLimitError extends SadaSendError {
|
|
93
|
+
readonly retryAfterSeconds?: number;
|
|
94
|
+
constructor(code: string, status: number, message: string, body: Record<string, unknown>, retryAfterSeconds?: number);
|
|
95
|
+
/** True when the account is throttled for reputation, not merely over a key limit. */
|
|
96
|
+
get isAccountThrottle(): boolean;
|
|
97
|
+
}
|
|
98
|
+
/** 5xx, or a body that was not the error envelope. Retryable. */
|
|
99
|
+
export declare class ServerError extends SadaSendError {
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The request never got an answer — DNS, TLS, a dropped socket, a timeout.
|
|
103
|
+
*
|
|
104
|
+
* This one **is thrown** rather than returned. It is not the API refusing
|
|
105
|
+
* anything; it is not knowing whether the API saw the request at all, and that
|
|
106
|
+
* is a genuinely different situation from a refusal with a reason.
|
|
107
|
+
*/
|
|
108
|
+
export declare class ConnectionError extends Error {
|
|
109
|
+
readonly cause: unknown;
|
|
110
|
+
readonly attempts: number;
|
|
111
|
+
constructor(message: string, cause: unknown, attempts: number);
|
|
112
|
+
}
|
|
113
|
+
export declare function toError(status: number, body: Record<string, unknown>, retryAfterSeconds?: number): SadaSendError;
|
|
114
|
+
/**
|
|
115
|
+
* What is worth trying again.
|
|
116
|
+
*
|
|
117
|
+
* Every guardrail refusal is absent by design: an agent that retries past an
|
|
118
|
+
* allowlist is an agent that eventually gets through, and a client that retried
|
|
119
|
+
* `recipient_suppressed` would be automating the one thing the suppression list
|
|
120
|
+
* exists to stop.
|
|
121
|
+
*/
|
|
122
|
+
export declare function isRetryable(e: SadaSendError): boolean;
|
|
123
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,cAAc,CAAC;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,aAAc,SAAQ,KAAK;IACtC,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAE3B,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;CAQ9F;AAED,8DAA8D;AAC9D,qBAAa,mBAAoB,SAAQ,aAAa;CAAI;AAE1D;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;CAAI;AAE7D,4DAA4D;AAC5D,qBAAa,gBAAiB,SAAQ,aAAa;CAAI;AAEvD,qBAAa,mBAAoB,SAAQ,aAAa;CAAI;AAE1D;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;IACvD,IAAI,OAAO,IAAI,SAAS,EAAE,CAEzB;CACF;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,aAAa;IAC7D,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,IAAI,SAAS,IAAI,MAAM,EAAE,CAExB;CACF;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;IACzD,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,IAAI,MAAM,IAAI,aAAa,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAE/E;CACF;AAED,oEAAoE;AACpE,qBAAa,yBAA0B,SAAQ,aAAa;CAAI;AAEhE;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,aAAa;CAAI;AAEjE;;;;;;;GAOG;AACH,qBAAa,cAAe,SAAQ,aAAa;IAC/C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;gBAExB,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,EAAE,MAAM;IAMpH,sFAAsF;IACtF,IAAI,iBAAiB,IAAI,OAAO,CAE/B;CACF;AAED,iEAAiE;AACjE,qBAAa,WAAY,SAAQ,aAAa;CAAI;AAElD;;;;;;GAMG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM;CAM9D;AAqBD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,iBAAiB,CAAC,EAAE,MAAM,GACzB,aAAa,CAWf;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAIrD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An error class per failure mode, and every one of them carries the fix.
|
|
3
|
+
*
|
|
4
|
+
* The standard is the one the free tools hold themselves to: a message that
|
|
5
|
+
* says what is wrong and nothing about what to do is a message that generates a
|
|
6
|
+
* support ticket. `DomainNotVerifiedError` carries the DNS records that are
|
|
7
|
+
* missing, because the person reading it is about to go and look them up.
|
|
8
|
+
*
|
|
9
|
+
* These are **not thrown** for guardrail refusals. A refusal is the product
|
|
10
|
+
* working — an agent stopped from mailing someone it should not — and throwing
|
|
11
|
+
* turns the normal case into an exception. They arrive inside the result union,
|
|
12
|
+
* where `instanceof` narrows them and the compiler makes you handle them.
|
|
13
|
+
*/
|
|
14
|
+
export class SadaSendError extends Error {
|
|
15
|
+
/** The machine-readable code. Stable; the message is not. */
|
|
16
|
+
code;
|
|
17
|
+
status;
|
|
18
|
+
/** `https://sadasend.com/docs/errors#<code>`, sent by the API. */
|
|
19
|
+
docs;
|
|
20
|
+
/** The whole body, for codes newer than this SDK. */
|
|
21
|
+
body;
|
|
22
|
+
constructor(code, status, message, body = {}) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = new.target.name;
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.status = status;
|
|
27
|
+
this.docs = typeof body.docs === 'string' ? body.docs : undefined;
|
|
28
|
+
this.body = body;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** The key is not valid, or was revoked. Nothing to retry. */
|
|
32
|
+
export class AuthenticationError extends SadaSendError {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The key has scopes, and `send` is not among them.
|
|
36
|
+
*
|
|
37
|
+
* Deliberately not retryable and deliberately not fixable in code: widening a
|
|
38
|
+
* key is a decision someone makes in the dashboard, on purpose.
|
|
39
|
+
*/
|
|
40
|
+
export class InsufficientScopeError extends SadaSendError {
|
|
41
|
+
}
|
|
42
|
+
/** The `from` address did not parse as an email address. */
|
|
43
|
+
export class InvalidFromError extends SadaSendError {
|
|
44
|
+
}
|
|
45
|
+
export class DomainNotFoundError extends SadaSendError {
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The domain exists but has not passed DNS verification — and the records are
|
|
49
|
+
* attached, so the fix is in the error rather than a page away.
|
|
50
|
+
*/
|
|
51
|
+
export class DomainNotVerifiedError extends SadaSendError {
|
|
52
|
+
get records() {
|
|
53
|
+
return Array.isArray(this.body.records) ? this.body.records : [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The guardrail that makes an agent safe to hand a key to. The allowlist is on
|
|
58
|
+
* the error because the interesting question is always "what *is* it allowed to
|
|
59
|
+
* mail, then".
|
|
60
|
+
*/
|
|
61
|
+
export class RecipientNotAllowlistedError extends SadaSendError {
|
|
62
|
+
get recipient() {
|
|
63
|
+
return typeof this.body.recipient === 'string' ? this.body.recipient : undefined;
|
|
64
|
+
}
|
|
65
|
+
get allowlist() {
|
|
66
|
+
return Array.isArray(this.body.allowlist) ? this.body.allowlist : [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The address is on the suppression list. The reason carries a judgement the
|
|
71
|
+
* caller should not make on its own: `unsubscribe` is a person's decision, and
|
|
72
|
+
* `hard_bounce` is an address that does not exist. Neither is "retry later",
|
|
73
|
+
* which is why this is not retryable.
|
|
74
|
+
*/
|
|
75
|
+
export class RecipientSuppressedError extends SadaSendError {
|
|
76
|
+
get recipient() {
|
|
77
|
+
return typeof this.body.recipient === 'string' ? this.body.recipient : undefined;
|
|
78
|
+
}
|
|
79
|
+
get reason() {
|
|
80
|
+
return this.body.reason;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** The same key with a different body. The first request stands. */
|
|
84
|
+
export class IdempotencyKeyReusedError extends SadaSendError {
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The first request with this key has not finished. Retrying returns *its*
|
|
88
|
+
* result rather than sending twice, so this one **is** retryable — and the
|
|
89
|
+
* client does retry it, which is the whole point of sending the key.
|
|
90
|
+
*/
|
|
91
|
+
export class IdempotencyInProgressError extends SadaSendError {
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Rate limited — by this key's own limit, or by the account-wide throttle that
|
|
95
|
+
* a bounce or complaint rate above the published threshold applies.
|
|
96
|
+
*
|
|
97
|
+
* `retryAfterSeconds` comes from the `Retry-After` header the API already
|
|
98
|
+
* sends. The client waits exactly that long rather than guessing, because a
|
|
99
|
+
* guess that is too short is what turns a limit into an outage.
|
|
100
|
+
*/
|
|
101
|
+
export class RateLimitError extends SadaSendError {
|
|
102
|
+
retryAfterSeconds;
|
|
103
|
+
constructor(code, status, message, body, retryAfterSeconds) {
|
|
104
|
+
super(code, status, message, body);
|
|
105
|
+
this.retryAfterSeconds = retryAfterSeconds
|
|
106
|
+
?? (typeof body.retryAfterSeconds === 'number' ? body.retryAfterSeconds : undefined);
|
|
107
|
+
}
|
|
108
|
+
/** True when the account is throttled for reputation, not merely over a key limit. */
|
|
109
|
+
get isAccountThrottle() {
|
|
110
|
+
return this.code === 'account_throttled';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** 5xx, or a body that was not the error envelope. Retryable. */
|
|
114
|
+
export class ServerError extends SadaSendError {
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The request never got an answer — DNS, TLS, a dropped socket, a timeout.
|
|
118
|
+
*
|
|
119
|
+
* This one **is thrown** rather than returned. It is not the API refusing
|
|
120
|
+
* anything; it is not knowing whether the API saw the request at all, and that
|
|
121
|
+
* is a genuinely different situation from a refusal with a reason.
|
|
122
|
+
*/
|
|
123
|
+
export class ConnectionError extends Error {
|
|
124
|
+
cause;
|
|
125
|
+
attempts;
|
|
126
|
+
constructor(message, cause, attempts) {
|
|
127
|
+
super(message);
|
|
128
|
+
this.name = 'ConnectionError';
|
|
129
|
+
this.cause = cause;
|
|
130
|
+
this.attempts = attempts;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Codes to classes. A code this SDK has not heard of becomes a plain
|
|
135
|
+
* `SadaSendError` with the body intact — an SDK a version behind should degrade
|
|
136
|
+
* to "less specific", never to "throws on parse".
|
|
137
|
+
*/
|
|
138
|
+
const BY_CODE = {
|
|
139
|
+
missing_api_key: AuthenticationError,
|
|
140
|
+
invalid_api_key: AuthenticationError,
|
|
141
|
+
unauthenticated: AuthenticationError,
|
|
142
|
+
insufficient_scope: InsufficientScopeError,
|
|
143
|
+
invalid_from: InvalidFromError,
|
|
144
|
+
domain_not_found: DomainNotFoundError,
|
|
145
|
+
domain_not_verified: DomainNotVerifiedError,
|
|
146
|
+
recipient_not_allowlisted: RecipientNotAllowlistedError,
|
|
147
|
+
recipient_suppressed: RecipientSuppressedError,
|
|
148
|
+
idempotency_key_reused: IdempotencyKeyReusedError,
|
|
149
|
+
idempotency_key_in_progress: IdempotencyInProgressError,
|
|
150
|
+
};
|
|
151
|
+
export function toError(status, body, retryAfterSeconds) {
|
|
152
|
+
const code = typeof body.error === 'string' ? body.error : `http_${status}`;
|
|
153
|
+
const message = typeof body.message === 'string'
|
|
154
|
+
? body.message
|
|
155
|
+
: `The API returned ${status} with no error message.`;
|
|
156
|
+
if (status === 429)
|
|
157
|
+
return new RateLimitError(code, status, message, body, retryAfterSeconds);
|
|
158
|
+
if (status >= 500)
|
|
159
|
+
return new ServerError(code, status, message, body);
|
|
160
|
+
const Cls = BY_CODE[code];
|
|
161
|
+
return Cls ? new Cls(code, status, message, body) : new SadaSendError(code, status, message, body);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* What is worth trying again.
|
|
165
|
+
*
|
|
166
|
+
* Every guardrail refusal is absent by design: an agent that retries past an
|
|
167
|
+
* allowlist is an agent that eventually gets through, and a client that retried
|
|
168
|
+
* `recipient_suppressed` would be automating the one thing the suppression list
|
|
169
|
+
* exists to stop.
|
|
170
|
+
*/
|
|
171
|
+
export function isRetryable(e) {
|
|
172
|
+
return e instanceof ServerError
|
|
173
|
+
|| e instanceof RateLimitError
|
|
174
|
+
|| e instanceof IdempotencyInProgressError;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sadasend` — the SadaSend client.
|
|
3
|
+
*
|
|
4
|
+
* Zero dependencies, and deliberately so: this is the one package a customer
|
|
5
|
+
* installs, and every dependency it carries is one they audit, resolve and
|
|
6
|
+
* eventually get a CVE notice about. Everything here is `fetch` and WebCrypto,
|
|
7
|
+
* both of which are in Node 18+, Bun, Deno, Cloudflare Workers and the browser.
|
|
8
|
+
*/
|
|
9
|
+
export { SadaSend } from './client.js';
|
|
10
|
+
export type { AccountChecklist, AccountInfo, AccountStats, AccountVolume, AccountVolumeDay, ApiKeySummary, Attachment, BatchItemResult, BatchResult, ChecklistItem, CircuitBreaker, ClientOptions, DeliverabilityTool, HeldApproval, Message, MessageStatus, Result, SendInput, SendResult, StaffAccess, SupportTicketSummary, TeamMember, TemplateDetail, TemplateSummary, WebhookDelivery, WebhookEndpoint, } from './client.js';
|
|
11
|
+
export { AuthenticationError, ConnectionError, DomainNotFoundError, DomainNotVerifiedError, IdempotencyInProgressError, IdempotencyKeyReusedError, InsufficientScopeError, InvalidFromError, RateLimitError, RecipientNotAllowlistedError, RecipientSuppressedError, SadaSendError, ServerError, isRetryable, } from './errors.js';
|
|
12
|
+
export type { DnsRecord } from './errors.js';
|
|
13
|
+
export { DEFAULT_RETRY } from './retry.js';
|
|
14
|
+
export type { RetryPolicy } from './retry.js';
|
|
15
|
+
export { DEFAULT_TOLERANCE_MS, SIGNATURE_HEADER, parseWebhook, verifyWebhook, } from './webhooks.js';
|
|
16
|
+
export type { VerifyOptions, WebhookEvent, WebhookEventType } from './webhooks.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EACV,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAC5E,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EACtE,cAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,YAAY,EAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAClE,oBAAoB,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EACjE,eAAe,EAAE,eAAe,GACjC,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,sBAAsB,EACjF,0BAA0B,EAAE,yBAAyB,EAAE,sBAAsB,EAC7E,gBAAgB,EAAE,cAAc,EAAE,4BAA4B,EAAE,wBAAwB,EACxF,aAAa,EAAE,WAAW,EAAE,WAAW,GACxC,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EACL,oBAAoB,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,GACpE,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sadasend` — the SadaSend client.
|
|
3
|
+
*
|
|
4
|
+
* Zero dependencies, and deliberately so: this is the one package a customer
|
|
5
|
+
* installs, and every dependency it carries is one they audit, resolve and
|
|
6
|
+
* eventually get a CVE notice about. Everything here is `fetch` and WebCrypto,
|
|
7
|
+
* both of which are in Node 18+, Bun, Deno, Cloudflare Workers and the browser.
|
|
8
|
+
*/
|
|
9
|
+
export { SadaSend } from './client.js';
|
|
10
|
+
export { AuthenticationError, ConnectionError, DomainNotFoundError, DomainNotVerifiedError, IdempotencyInProgressError, IdempotencyKeyReusedError, InsufficientScopeError, InvalidFromError, RateLimitError, RecipientNotAllowlistedError, RecipientSuppressedError, SadaSendError, ServerError, isRetryable, } from './errors.js';
|
|
11
|
+
export { DEFAULT_RETRY } from './retry.js';
|
|
12
|
+
export { DEFAULT_TOLERANCE_MS, SIGNATURE_HEADER, parseWebhook, verifyWebhook, } from './webhooks.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAUvC,OAAO,EACL,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,sBAAsB,EACjF,0BAA0B,EAAE,yBAAyB,EAAE,sBAAsB,EAC7E,gBAAgB,EAAE,cAAc,EAAE,4BAA4B,EAAE,wBAAwB,EACxF,aAAa,EAAE,WAAW,EAAE,WAAW,GACxC,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,OAAO,EACL,oBAAoB,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,GACpE,MAAM,eAAe,CAAC"}
|