@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/src/types.ts
CHANGED
|
@@ -296,6 +296,112 @@ export interface MessagePage {
|
|
|
296
296
|
next: string | null;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
/** The body POST /v1/inbound/search takes. */
|
|
300
|
+
export interface InboundSearchBody {
|
|
301
|
+
streamId?: string | undefined;
|
|
302
|
+
from?: string | undefined;
|
|
303
|
+
recipient?: string | undefined;
|
|
304
|
+
mailboxHash?: string | undefined;
|
|
305
|
+
receivedFrom?: string | undefined;
|
|
306
|
+
receivedTo?: string | undefined;
|
|
307
|
+
limit?: number | undefined;
|
|
308
|
+
after?: string | undefined;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** The filters of a search over received mail; every one is optional. */
|
|
312
|
+
export interface InboundSearch {
|
|
313
|
+
/** Messages received on this inbound stream of the server. */
|
|
314
|
+
streamId?: string | undefined;
|
|
315
|
+
/** Messages from this address, in the envelope or the From header. */
|
|
316
|
+
from?: string | undefined;
|
|
317
|
+
/** Messages sent to this address of yours. */
|
|
318
|
+
recipient?: string | undefined;
|
|
319
|
+
/** Messages whose address carried this text after the plus sign. */
|
|
320
|
+
mailboxHash?: string | undefined;
|
|
321
|
+
/** Accepted at or after this time. */
|
|
322
|
+
receivedFrom?: Date | string | undefined;
|
|
323
|
+
/** Accepted before this time. */
|
|
324
|
+
receivedTo?: Date | string | undefined;
|
|
325
|
+
/** Page size, 1 to 100; 50 when left out. */
|
|
326
|
+
limit?: number | undefined;
|
|
327
|
+
/** The `next` value of the previous page. */
|
|
328
|
+
after?: string | undefined;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** An attachment of a received message, described; its bytes are `sendora.inbound.attachment`. */
|
|
332
|
+
export interface InboundMessageAttachment {
|
|
333
|
+
attachmentId: string;
|
|
334
|
+
/** Its place among the message's attachments, from 0. */
|
|
335
|
+
position: number;
|
|
336
|
+
/** The filename, sanitised; null once the content is gone. */
|
|
337
|
+
name: string | null;
|
|
338
|
+
/** The type the sender declared; every download is served as application/octet-stream. */
|
|
339
|
+
contentType: string | null;
|
|
340
|
+
/** The Content-ID an HTML body refers to with `cid:`. */
|
|
341
|
+
contentId: string | null;
|
|
342
|
+
size: number;
|
|
343
|
+
/** True for a part shown in the body rather than offered as a file. */
|
|
344
|
+
inline: boolean;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** A received message as the list shows it. */
|
|
348
|
+
export interface InboundMessage {
|
|
349
|
+
inboundMessageId: string;
|
|
350
|
+
/** The inbound stream that received it. */
|
|
351
|
+
streamId: string;
|
|
352
|
+
/** When the message was accepted from the sending server. */
|
|
353
|
+
receivedAt: string;
|
|
354
|
+
/** The address of yours the message was sent to. */
|
|
355
|
+
envelopeRecipient: string;
|
|
356
|
+
/** The text after the plus sign in that address, when the sender used one. */
|
|
357
|
+
mailboxHash: string | null;
|
|
358
|
+
sizeBytes: number;
|
|
359
|
+
attachmentCount: number;
|
|
360
|
+
hasText: boolean;
|
|
361
|
+
hasHtml: boolean;
|
|
362
|
+
/** What the parser met, from a closed set; null when the message parsed clean. */
|
|
363
|
+
parseIssue: string | null;
|
|
364
|
+
authentication: InboundAuthentication;
|
|
365
|
+
/** False once the stream's content window has passed; only the reference remains. */
|
|
366
|
+
contentAvailable: boolean;
|
|
367
|
+
/** When the content goes. */
|
|
368
|
+
contentExpiresAt: string;
|
|
369
|
+
/** The From header; null without it or once the content is gone. */
|
|
370
|
+
from: InboundAddress | null;
|
|
371
|
+
subject: string | null;
|
|
372
|
+
/** The sender's Date header as ISO 8601, when it was a real moment. */
|
|
373
|
+
date: string | null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** The received message with everything but the attachment bytes. */
|
|
377
|
+
export interface InboundMessageDetail extends InboundMessage {
|
|
378
|
+
/** The envelope sender; null for a bounce, or once the content is gone. */
|
|
379
|
+
envelope: { sender: string | null } | null;
|
|
380
|
+
replyTo: InboundAddress[];
|
|
381
|
+
/** Up to 100 entries; `toCount` is the whole number. */
|
|
382
|
+
to: InboundAddress[];
|
|
383
|
+
toCount: number;
|
|
384
|
+
cc: InboundAddress[];
|
|
385
|
+
ccCount: number;
|
|
386
|
+
messageIdHeader: string | null;
|
|
387
|
+
inReplyTo: string | null;
|
|
388
|
+
references: string[];
|
|
389
|
+
/** Every header in order; null once the content is gone. */
|
|
390
|
+
headers: InboundHeader[] | null;
|
|
391
|
+
/** The plain-text body; null without one or once the content is gone. */
|
|
392
|
+
text: string | null;
|
|
393
|
+
/** The HTML body as received; null without one or once the content is gone. */
|
|
394
|
+
html: string | null;
|
|
395
|
+
attachments: InboundMessageAttachment[];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** One page of received messages, newest first. */
|
|
399
|
+
export interface InboundPage {
|
|
400
|
+
messages: InboundMessage[];
|
|
401
|
+
/** Pass as `after` for the next page; null on the last. */
|
|
402
|
+
next: string | null;
|
|
403
|
+
}
|
|
404
|
+
|
|
299
405
|
/** Cursor paging for the lists that page. */
|
|
300
406
|
export interface PageQuery {
|
|
301
407
|
/** Page size, 1 to 1000; 100 when left out. */
|
|
@@ -480,13 +586,13 @@ export interface BroadcastPage {
|
|
|
480
586
|
/** What `broadcasts.list` takes. */
|
|
481
587
|
export type BroadcastList = PageQuery;
|
|
482
588
|
|
|
483
|
-
/** The body POST /v1/tokens
|
|
589
|
+
/** The body POST /v1/tokens and POST /v1/servers/{id}/tokens take. */
|
|
484
590
|
export interface CreateTokenRequest {
|
|
485
591
|
/** 1 to 100 characters, for people to tell tokens apart. */
|
|
486
592
|
name: string;
|
|
487
593
|
}
|
|
488
594
|
|
|
489
|
-
/** A
|
|
595
|
+
/** A key of a server; its value is shown only when it is created. */
|
|
490
596
|
export interface Token {
|
|
491
597
|
tokenId: string;
|
|
492
598
|
name: string;
|
|
@@ -496,7 +602,7 @@ export interface Token {
|
|
|
496
602
|
revokedAt: string | null;
|
|
497
603
|
}
|
|
498
604
|
|
|
499
|
-
/** A
|
|
605
|
+
/** A key just created, with its value, shown this once. */
|
|
500
606
|
export interface CreatedToken extends Token {
|
|
501
607
|
token: string;
|
|
502
608
|
}
|
|
@@ -505,6 +611,37 @@ export interface TokenList {
|
|
|
505
611
|
tokens: Token[];
|
|
506
612
|
}
|
|
507
613
|
|
|
614
|
+
/** A server of the account: an isolation boundary with its own keys, streams, log, suppressions and webhooks. */
|
|
615
|
+
export interface Server {
|
|
616
|
+
/** The id every server key, stream and message of the server refers to. */
|
|
617
|
+
serverId: string;
|
|
618
|
+
/** The name given at creation, unique within the account. */
|
|
619
|
+
name: string;
|
|
620
|
+
createdAt: string;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/** A server just created, with its first key, whose value is shown this once. */
|
|
624
|
+
export interface CreatedServer extends Server {
|
|
625
|
+
/** The server's first key, named default; its value is never shown again. */
|
|
626
|
+
token: CreatedToken;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
export interface ServerList {
|
|
630
|
+
servers: Server[];
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** The body POST /v1/servers takes. */
|
|
634
|
+
export interface CreateServerRequest {
|
|
635
|
+
/** 1 to 100 characters, unique within the account. */
|
|
636
|
+
name: string;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/** The body PATCH /v1/servers/{id} takes. */
|
|
640
|
+
export interface UpdateServerRequest {
|
|
641
|
+
/** 1 to 100 characters, unique within the account. */
|
|
642
|
+
name: string;
|
|
643
|
+
}
|
|
644
|
+
|
|
508
645
|
/** The events a webhook can receive. */
|
|
509
646
|
export type WebhookEventName =
|
|
510
647
|
| 'delivered'
|
|
@@ -543,6 +680,19 @@ export interface Webhook {
|
|
|
543
680
|
/** How the inbound event carries a received message: the parsed message, or a reference. */
|
|
544
681
|
inboundContent: InboundContent;
|
|
545
682
|
createdAt: string;
|
|
683
|
+
/** The live secrets, oldest first; every delivery is signed with each of them, the newest first in Sendora-Signature. */
|
|
684
|
+
secrets: WebhookSecret[];
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/** A live signing secret of a webhook by id and age; its value was shown once when it was created. */
|
|
688
|
+
export interface WebhookSecret {
|
|
689
|
+
secretId: string;
|
|
690
|
+
createdAt: string;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/** A secret just created, with its value, shown this once. */
|
|
694
|
+
export interface CreatedWebhookSecret extends WebhookSecret {
|
|
695
|
+
secret: string;
|
|
546
696
|
}
|
|
547
697
|
|
|
548
698
|
/** A webhook just created, with its signing secret, shown this once. */
|
|
@@ -567,6 +717,8 @@ export interface Delivery {
|
|
|
567
717
|
event: WebhookEventName;
|
|
568
718
|
/** Null for an event about usage rather than a message. */
|
|
569
719
|
messageId: string | null;
|
|
720
|
+
/** The received message an inbound event is about; null for every other event. */
|
|
721
|
+
inboundMessageId: string | null;
|
|
570
722
|
status: DeliveryStatus;
|
|
571
723
|
attempts: number;
|
|
572
724
|
/** When the next attempt is due, while pending. */
|
|
@@ -598,7 +750,7 @@ export interface CreateDomainRequest {
|
|
|
598
750
|
}
|
|
599
751
|
|
|
600
752
|
/** A DNS record the domain needs and whether it has been seen. */
|
|
601
|
-
export interface DnsRecord<Type extends 'CNAME' | 'TXT'> {
|
|
753
|
+
export interface DnsRecord<Type extends 'CNAME' | 'TXT' | 'MX'> {
|
|
602
754
|
type: Type;
|
|
603
755
|
/** The name to create the record under. */
|
|
604
756
|
host: string;
|
|
@@ -635,6 +787,43 @@ export interface DomainList {
|
|
|
635
787
|
domains: SendingDomain[];
|
|
636
788
|
}
|
|
637
789
|
|
|
790
|
+
/** The body POST /v1/inbound/domains takes. */
|
|
791
|
+
export interface CreateInboundDomainRequest {
|
|
792
|
+
/** An inbound stream of the server. */
|
|
793
|
+
streamId: string;
|
|
794
|
+
/** The domain to receive on, such as post.example.se. */
|
|
795
|
+
domain: string;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/** A domain on an inbound stream and the two records it needs. */
|
|
799
|
+
export interface InboundDomain {
|
|
800
|
+
inboundDomainId: string;
|
|
801
|
+
/** The inbound stream the domain delivers to. */
|
|
802
|
+
streamId: string;
|
|
803
|
+
/** The domain, lower-cased and IDNA-encoded. */
|
|
804
|
+
domain: string;
|
|
805
|
+
/** True while both records are seen; only then is mail to the domain accepted. */
|
|
806
|
+
verified: boolean;
|
|
807
|
+
createdAt: string;
|
|
808
|
+
/** When the records were last looked up. */
|
|
809
|
+
lastCheckedAt: string | null;
|
|
810
|
+
/** When a verified domain lost its records. Mail to it is deferred for 72 hours from then and refused after, until the records are back. */
|
|
811
|
+
unverifiedAt: string | null;
|
|
812
|
+
/** The MX record that brings the domain's mail to Sendora, at any priority. */
|
|
813
|
+
mx: DnsRecord<'MX'>;
|
|
814
|
+
/** The TXT record that proves the claim; it carries a token only you were shown. */
|
|
815
|
+
txt: DnsRecord<'TXT'>;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/** The domain as it stands after a check, and what each lookup found. */
|
|
819
|
+
export interface VerifiedInboundDomain extends InboundDomain {
|
|
820
|
+
check: { mx: RecordCheck; txt: RecordCheck };
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
export interface InboundDomainList {
|
|
824
|
+
domains: InboundDomain[];
|
|
825
|
+
}
|
|
826
|
+
|
|
638
827
|
/** What every event about a message carries. */
|
|
639
828
|
export interface MessageEventFields {
|
|
640
829
|
/** The delivery id. Deliveries arrive at least once, so key your handling on it. */
|
|
@@ -831,7 +1020,7 @@ export interface InboundEventContent {
|
|
|
831
1020
|
/**
|
|
832
1021
|
* A message received on an inbound stream. The content fields are present
|
|
833
1022
|
* for a webhook with `inboundContent: 'full'` and absent for
|
|
834
|
-
* `reference`; `
|
|
1023
|
+
* `reference`; `event.contentOmitted !== undefined` tells them apart.
|
|
835
1024
|
*/
|
|
836
1025
|
export type InboundEvent = InboundEventFields &
|
|
837
1026
|
(InboundEventContent | { contentOmitted?: undefined });
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The package version, sent as the User-Agent; a test holds it equal to package.json. */
|
|
2
|
-
export const SDK_VERSION = '
|
|
2
|
+
export const SDK_VERSION = '2.1.0';
|
package/src/webhook-verify.ts
CHANGED
|
@@ -33,11 +33,13 @@ const decoder = new TextDecoder();
|
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Checks a webhook request came from Sendora and answers its event, typed
|
|
36
|
-
* by `event`. The header is `Sendora-Signature: t=<unix seconds>,v1=<hex
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
36
|
+
* by `event`. The header is `Sendora-Signature: t=<unix seconds>,v1=<hex>[,v1=<hex>]`,
|
|
37
|
+
* one hex per live secret of the webhook, each an HMAC-SHA256 with that
|
|
38
|
+
* secret over `<t>.<raw body>`; the one your secret produces is enough, so
|
|
39
|
+
* a secret being rolled in verifies as well as the old one. The timestamp
|
|
40
|
+
* is inside the signed text, so a captured request cannot be replayed
|
|
41
|
+
* after the tolerance. Throws `SendoraError` with `invalid_signature` or
|
|
42
|
+
* `stale_signature`.
|
|
41
43
|
*
|
|
42
44
|
* @example
|
|
43
45
|
* const event = await verifyWebhook({
|
|
@@ -72,36 +74,55 @@ export async function verifyWebhook(input: VerifyWebhookInput): Promise<WebhookE
|
|
|
72
74
|
false,
|
|
73
75
|
['verify'],
|
|
74
76
|
);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
// Every signature is checked, so the time taken says nothing about which one matched.
|
|
78
|
+
let matched = false;
|
|
79
|
+
for (const mac of signature.macs) {
|
|
80
|
+
matched = (await crypto.subtle.verify('HMAC', key, mac, signed)) || matched;
|
|
81
|
+
}
|
|
82
|
+
if (!matched) {
|
|
83
|
+
throw invalidSignature('No signature in the header matches the body under this secret.');
|
|
77
84
|
}
|
|
78
85
|
return parseEvent(decoder.decode(body));
|
|
79
86
|
}
|
|
80
87
|
|
|
88
|
+
/** The timestamp and every `v1` value, one per live secret of the webhook. */
|
|
81
89
|
function parseSignature(header: string | null | undefined): {
|
|
82
90
|
timestamp: number;
|
|
83
|
-
|
|
91
|
+
macs: Uint8Array<ArrayBuffer>[];
|
|
84
92
|
} {
|
|
85
93
|
if (typeof header !== 'string' || header === '') {
|
|
86
94
|
throw invalidSignature('The request carries no Sendora-Signature header.');
|
|
87
95
|
}
|
|
88
|
-
|
|
96
|
+
let timestamp: number | undefined;
|
|
97
|
+
const macs: Uint8Array<ArrayBuffer>[] = [];
|
|
89
98
|
for (const part of header.split(',')) {
|
|
90
99
|
const separator = part.indexOf('=');
|
|
91
|
-
if (separator
|
|
92
|
-
|
|
100
|
+
if (separator <= 0) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const name = part.slice(0, separator).trim();
|
|
104
|
+
const value = part.slice(separator + 1).trim();
|
|
105
|
+
if (name === 't') {
|
|
106
|
+
timestamp = Number(value);
|
|
107
|
+
} else if (name === 'v1') {
|
|
108
|
+
if (!MAC_HEX.test(value)) {
|
|
109
|
+
throw invalidSignature('The Sendora-Signature header is malformed.');
|
|
110
|
+
}
|
|
111
|
+
macs.push(bytesOf(value));
|
|
93
112
|
}
|
|
94
113
|
}
|
|
95
|
-
|
|
96
|
-
const hex = parts.get('v1');
|
|
97
|
-
if (!Number.isInteger(timestamp) || hex === undefined || !MAC_HEX.test(hex)) {
|
|
114
|
+
if (timestamp === undefined || !Number.isInteger(timestamp) || macs.length === 0) {
|
|
98
115
|
throw invalidSignature('The Sendora-Signature header is malformed.');
|
|
99
116
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
117
|
+
return { timestamp, macs };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function bytesOf(hex: string): Uint8Array<ArrayBuffer> {
|
|
121
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
122
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
123
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
103
124
|
}
|
|
104
|
-
return
|
|
125
|
+
return bytes;
|
|
105
126
|
}
|
|
106
127
|
|
|
107
128
|
function parseEvent(text: string): WebhookEvent {
|
package/src/webhooks.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { paginate } from './pagination.ts';
|
|
|
2
2
|
import type { Transport } from './transport.ts';
|
|
3
3
|
import type {
|
|
4
4
|
CreatedWebhook,
|
|
5
|
+
CreatedWebhookSecret,
|
|
5
6
|
CreateWebhookRequest,
|
|
6
7
|
Delivery,
|
|
7
8
|
DeliveryPage,
|
|
@@ -74,6 +75,34 @@ export class WebhooksResource {
|
|
|
74
75
|
});
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Adds a second live secret and answers its value once. Every delivery
|
|
80
|
+
* then carries one signature per live secret, the newest first, so
|
|
81
|
+
* switch your receiver to the new secret and delete the old one; a third
|
|
82
|
+
* is refused with `secret_limit`.
|
|
83
|
+
*
|
|
84
|
+
*
|
|
85
|
+
* const { secret, secretId } = await sendora.webhooks.createSecret(webhookId);
|
|
86
|
+
*/
|
|
87
|
+
createSecret(webhookId: string, options: RequestOptions = {}): Promise<CreatedWebhookSecret> {
|
|
88
|
+
return this.#transport.request<CreatedWebhookSecret>({
|
|
89
|
+
method: 'POST',
|
|
90
|
+
path: `/v1/webhooks/${encodeURIComponent(webhookId)}/secrets`,
|
|
91
|
+
idempotent: false,
|
|
92
|
+
signal: options.signal,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Deletes a secret; deliveries are no longer signed with it. The last live secret is refused (`last_secret`). */
|
|
97
|
+
deleteSecret(webhookId: string, secretId: string, options: RequestOptions = {}): Promise<void> {
|
|
98
|
+
return this.#transport.request<undefined>({
|
|
99
|
+
method: 'DELETE',
|
|
100
|
+
path: `/v1/webhooks/${encodeURIComponent(webhookId)}/secrets/${encodeURIComponent(secretId)}`,
|
|
101
|
+
idempotent: true,
|
|
102
|
+
signal: options.signal,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
77
106
|
/**
|
|
78
107
|
* One page of the events handed to the webhook, newest first, with the
|
|
79
108
|
* outcome of the last attempt; `status` narrows to `pending`,
|