@sendora/sdk 1.1.0 → 2.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/README.md +152 -70
- package/dist/account.d.ts +30 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +25 -0
- package/dist/account.js.map +1 -0
- package/dist/client.d.ts +13 -16
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -30
- package/dist/client.js.map +1 -1
- package/dist/domains.d.ts +1 -1
- package/dist/domains.d.ts.map +1 -1
- package/dist/domains.js +1 -1
- package/dist/domains.js.map +1 -1
- package/dist/error.d.ts +6 -3
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +22 -2
- package/dist/error.js.map +1 -1
- package/dist/inbound-domains.d.ts +36 -0
- package/dist/inbound-domains.d.ts.map +1 -0
- package/dist/inbound-domains.js +72 -0
- package/dist/inbound-domains.js.map +1 -0
- package/dist/inbound.d.ts +61 -0
- package/dist/inbound.d.ts.map +1 -0
- package/dist/inbound.js +106 -0
- package/dist/inbound.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +20 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +34 -0
- package/dist/options.js.map +1 -0
- package/dist/servers.d.ts +64 -0
- package/dist/servers.d.ts.map +1 -0
- package/dist/servers.js +133 -0
- package/dist/servers.js.map +1 -0
- package/dist/transport.d.ts +2 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +15 -5
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +182 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhook-verify.d.ts +7 -5
- package/dist/webhook-verify.d.ts.map +1 -1
- package/dist/webhook-verify.js +38 -17
- package/dist/webhook-verify.js.map +1 -1
- package/dist/webhooks.d.ts +13 -1
- package/dist/webhooks.d.ts.map +1 -1
- package/dist/webhooks.js +26 -0
- package/dist/webhooks.js.map +1 -1
- package/package.json +4 -9
- package/skills/sendora/SKILL.md +19 -9
- package/src/account.ts +40 -0
- package/src/client.ts +20 -43
- package/src/domains.ts +1 -1
- package/src/error.ts +36 -3
- package/src/inbound-domains.ts +89 -0
- package/src/inbound.ts +135 -0
- package/src/index.ts +8 -1
- package/src/options.ts +51 -0
- package/src/servers.ts +166 -0
- package/src/transport.ts +26 -5
- package/src/types.ts +194 -5
- package/src/version.ts +1 -1
- package/src/webhook-verify.ts +39 -18
- package/src/webhooks.ts +29 -0
package/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# @sendora/sdk
|
|
2
2
|
|
|
3
3
|
The official TypeScript SDK for [Sendora](https://sendora.se), transactional
|
|
4
|
-
email delivery
|
|
5
|
-
newer and on any runtime with `fetch` and WebCrypto: Bun, Deno, Cloudflare
|
|
4
|
+
email delivery. Zero dependencies. Runs on Node 20.19 or newer and on any runtime with `fetch` and WebCrypto: Bun, Deno, Cloudflare
|
|
6
5
|
Workers. ESM only; CommonJS projects on Node 20.19 or 22.12 and newer load it
|
|
7
6
|
with `require`.
|
|
8
7
|
|
|
@@ -10,9 +9,13 @@ with `require`.
|
|
|
10
9
|
npm install @sendora/sdk
|
|
11
10
|
```
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
Two clients, two kinds of key. `Sendora` takes a server key (`sk_…`) and
|
|
13
|
+
does everything inside one server: sending, the log, streams,
|
|
14
|
+
suppressions, tokens and webhooks. `SendoraAccount` takes an account key
|
|
15
|
+
(`ak_…`) and manages the account: its servers, their keys and its sending
|
|
16
|
+
domains. Both keys are secrets: keep them on the server and never ship
|
|
17
|
+
them to a browser. Either client throws at construction when its key is
|
|
18
|
+
missing, so build it at startup.
|
|
16
19
|
|
|
17
20
|
```ts
|
|
18
21
|
import { Sendora } from '@sendora/sdk';
|
|
@@ -69,11 +72,31 @@ for (const result of results) {
|
|
|
69
72
|
|
|
70
73
|
## Messages
|
|
71
74
|
|
|
72
|
-
| Call
|
|
73
|
-
|
|
|
74
|
-
| `sendora.messages.get(messageId)`
|
|
75
|
-
| `sendora.messages.search(filters?)`
|
|
76
|
-
| `sendora.messages.searchAll(filters?)`
|
|
75
|
+
| Call | Answers |
|
|
76
|
+
| ------------------------------------------------------------ | --------------------------------------------------------------------------------- |
|
|
77
|
+
| `sendora.messages.get(messageId)` | The message with its recipients, its attachments described and its timeline |
|
|
78
|
+
| `sendora.messages.search(filters?)` | `{ messages, next }`, one page newest first |
|
|
79
|
+
| `sendora.messages.searchAll(filters?)` | Every match, page by page, for `for await` |
|
|
80
|
+
| `sendora.inbound.get(inboundMessageId)` | A received message: envelope, parties, headers, text, HTML, attachments described |
|
|
81
|
+
| `sendora.inbound.search(filters?)` | `{ messages, next }` of received mail, newest first |
|
|
82
|
+
| `sendora.inbound.searchAll(filters?)` | Every received match, page by page, for `for await` |
|
|
83
|
+
| `sendora.inbound.raw(inboundMessageId)` | The raw message as bytes, `message/rfc822` |
|
|
84
|
+
| `sendora.inbound.attachment(inboundMessageId, attachmentId)` | An attachment's bytes |
|
|
85
|
+
|
|
86
|
+
A stream can also receive on a domain of yours: every address on it,
|
|
87
|
+
whatever the local part, lands on the stream. Claim it with the stream
|
|
88
|
+
id, add the two records the answer gives, an MX that names Sendora and a
|
|
89
|
+
TXT record that proves the claim, and mail is accepted once both are
|
|
90
|
+
seen. A stream holds one domain, and the first account to verify a name
|
|
91
|
+
holds it.
|
|
92
|
+
|
|
93
|
+
| Call | Answers |
|
|
94
|
+
| ----------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
95
|
+
| `sendora.inboundDomains.create({ streamId, domain })` | The domain with `mx` and `txt` to add |
|
|
96
|
+
| `sendora.inboundDomains.list()` | `{ domains }` of the server |
|
|
97
|
+
| `sendora.inboundDomains.get(inboundDomainId)` | One domain with the state of its records |
|
|
98
|
+
| `sendora.inboundDomains.verify(inboundDomainId)` | The domain plus `check` per record: `ok`, `missing`, `mismatch`, `dns_error` |
|
|
99
|
+
| `sendora.inboundDomains.delete(inboundDomainId)` | Nothing; mail to it is refused from then on |
|
|
77
100
|
|
|
78
101
|
Filters: `recipient`, `streamId`, `tag`, `status` (`queued`, `delivered`,
|
|
79
102
|
`deferred`, `bounced`, `expired`), `from` and `to` as `Date` or ISO 8601,
|
|
@@ -169,20 +192,25 @@ await sendora.suppressions.delete({ address: 'anna@example.com' });
|
|
|
169
192
|
|
|
170
193
|
## Tokens
|
|
171
194
|
|
|
172
|
-
|
|
173
|
-
it is created
|
|
195
|
+
The server's own keys, from its own key. Every key of a server has the
|
|
196
|
+
same rights; the value is shown once, when it is created; a server holds
|
|
197
|
+
up to two live keys, and a third is `token_limit`. The account key
|
|
198
|
+
manages the same keys under `account.servers.tokens`.
|
|
174
199
|
|
|
175
|
-
| Call | Answers
|
|
176
|
-
| --------------------------------- |
|
|
177
|
-
| `sendora.tokens.create({ name })` | The token with its `token` value, once
|
|
178
|
-
| `sendora.tokens.list()` | `{ tokens }`, revoked ones included
|
|
179
|
-
| `sendora.tokens.get(tokenId)` | One token, without its value
|
|
180
|
-
| `sendora.tokens.revoke(tokenId)` | Nothing; the last live
|
|
200
|
+
| Call | Answers |
|
|
201
|
+
| --------------------------------- | ---------------------------------------------------- |
|
|
202
|
+
| `sendora.tokens.create({ name })` | The token with its `token` value, once |
|
|
203
|
+
| `sendora.tokens.list()` | `{ tokens }`, revoked ones included |
|
|
204
|
+
| `sendora.tokens.get(tokenId)` | One token, without its value |
|
|
205
|
+
| `sendora.tokens.revoke(tokenId)` | Nothing; the last live key is refused (`last_token`) |
|
|
181
206
|
|
|
182
207
|
## Webhooks
|
|
183
208
|
|
|
184
209
|
An https URL of yours that Sendora posts events to as they happen, signed
|
|
185
|
-
with a secret shown once at creation.
|
|
210
|
+
with a secret shown once at creation. A webhook holds up to two live
|
|
211
|
+
secrets, so a new one can be rolled in beside the old one: every delivery
|
|
212
|
+
is then signed with each, the newest first, and the old secret is deleted
|
|
213
|
+
once your receiver has switched.
|
|
186
214
|
|
|
187
215
|
| Call | Answers |
|
|
188
216
|
| -------------------------------------------------------- | ------------------------------------------------ |
|
|
@@ -193,6 +221,8 @@ with a secret shown once at creation.
|
|
|
193
221
|
| `sendora.webhooks.deliveries(webhookId, { status? })` | `{ deliveries, next }`, newest first |
|
|
194
222
|
| `sendora.webhooks.deliveriesAll(webhookId, { status? })` | Every delivery, for `for await` |
|
|
195
223
|
| `sendora.webhooks.replay(webhookId, deliveryId)` | The delivery, queued again |
|
|
224
|
+
| `sendora.webhooks.createSecret(webhookId)` | A second secret with its `secret` value, once |
|
|
225
|
+
| `sendora.webhooks.deleteSecret(webhookId, secretId)` | Nothing; the last live secret is refused |
|
|
196
226
|
| `sendora.webhooks.receive(request, secret)` | The verified, typed event from a Fetch `Request` |
|
|
197
227
|
|
|
198
228
|
Events: `delivered`, `bounced`, `deferred`, `spam_complaint` and
|
|
@@ -246,31 +276,72 @@ const event = await verifyWebhook({
|
|
|
246
276
|
});
|
|
247
277
|
```
|
|
248
278
|
|
|
249
|
-
The signature is `Sendora-Signature: t=<unix seconds>,v1=<hex
|
|
250
|
-
|
|
251
|
-
|
|
279
|
+
The signature is `Sendora-Signature: t=<unix seconds>,v1=<hex>[,v1=<hex>]`,
|
|
280
|
+
one `v1` per live secret of the webhook, each an HMAC-SHA256 with that
|
|
281
|
+
secret over `<t>.<raw body>`, compared in constant time through WebCrypto;
|
|
282
|
+
the one your secret produces is enough. To roll a secret, create the new
|
|
283
|
+
one with `webhooks.createSecret`, move your receiver to it while both
|
|
284
|
+
sign every delivery, then delete the old one. A signature older than five minutes is refused
|
|
252
285
|
(`stale_signature`; `toleranceSeconds` changes the limit), a wrong one
|
|
253
286
|
throws `invalid_signature`.
|
|
254
287
|
|
|
255
|
-
##
|
|
288
|
+
## The account: servers, their keys and domains
|
|
289
|
+
|
|
290
|
+
An account key (`ak_…`) manages the account and never sends. An
|
|
291
|
+
administrator creates one in the dashboard under Account › API keys; the
|
|
292
|
+
account holds up to two live ones. `SendoraAccount` takes the same
|
|
293
|
+
options as `Sendora`.
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
import { Sendora, SendoraAccount } from '@sendora/sdk';
|
|
297
|
+
|
|
298
|
+
const account = new SendoraAccount({ token: process.env.SENDORA_ACCOUNT_TOKEN });
|
|
299
|
+
|
|
300
|
+
const server = await account.servers.create({ name: 'Fakturering' });
|
|
301
|
+
const sendora = new Sendora({ token: server.token.token });
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
A server is created with its default transactional stream and its first
|
|
305
|
+
key, whose value is in the answer this once. A server holds up to two
|
|
306
|
+
live keys and never falls below one, so rotation is create the new key,
|
|
307
|
+
switch to it, revoke the old one.
|
|
308
|
+
|
|
309
|
+
| Call | Answers |
|
|
310
|
+
| --------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
311
|
+
| `account.servers.create({ name })` | The server with its first key as `token`, once; a taken name is `server_exists` |
|
|
312
|
+
| `account.servers.list()` | `{ servers }`, oldest first |
|
|
313
|
+
| `account.servers.get(serverId)` | One server |
|
|
314
|
+
| `account.servers.update(serverId, { name })` | The renamed server |
|
|
315
|
+
| `account.servers.delete(serverId)` | Nothing; `server_in_flight` while its messages are still being delivered |
|
|
316
|
+
| `account.servers.tokens.create(serverId, { name })` | The key with its `token` value, once; a third live key is `token_limit` with `max` |
|
|
317
|
+
| `account.servers.tokens.list(serverId)` | `{ tokens }`, revoked ones included |
|
|
318
|
+
| `account.servers.tokens.get(serverId, tokenId)` | One key, without its value |
|
|
319
|
+
| `account.servers.tokens.revoke(serverId, tokenId)` | Nothing; the last live key is refused (`last_token`) |
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
const { token } = await account.servers.tokens.create(serverId, { name: 'Fakturasystemet' });
|
|
323
|
+
```
|
|
256
324
|
|
|
257
325
|
Sending domains belong to the account, and every server sends from them.
|
|
258
326
|
A domain sends once both DNS records are seen.
|
|
259
327
|
|
|
260
328
|
| Call | Answers |
|
|
261
329
|
| ------------------------------------ | ---------------------------------------------------------------------------- |
|
|
262
|
-
| `
|
|
263
|
-
| `
|
|
264
|
-
| `
|
|
265
|
-
| `
|
|
266
|
-
| `
|
|
330
|
+
| `account.domains.create({ domain })` | The domain with `returnPath` (CNAME) and `dkim` (TXT) to add |
|
|
331
|
+
| `account.domains.list()` | `{ domains }` |
|
|
332
|
+
| `account.domains.get(domainId)` | One domain with the state of its records |
|
|
333
|
+
| `account.domains.verify(domainId)` | The domain plus `check` per record: `ok`, `missing`, `mismatch`, `dns_error` |
|
|
334
|
+
| `account.domains.delete(domainId)` | Nothing; mail from it is refused from then on |
|
|
267
335
|
|
|
268
336
|
```ts
|
|
269
|
-
const domain = await
|
|
337
|
+
const domain = await account.domains.create({ domain: 'example.se' });
|
|
270
338
|
console.log(`${domain.returnPath.type} ${domain.returnPath.host} -> ${domain.returnPath.value}`);
|
|
271
339
|
console.log(`${domain.dkim.type} ${domain.dkim.host} -> ${domain.dkim.value}`);
|
|
272
340
|
```
|
|
273
341
|
|
|
342
|
+
A key of the wrong kind answers `wrong_token_kind`: a server key on the
|
|
343
|
+
account's routes, or an account key on a server's.
|
|
344
|
+
|
|
274
345
|
## Errors
|
|
275
346
|
|
|
276
347
|
Every failed call throws `SendoraError`. Narrow on `code`:
|
|
@@ -298,48 +369,58 @@ try {
|
|
|
298
369
|
}
|
|
299
370
|
```
|
|
300
371
|
|
|
301
|
-
| Code | Status | Meaning
|
|
302
|
-
| --------------------------------- | ------ |
|
|
303
|
-
| `invalid_request` | 400 | A field is wrong; `issues` says which.
|
|
304
|
-
| `idempotency_key_required` | 400 | A batch was sent without a key.
|
|
305
|
-
| `unauthorized` | 401 | The
|
|
306
|
-
| `
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
318
|
-
| `
|
|
319
|
-
| `
|
|
320
|
-
| `
|
|
321
|
-
| `
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
| `
|
|
333
|
-
| `
|
|
334
|
-
| `
|
|
335
|
-
| `
|
|
336
|
-
| `
|
|
337
|
-
| `
|
|
338
|
-
| `
|
|
339
|
-
| `
|
|
372
|
+
| Code | Status | Meaning |
|
|
373
|
+
| --------------------------------- | ------ | ---------------------------------------------------------------------------------------------------- |
|
|
374
|
+
| `invalid_request` | 400 | A field is wrong; `issues` says which. |
|
|
375
|
+
| `idempotency_key_required` | 400 | A batch was sent without a key. |
|
|
376
|
+
| `unauthorized` | 401 | The key is missing, malformed or revoked. |
|
|
377
|
+
| `wrong_token_kind` | 403 | A server key where an account key is needed, or the reverse; `message` names the kind. |
|
|
378
|
+
| `payment_required` | 402 | The account has no active subscription. |
|
|
379
|
+
| `tenant_paused` | 403 | Sendora has paused the account. |
|
|
380
|
+
| `tenant_not_active` | 403 | The account is not approved to send, or not active for an inbound stream. |
|
|
381
|
+
| `spam_complaint_locked` | 403 | Only support can lift a spam-complaint suppression. |
|
|
382
|
+
| `unsubscribe_locked` | 403 | Only support can lift a recipient's own unsubscribe. |
|
|
383
|
+
| `not_found` | 404 | No such id on this server, or no such suppressed address. |
|
|
384
|
+
| `domain_exists` | 409 | The account already has the domain; `existingId` names it. |
|
|
385
|
+
| `domain_reserved` | 400 | The name is Sendora's own; no account can receive on it. |
|
|
386
|
+
| `inbound_domain_exists` | 409 | The stream already has a domain (`existingId` names it), or another account holds the name verified. |
|
|
387
|
+
| `webhook_exists` | 409 | The server already has a webhook for that URL; `existingId` names it. |
|
|
388
|
+
| `stream_exists` | 409 | The server already has a stream with that name; `existingId` names it. |
|
|
389
|
+
| `inbound_stream_exists` | 409 | The server already has a live inbound stream; `existingId` names it. |
|
|
390
|
+
| `default_stream` | 409 | The default stream cannot be archived. |
|
|
391
|
+
| `last_token` | 409 | The only live key cannot be revoked. |
|
|
392
|
+
| `last_secret` | 409 | The only live secret of a webhook cannot be deleted. |
|
|
393
|
+
| `secret_limit` | 409 | The webhook already holds two live secrets; `max` says how many. |
|
|
394
|
+
| `token_limit` | 409 | The server or the account already holds two live keys; `max` says how many. |
|
|
395
|
+
| `server_exists` | 409 | The account already has a server with that name. |
|
|
396
|
+
| `server_limit` | 409 | The account has as many servers as it may; `max` says how many. |
|
|
397
|
+
| `server_reserved` | 409 | The server sends Sendora's own sign-in mail and cannot be renamed or removed. |
|
|
398
|
+
| `server_in_flight` | 409 | Messages of the server are still being delivered; delete it later. |
|
|
399
|
+
| `request_too_large` | 413 | The body exceeds 10 MB. |
|
|
400
|
+
| `from_domain_not_verified` | 422 | The From domain is not a verified sending domain. |
|
|
401
|
+
| `stream_not_found` | 422 | `streamId` names no stream of this server. |
|
|
402
|
+
| `stream_archived` | 422 | The stream is archived and takes no new messages. |
|
|
403
|
+
| `stream_paused` | 422 | Sendora paused the stream after complaints; support resumes it. |
|
|
404
|
+
| `stream_not_sendable` | 422 | An inbound stream receives mail; it takes no messages and has no list. |
|
|
405
|
+
| `stream_not_broadcast` | 422 | A broadcast goes on a broadcast stream; this one is transactional. |
|
|
406
|
+
| `substitution_missing` | 422 | The content names a `{{ key }}` a message does not give. |
|
|
407
|
+
| `broadcast_not_open` | 409 | The broadcast is completed or cancelled; nothing is left to cancel. |
|
|
408
|
+
| `broadcast_not_enabled` | 422 | Broadcast is not enabled for the account: no broadcast stream, no send. |
|
|
409
|
+
| `unsubscribe_placeholder_missing` | 422 | A broadcast message lacks `{{ unsubscribe_url }}` in a part. |
|
|
410
|
+
| `list_unsubscribe_reserved` | 422 | Sendora writes List-Unsubscribe on broadcast streams; leave it out. |
|
|
411
|
+
| `recipient_suppressed` | 422 | Recipients on the suppression list; `suppressed` lists them. |
|
|
412
|
+
| `idempotency_key_mismatch` | 422 | The key was used before with a different body. |
|
|
413
|
+
| `rate_limited` | 429 | Per-minute limit; `retryAfter`, `scope`, `limit`. |
|
|
414
|
+
| `monthly_cap_reached` | 429 | The monthly cap is used up; `scope`, `cap`, `used`, `resetsAt`. |
|
|
415
|
+
| `sending_disabled` | 503 | Sending is paused for everyone; `retryAfter`. |
|
|
416
|
+
| `connection_failed` | none | The request never reached the API; `cause` holds the failure. |
|
|
417
|
+
| `timeout` | none | No answer within `timeoutMs`. |
|
|
418
|
+
| `unexpected_response` | any | An answer without a JSON error body, such as from a proxy. |
|
|
419
|
+
| `invalid_signature` | none | A webhook's signature is missing, malformed or wrong. |
|
|
420
|
+
| `stale_signature` | none | A webhook's signature is older than the tolerance. |
|
|
340
421
|
|
|
341
422
|
`error.retryable` is true when waiting and calling again could succeed.
|
|
342
|
-
Neither the
|
|
423
|
+
Neither the key nor a request body is ever part of an error.
|
|
343
424
|
|
|
344
425
|
## Retries
|
|
345
426
|
|
|
@@ -347,7 +428,8 @@ Lost connections, timeouts, `rate_limited`, `sending_disabled` and server
|
|
|
347
428
|
errors are retried with jittered backoff, twice by default, honouring
|
|
348
429
|
`retryAfter` when it fits within five seconds of waiting in all. A longer
|
|
349
430
|
`retryAfter` is thrown at once for you to schedule. A request that creates
|
|
350
|
-
something (`
|
|
431
|
+
something (`servers.create`, `servers.tokens.create`, `tokens.create`,
|
|
432
|
+
`webhooks.create`, `webhooks.createSecret`, `domains.create`, `replay`)
|
|
351
433
|
is repeated only after a `rate_limited` or `sending_disabled` answer, never
|
|
352
434
|
after a lost connection, so nothing is created twice. Nothing else is
|
|
353
435
|
retried. `new Sendora({ maxRetries: 0 })` turns retries off; `timeoutMs`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DomainsResource } from './domains.ts';
|
|
2
|
+
import { type ClientOptions } from './options.ts';
|
|
3
|
+
import { ServersResource } from './servers.ts';
|
|
4
|
+
export interface SendoraAccountOptions extends ClientOptions {
|
|
5
|
+
/**
|
|
6
|
+
* An account key (`ak_…`), created by an administrator in the dashboard.
|
|
7
|
+
* It manages the account and never sends. Keep it on the server; never
|
|
8
|
+
* ship it to a browser. `undefined`, as an unset environment variable
|
|
9
|
+
* gives, throws at construction rather than at the first call.
|
|
10
|
+
*/
|
|
11
|
+
token: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The account client: the servers, each server's keys and the sending
|
|
15
|
+
* domains, under an account key. Sending, the log, streams, suppressions
|
|
16
|
+
* and webhooks belong to a server and to `Sendora` with a server key.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { Sendora, SendoraAccount } from '@sendora/sdk';
|
|
20
|
+
*
|
|
21
|
+
* const account = new SendoraAccount({ token: process.env.SENDORA_ACCOUNT_TOKEN });
|
|
22
|
+
* const server = await account.servers.create({ name: 'Fakturering' });
|
|
23
|
+
* const sendora = new Sendora({ token: server.token.token });
|
|
24
|
+
*/
|
|
25
|
+
export declare class SendoraAccount {
|
|
26
|
+
readonly servers: ServersResource;
|
|
27
|
+
readonly domains: DomainsResource;
|
|
28
|
+
constructor(options: SendoraAccountOptions);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D;;;;;OAKG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,cAAc;IACzB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;gBAEtB,OAAO,EAAE,qBAAqB;CAS3C"}
|
package/dist/account.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DomainsResource } from "./domains.js";
|
|
2
|
+
import { transportFor } from "./options.js";
|
|
3
|
+
import { ServersResource } from "./servers.js";
|
|
4
|
+
/**
|
|
5
|
+
* The account client: the servers, each server's keys and the sending
|
|
6
|
+
* domains, under an account key. Sending, the log, streams, suppressions
|
|
7
|
+
* and webhooks belong to a server and to `Sendora` with a server key.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { Sendora, SendoraAccount } from '@sendora/sdk';
|
|
11
|
+
*
|
|
12
|
+
* const account = new SendoraAccount({ token: process.env.SENDORA_ACCOUNT_TOKEN });
|
|
13
|
+
* const server = await account.servers.create({ name: 'Fakturering' });
|
|
14
|
+
* const sendora = new Sendora({ token: server.token.token });
|
|
15
|
+
*/
|
|
16
|
+
export class SendoraAccount {
|
|
17
|
+
servers;
|
|
18
|
+
domains;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
const transport = transportFor(options.token, options, 'SendoraAccount needs an account key (ak_…); an administrator creates one in the dashboard.');
|
|
21
|
+
this.servers = new ServersResource(transport);
|
|
22
|
+
this.domains = new DomainsResource(transport);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAsB,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAY/C;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,cAAc;IAChB,OAAO,CAAkB;IACzB,OAAO,CAAkB;IAElC,YAAY,OAA8B;QACxC,MAAM,SAAS,GAAG,YAAY,CAC5B,OAAO,CAAC,KAAK,EACb,OAAO,EACP,4FAA4F,CAC7F,CAAC;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;CACF"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
import { DomainsResource } from './domains.ts';
|
|
2
1
|
import { BroadcastsResource } from './broadcasts.ts';
|
|
3
2
|
import { EmailResource } from './email.ts';
|
|
3
|
+
import { InboundResource } from './inbound.ts';
|
|
4
|
+
import { InboundDomainsResource } from './inbound-domains.ts';
|
|
4
5
|
import { MessagesResource } from './messages.ts';
|
|
6
|
+
import { type ClientOptions } from './options.ts';
|
|
5
7
|
import { StreamsResource } from './streams.ts';
|
|
6
8
|
import { SuppressionsResource } from './suppressions.ts';
|
|
7
9
|
import { TokensResource } from './tokens.ts';
|
|
8
10
|
import { WebhooksResource } from './webhooks.ts';
|
|
9
|
-
export
|
|
10
|
-
export interface SendoraOptions {
|
|
11
|
+
export interface SendoraOptions extends ClientOptions {
|
|
11
12
|
/**
|
|
12
|
-
* A server
|
|
13
|
-
* never ship it to a browser.
|
|
14
|
-
* variable gives, throws at
|
|
13
|
+
* A server key (`sk_…`), answered once when the server is created or a
|
|
14
|
+
* key is added to it. Keep it on the server; never ship it to a browser.
|
|
15
|
+
* `undefined`, as an unset environment variable gives, throws at
|
|
16
|
+
* construction rather than at the first call.
|
|
15
17
|
*/
|
|
16
18
|
token: string | undefined;
|
|
17
|
-
/** The API's origin; https://api.sendora.se unless you test against another. */
|
|
18
|
-
baseUrl?: string | undefined;
|
|
19
|
-
/** The fetch to use; the global one unless you need a proxy or a fake. */
|
|
20
|
-
fetch?: typeof fetch | undefined;
|
|
21
|
-
/** How long one attempt may take; 30 seconds by default. */
|
|
22
|
-
timeoutMs?: number | undefined;
|
|
23
|
-
/** How many times a failed call is repeated when repeating is safe; 2 by default, 0 turns retries off. */
|
|
24
|
-
maxRetries?: number | undefined;
|
|
25
19
|
}
|
|
26
20
|
/**
|
|
27
|
-
* The client. One instance per server
|
|
21
|
+
* The server client. One instance per server key; every resource of the
|
|
22
|
+
* server hangs off it. The account's servers and sending domains are
|
|
23
|
+
* `SendoraAccount` with an account key.
|
|
28
24
|
*
|
|
29
25
|
* @example
|
|
30
26
|
* import { Sendora } from '@sendora/sdk';
|
|
@@ -41,11 +37,12 @@ export declare class Sendora {
|
|
|
41
37
|
readonly email: EmailResource;
|
|
42
38
|
readonly broadcasts: BroadcastsResource;
|
|
43
39
|
readonly messages: MessagesResource;
|
|
40
|
+
readonly inbound: InboundResource;
|
|
41
|
+
readonly inboundDomains: InboundDomainsResource;
|
|
44
42
|
readonly streams: StreamsResource;
|
|
45
43
|
readonly suppressions: SuppressionsResource;
|
|
46
44
|
readonly tokens: TokensResource;
|
|
47
45
|
readonly webhooks: WebhooksResource;
|
|
48
|
-
readonly domains: DomainsResource;
|
|
49
46
|
constructor(options: SendoraOptions);
|
|
50
47
|
}
|
|
51
48
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD;;;;;OAKG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,sBAAsB,CAAC;IAChD,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;gBAExB,OAAO,EAAE,cAAc;CAgBpC"}
|
package/dist/client.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import { DomainsResource } from "./domains.js";
|
|
2
1
|
import { BroadcastsResource } from "./broadcasts.js";
|
|
3
2
|
import { EmailResource } from "./email.js";
|
|
3
|
+
import { InboundResource } from "./inbound.js";
|
|
4
|
+
import { InboundDomainsResource } from "./inbound-domains.js";
|
|
4
5
|
import { MessagesResource } from "./messages.js";
|
|
5
|
-
import {
|
|
6
|
+
import { transportFor } from "./options.js";
|
|
6
7
|
import { StreamsResource } from "./streams.js";
|
|
7
8
|
import { SuppressionsResource } from "./suppressions.js";
|
|
8
9
|
import { TokensResource } from "./tokens.js";
|
|
9
|
-
import { Transport } from "./transport.js";
|
|
10
|
-
import { SDK_VERSION } from "./version.js";
|
|
11
10
|
import { WebhooksResource } from "./webhooks.js";
|
|
12
|
-
export const DEFAULT_BASE_URL = 'https://api.sendora.se';
|
|
13
|
-
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
14
11
|
/**
|
|
15
|
-
* The client. One instance per server
|
|
12
|
+
* The server client. One instance per server key; every resource of the
|
|
13
|
+
* server hangs off it. The account's servers and sending domains are
|
|
14
|
+
* `SendoraAccount` with an account key.
|
|
16
15
|
*
|
|
17
16
|
* @example
|
|
18
17
|
* import { Sendora } from '@sendora/sdk';
|
|
@@ -29,41 +28,23 @@ export class Sendora {
|
|
|
29
28
|
email;
|
|
30
29
|
broadcasts;
|
|
31
30
|
messages;
|
|
31
|
+
inbound;
|
|
32
|
+
inboundDomains;
|
|
32
33
|
streams;
|
|
33
34
|
suppressions;
|
|
34
35
|
tokens;
|
|
35
36
|
webhooks;
|
|
36
|
-
domains;
|
|
37
37
|
constructor(options) {
|
|
38
|
-
|
|
39
|
-
throw new TypeError('Sendora needs a server API token; create one in the dashboard.');
|
|
40
|
-
}
|
|
41
|
-
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
42
|
-
new URL(baseUrl);
|
|
43
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
44
|
-
if (!(timeoutMs > 0)) {
|
|
45
|
-
throw new TypeError('timeoutMs must be a positive number of milliseconds.');
|
|
46
|
-
}
|
|
47
|
-
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
48
|
-
if (!Number.isInteger(maxRetries) || maxRetries < 0) {
|
|
49
|
-
throw new TypeError('maxRetries must be a whole number of zero or more.');
|
|
50
|
-
}
|
|
51
|
-
const transport = new Transport({
|
|
52
|
-
baseUrl,
|
|
53
|
-
token: options.token,
|
|
54
|
-
fetch: options.fetch ?? fetch,
|
|
55
|
-
timeoutMs,
|
|
56
|
-
maxRetries,
|
|
57
|
-
userAgent: `sendora-sdk/${SDK_VERSION}`,
|
|
58
|
-
});
|
|
38
|
+
const transport = transportFor(options.token, options, 'Sendora needs a server key (sk_…); it is shown once when the server or the key is created.');
|
|
59
39
|
this.email = new EmailResource(transport);
|
|
60
40
|
this.broadcasts = new BroadcastsResource(transport);
|
|
61
41
|
this.messages = new MessagesResource(transport);
|
|
42
|
+
this.inbound = new InboundResource(transport);
|
|
43
|
+
this.inboundDomains = new InboundDomainsResource(transport);
|
|
62
44
|
this.streams = new StreamsResource(transport);
|
|
63
45
|
this.suppressions = new SuppressionsResource(transport);
|
|
64
46
|
this.tokens = new TokensResource(transport);
|
|
65
47
|
this.webhooks = new WebhooksResource(transport);
|
|
66
|
-
this.domains = new DomainsResource(transport);
|
|
67
48
|
}
|
|
68
49
|
}
|
|
69
50
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAsB,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAYjD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,OAAO;IACT,KAAK,CAAgB;IACrB,UAAU,CAAqB;IAC/B,QAAQ,CAAmB;IAC3B,OAAO,CAAkB;IACzB,cAAc,CAAyB;IACvC,OAAO,CAAkB;IACzB,YAAY,CAAuB;IACnC,MAAM,CAAiB;IACvB,QAAQ,CAAmB;IAEpC,YAAY,OAAuB;QACjC,MAAM,SAAS,GAAG,YAAY,CAC5B,OAAO,CAAC,KAAK,EACb,OAAO,EACP,4FAA4F,CAC7F,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,GAAG,IAAI,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,cAAc,GAAG,IAAI,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,YAAY,GAAG,IAAI,oBAAoB,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;CACF"}
|
package/dist/domains.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Transport } from './transport.ts';
|
|
2
2
|
import type { CreateDomainRequest, DomainList, RequestOptions, SendingDomain, VerifiedDomain } from './types.ts';
|
|
3
|
-
/** The account's sending domains and the two DNS records each one needs
|
|
3
|
+
/** The account's sending domains and the two DNS records each one needs, managed with the account key; every server sends from them. */
|
|
4
4
|
export declare class DomainsResource {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(transport: Transport);
|
package/dist/domains.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../src/domains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EACV,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,
|
|
1
|
+
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../src/domains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EACV,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,wIAAwI;AACxI,qBAAa,eAAe;;gBAGd,SAAS,EAAE,SAAS;IAIhC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,OAAO,EAAE,mBAAmB,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAU1F,2CAA2C;IAC3C,IAAI,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IASvD,uDAAuD;IACvD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAS3E;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,cAAc,CAAC;IAS/E,yFAAyF;IACzF,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CAQtE"}
|
package/dist/domains.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The account's sending domains and the two DNS records each one needs
|
|
1
|
+
/** The account's sending domains and the two DNS records each one needs, managed with the account key; every server sends from them. */
|
|
2
2
|
export class DomainsResource {
|
|
3
3
|
#transport;
|
|
4
4
|
constructor(transport) {
|
package/dist/domains.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domains.js","sourceRoot":"","sources":["../src/domains.ts"],"names":[],"mappings":"AASA,
|
|
1
|
+
{"version":3,"file":"domains.js","sourceRoot":"","sources":["../src/domains.ts"],"names":[],"mappings":"AASA,wIAAwI;AACxI,MAAM,OAAO,eAAe;IACjB,UAAU,CAAY;IAE/B,YAAY,SAAoB;QAC9B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,OAA4B,EAAE,UAA0B,EAAE;QAC/D,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAgB;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,2CAA2C;IAC3C,IAAI,CAAC,UAA0B,EAAE;QAC/B,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAa;YACzC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,aAAa;YACnB,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,uDAAuD;IACvD,GAAG,CAAC,QAAgB,EAAE,UAA0B,EAAE;QAChD,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAgB;YAC5C,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,eAAe,kBAAkB,CAAC,QAAQ,CAAC,EAAE;YACnD,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,QAAgB,EAAE,UAA0B,EAAE;QACnD,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAiB;YAC7C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,eAAe,kBAAkB,CAAC,QAAQ,CAAC,SAAS;YAC1D,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,yFAAyF;IACzF,MAAM,CAAC,QAAgB,EAAE,UAA0B,EAAE;QACnD,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAY;YACxC,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,eAAe,kBAAkB,CAAC,QAAQ,CAAC,EAAE;YACnD,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/dist/error.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { LimitScope, SuppressedRecipient, ValidationIssue } from './types.ts';
|
|
2
|
-
/** Every code the API answers, the three the SDK raises when it never got a proper answer, and the two of the webhook verifier. */
|
|
3
|
-
export type SendoraErrorCode = 'invalid_request' | 'unauthorized' | 'payment_required' | 'tenant_paused' | 'tenant_not_active' | 'spam_complaint_locked' | 'unsubscribe_locked' | 'not_found' | 'domain_exists' | 'webhook_exists' | 'stream_exists' | 'inbound_stream_exists' | 'default_stream' | 'last_token' | 'request_too_large' | 'from_domain_not_verified' | 'stream_not_found' | 'stream_archived' | 'stream_paused' | 'stream_not_sendable' | 'stream_not_broadcast' | 'broadcast_not_enabled' | 'broadcast_not_open' | 'substitution_missing' | 'unsubscribe_placeholder_missing' | 'list_unsubscribe_reserved' | 'recipient_suppressed' | 'idempotency_key_mismatch' | 'idempotency_key_required' | 'rate_limited' | 'monthly_cap_reached' | 'sending_disabled' | 'connection_failed' | 'timeout' | 'unexpected_response' | 'invalid_signature' | 'stale_signature';
|
|
2
|
+
/** Every code the API answers, under either kind of key, the three the SDK raises when it never got a proper answer, and the two of the webhook verifier. */
|
|
3
|
+
export type SendoraErrorCode = 'invalid_request' | 'unauthorized' | 'wrong_token_kind' | 'payment_required' | 'tenant_paused' | 'tenant_not_active' | 'spam_complaint_locked' | 'unsubscribe_locked' | 'not_found' | 'domain_exists' | 'domain_reserved' | 'inbound_domain_exists' | 'webhook_exists' | 'stream_exists' | 'inbound_stream_exists' | 'default_stream' | 'last_token' | 'token_limit' | 'last_secret' | 'secret_limit' | 'server_exists' | 'server_limit' | 'server_reserved' | 'server_in_flight' | 'request_too_large' | 'from_domain_not_verified' | 'stream_not_found' | 'stream_archived' | 'stream_paused' | 'stream_not_sendable' | 'stream_not_broadcast' | 'broadcast_not_enabled' | 'broadcast_not_open' | 'substitution_missing' | 'unsubscribe_placeholder_missing' | 'list_unsubscribe_reserved' | 'content_expired' | 'content_unreadable' | 'recipient_suppressed' | 'idempotency_key_mismatch' | 'idempotency_key_required' | 'rate_limited' | 'monthly_cap_reached' | 'sending_disabled' | 'connection_failed' | 'timeout' | 'unexpected_response' | 'invalid_signature' | 'stale_signature';
|
|
4
4
|
export interface SendoraErrorFields {
|
|
5
5
|
code: SendoraErrorCode;
|
|
6
6
|
message: string;
|
|
@@ -11,6 +11,7 @@ export interface SendoraErrorFields {
|
|
|
11
11
|
cap?: number | null;
|
|
12
12
|
used?: number | null;
|
|
13
13
|
resetsAt?: string | null;
|
|
14
|
+
max?: number | null;
|
|
14
15
|
issues?: ValidationIssue[];
|
|
15
16
|
suppressed?: SuppressedRecipient[];
|
|
16
17
|
streamId?: string | null;
|
|
@@ -49,13 +50,15 @@ export declare class SendoraError extends Error {
|
|
|
49
50
|
readonly used: number | null;
|
|
50
51
|
/** When the month counter resets, on monthly_cap_reached. */
|
|
51
52
|
readonly resetsAt: string | null;
|
|
53
|
+
/** Live keys the server or the account may hold, on token_limit; servers the account may have, on server_limit; live secrets a webhook may hold, on secret_limit. */
|
|
54
|
+
readonly max: number | null;
|
|
52
55
|
/** One entry per invalid field, on invalid_request. */
|
|
53
56
|
readonly issues: ValidationIssue[];
|
|
54
57
|
/** The recipients the server refused, on recipient_suppressed. */
|
|
55
58
|
readonly suppressed: SuppressedRecipient[];
|
|
56
59
|
/** The stream whose suppression list refused the send, on recipient_suppressed. */
|
|
57
60
|
readonly streamId: string | null;
|
|
58
|
-
/** The id of the domain, webhook or stream that already exists, on domain_exists, webhook_exists and
|
|
61
|
+
/** The id of the domain, webhook or stream that already exists, on domain_exists, webhook_exists, stream_exists, inbound_stream_exists and, when the stream already has a domain, inbound_domain_exists. */
|
|
59
62
|
readonly existingId: string | null;
|
|
60
63
|
constructor(fields: SendoraErrorFields);
|
|
61
64
|
/** True when waiting and calling again could succeed: a rate limit, sending paused for everyone, a lost connection, a timeout, or a server-side failure. */
|