@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.
Files changed (69) hide show
  1. package/README.md +152 -70
  2. package/dist/account.d.ts +30 -0
  3. package/dist/account.d.ts.map +1 -0
  4. package/dist/account.js +25 -0
  5. package/dist/account.js.map +1 -0
  6. package/dist/client.d.ts +13 -16
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +11 -30
  9. package/dist/client.js.map +1 -1
  10. package/dist/domains.d.ts +1 -1
  11. package/dist/domains.d.ts.map +1 -1
  12. package/dist/domains.js +1 -1
  13. package/dist/domains.js.map +1 -1
  14. package/dist/error.d.ts +6 -3
  15. package/dist/error.d.ts.map +1 -1
  16. package/dist/error.js +22 -2
  17. package/dist/error.js.map +1 -1
  18. package/dist/inbound-domains.d.ts +36 -0
  19. package/dist/inbound-domains.d.ts.map +1 -0
  20. package/dist/inbound-domains.js +72 -0
  21. package/dist/inbound-domains.js.map +1 -0
  22. package/dist/inbound.d.ts +61 -0
  23. package/dist/inbound.d.ts.map +1 -0
  24. package/dist/inbound.js +106 -0
  25. package/dist/inbound.js.map +1 -0
  26. package/dist/index.d.ts +8 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/options.d.ts +20 -0
  31. package/dist/options.d.ts.map +1 -0
  32. package/dist/options.js +34 -0
  33. package/dist/options.js.map +1 -0
  34. package/dist/servers.d.ts +64 -0
  35. package/dist/servers.d.ts.map +1 -0
  36. package/dist/servers.js +133 -0
  37. package/dist/servers.js.map +1 -0
  38. package/dist/transport.d.ts +2 -0
  39. package/dist/transport.d.ts.map +1 -1
  40. package/dist/transport.js +15 -5
  41. package/dist/transport.js.map +1 -1
  42. package/dist/types.d.ts +182 -5
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/version.d.ts +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist/webhook-verify.d.ts +7 -5
  47. package/dist/webhook-verify.d.ts.map +1 -1
  48. package/dist/webhook-verify.js +38 -17
  49. package/dist/webhook-verify.js.map +1 -1
  50. package/dist/webhooks.d.ts +13 -1
  51. package/dist/webhooks.d.ts.map +1 -1
  52. package/dist/webhooks.js +26 -0
  53. package/dist/webhooks.js.map +1 -1
  54. package/package.json +4 -9
  55. package/skills/sendora/SKILL.md +19 -9
  56. package/src/account.ts +40 -0
  57. package/src/client.ts +20 -43
  58. package/src/domains.ts +1 -1
  59. package/src/error.ts +36 -3
  60. package/src/inbound-domains.ts +89 -0
  61. package/src/inbound.ts +135 -0
  62. package/src/index.ts +8 -1
  63. package/src/options.ts +51 -0
  64. package/src/servers.ts +166 -0
  65. package/src/transport.ts +26 -5
  66. package/src/types.ts +194 -5
  67. package/src/version.ts +1 -1
  68. package/src/webhook-verify.ts +39 -18
  69. 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 hosted in Sweden. Zero dependencies. Runs on Node 20.19 or
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
- The token is a secret. Create it in the dashboard, keep it on the server,
14
- and never ship it to a browser. The client throws at construction when the
15
- token is missing, so build it at startup.
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 | Answers |
73
- | -------------------------------------- | --------------------------------------------------------------------------- |
74
- | `sendora.messages.get(messageId)` | The message with its recipients, its attachments described and its timeline |
75
- | `sendora.messages.search(filters?)` | `{ messages, next }`, one page newest first |
76
- | `sendora.messages.searchAll(filters?)` | Every match, page by page, for `for await` |
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
- Every token of a server has the same rights; the value is shown once, when
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 token is refused (`last_token`) |
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>`, an
250
- HMAC-SHA256 with your secret over `<t>.<raw body>`, compared in constant
251
- time through WebCrypto. A signature older than five minutes is refused
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
- ## Domains
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
- | `sendora.domains.create({ domain })` | The domain with `returnPath` (CNAME) and `dkim` (TXT) to add |
263
- | `sendora.domains.list()` | `{ domains }` |
264
- | `sendora.domains.get(domainId)` | One domain with the state of its records |
265
- | `sendora.domains.verify(domainId)` | The domain plus `check` per record: `ok`, `missing`, `mismatch`, `dns_error` |
266
- | `sendora.domains.delete(domainId)` | Nothing; mail from it is refused from then on |
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 sendora.domains.create({ domain: 'example.se' });
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 token is missing, malformed or revoked. |
306
- | `payment_required` | 402 | The account has no active subscription. |
307
- | `tenant_paused` | 403 | Sendora has paused the account. |
308
- | `tenant_not_active` | 403 | The account is not approved to send, or not active for an inbound stream. |
309
- | `spam_complaint_locked` | 403 | Only support can lift a spam-complaint suppression. |
310
- | `unsubscribe_locked` | 403 | Only support can lift a recipient's own unsubscribe. |
311
- | `not_found` | 404 | No such id on this server, or no such suppressed address. |
312
- | `domain_exists` | 409 | The account already has the domain; `existingId` names it. |
313
- | `webhook_exists` | 409 | The server already has a webhook for that URL; `existingId` names it. |
314
- | `stream_exists` | 409 | The server already has a stream with that name; `existingId` names it. |
315
- | `inbound_stream_exists` | 409 | The server already has a live inbound stream; `existingId` names it. |
316
- | `default_stream` | 409 | The default stream cannot be archived. |
317
- | `last_token` | 409 | The only live token cannot be revoked. |
318
- | `request_too_large` | 413 | The body exceeds 10 MB. |
319
- | `from_domain_not_verified` | 422 | The From domain is not a verified sending domain. |
320
- | `stream_not_found` | 422 | `streamId` names no stream of this server. |
321
- | `stream_archived` | 422 | The stream is archived and takes no new messages. |
322
- | `stream_paused` | 422 | Sendora paused the stream after complaints; support resumes it. |
323
- | `stream_not_sendable` | 422 | An inbound stream receives mail; it takes no messages and has no list. |
324
- | `stream_not_broadcast` | 422 | A broadcast goes on a broadcast stream; this one is transactional. |
325
- | `substitution_missing` | 422 | The content names a `{{ key }}` a message does not give. |
326
- | `broadcast_not_open` | 409 | The broadcast is completed or cancelled; nothing is left to cancel. |
327
- | `broadcast_not_enabled` | 422 | Broadcast is not enabled for the account: no broadcast stream, no send. |
328
- | `unsubscribe_placeholder_missing` | 422 | A broadcast message lacks `{{ unsubscribe_url }}` in a part. |
329
- | `list_unsubscribe_reserved` | 422 | Sendora writes List-Unsubscribe on broadcast streams; leave it out. |
330
- | `recipient_suppressed` | 422 | Recipients on the suppression list; `suppressed` lists them. |
331
- | `idempotency_key_mismatch` | 422 | The key was used before with a different body. |
332
- | `rate_limited` | 429 | Per-minute limit; `retryAfter`, `scope`, `limit`. |
333
- | `monthly_cap_reached` | 429 | The monthly cap is used up; `scope`, `cap`, `used`, `resetsAt`. |
334
- | `sending_disabled` | 503 | Sending is paused for everyone; `retryAfter`. |
335
- | `connection_failed` | none | The request never reached the API; `cause` holds the failure. |
336
- | `timeout` | none | No answer within `timeoutMs`. |
337
- | `unexpected_response` | any | An answer without a JSON error body, such as from a proxy. |
338
- | `invalid_signature` | none | A webhook's signature is missing, malformed or wrong. |
339
- | `stale_signature` | none | A webhook's signature is older than the tolerance. |
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 token nor a request body is ever part of an error.
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 (`tokens.create`, `webhooks.create`, `domains.create`, `replay`)
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"}
@@ -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 declare const DEFAULT_BASE_URL = "https://api.sendora.se";
10
- export interface SendoraOptions {
11
+ export interface SendoraOptions extends ClientOptions {
11
12
  /**
12
- * A server's API token, created in the dashboard. Keep it on the server;
13
- * never ship it to a browser. `undefined`, as an unset environment
14
- * variable gives, throws at construction rather than at the first call.
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 token; every resource hangs off it.
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
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,eAAO,MAAM,gBAAgB,2BAA2B,CAAC;AAGzD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IACjC,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,0GAA0G;IAC1G,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;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,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;gBAEtB,OAAO,EAAE,cAAc;CA+BpC"}
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 { DEFAULT_MAX_RETRIES } from "./retry.js";
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 token; every resource hangs off it.
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
- if (options.token === undefined || options.token.trim() === '') {
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
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,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,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AACzD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAmBlC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,OAAO;IACT,KAAK,CAAgB;IACrB,UAAU,CAAqB;IAC/B,QAAQ,CAAmB;IAC3B,OAAO,CAAkB;IACzB,YAAY,CAAuB;IACnC,MAAM,CAAiB;IACvB,QAAQ,CAAmB;IAC3B,OAAO,CAAkB;IAElC,YAAY,OAAuB;QACjC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/D,MAAM,IAAI,SAAS,CAAC,gEAAgE,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;QACpD,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QACjB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;QAC1D,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,SAAS,CAAC,sDAAsD,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;QAC7D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;YAC9B,OAAO;YACP,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;YAC7B,SAAS;YACT,UAAU;YACV,SAAS,EAAE,eAAe,WAAW,EAAE;SACxC,CAAC,CAAC;QACH,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,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;QAChD,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;CACF"}
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. Any server's token manages them. */
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);
@@ -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,6GAA6G;AAC7G,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"}
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. Any server's token manages them. */
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) {
@@ -1 +1 @@
1
- {"version":3,"file":"domains.js","sourceRoot":"","sources":["../src/domains.ts"],"names":[],"mappings":"AASA,6GAA6G;AAC7G,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"}
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 stream_exists. */
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. */