@marktiderman/genesis-forms 0.8.0 → 0.9.1
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 +299 -10
- package/dist/destinations.cjs +331 -114
- package/dist/destinations.cjs.map +1 -1
- package/dist/destinations.d.cts +67 -45
- package/dist/destinations.d.ts +67 -45
- package/dist/destinations.js +327 -111
- package/dist/destinations.js.map +1 -1
- package/dist/{engine-Bj23YJlB.d.cts → engine-BaHPC2-1.d.cts} +2 -2
- package/dist/{engine-CzinTJph.d.ts → engine-Da99Tv-E.d.ts} +2 -2
- package/dist/index.cjs +996 -167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +288 -11
- package/dist/index.d.ts +288 -11
- package/dist/index.js +975 -168
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +563 -173
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +3 -474
- package/dist/server.d.ts +3 -474
- package/dist/server.js +558 -174
- package/dist/server.js.map +1 -1
- package/dist/submit-protocol-CFi-0Qd0.d.ts +840 -0
- package/dist/submit-protocol-D0cOckmK.d.cts +840 -0
- package/dist/testing.cjs +250 -154
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -4
- package/dist/testing.d.ts +4 -4
- package/dist/testing.js +250 -154
- package/dist/testing.js.map +1 -1
- package/dist/{types-jqDKcmP4.d.cts → types-C0pUfew3.d.cts} +7 -1
- package/dist/{types-jqDKcmP4.d.ts → types-C0pUfew3.d.ts} +7 -1
- package/dist/{validate-DvfQHYnu.d.ts → validate-DpmBssFk.d.ts} +258 -140
- package/dist/{validate-irIPubxc.d.cts → validate-U5LoW3eR.d.cts} +258 -140
- package/package.json +3 -2
- package/dist/upload-protocol-BOe018kL.d.cts +0 -122
- package/dist/upload-protocol-BUO74WkS.d.ts +0 -122
package/dist/destinations.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J as Json, F as FormDefinition, a as FieldBlock, C as Condition } from './types-
|
|
1
|
+
import { J as Json, F as FormDefinition, a as FieldBlock, C as Condition } from './types-C0pUfew3.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The contract every destination keeps. A destination sends one checked
|
|
@@ -103,6 +103,12 @@ interface DeliveryFailure {
|
|
|
103
103
|
retryAfterSeconds?: number;
|
|
104
104
|
/** The HTTP status that refused it, if one did. */
|
|
105
105
|
status?: number;
|
|
106
|
+
/**
|
|
107
|
+
* The receiver asked to be switched off (a webhook answered 410 Gone, as
|
|
108
|
+
* Standard Webhooks specifies): disable the destination rather than keep
|
|
109
|
+
* sending to it. Always with `retryable: false`.
|
|
110
|
+
*/
|
|
111
|
+
disable?: true;
|
|
106
112
|
/** Safe to store and log: a status and a short reason, never secrets, answers or contact details. */
|
|
107
113
|
error: string;
|
|
108
114
|
}
|
|
@@ -129,10 +135,13 @@ declare class DeliveryError extends Error {
|
|
|
129
135
|
readonly retryable: boolean;
|
|
130
136
|
readonly retryAfterSeconds: number | undefined;
|
|
131
137
|
readonly status: number | undefined;
|
|
138
|
+
/** The receiver asked to be switched off (`DeliveryFailure.disable`); never retryable. */
|
|
139
|
+
readonly disable: boolean;
|
|
132
140
|
constructor(message: string, options?: {
|
|
133
141
|
retryable?: boolean | undefined;
|
|
134
142
|
retryAfterSeconds?: number | undefined;
|
|
135
143
|
status?: number | undefined;
|
|
144
|
+
disable?: boolean | undefined;
|
|
136
145
|
});
|
|
137
146
|
}
|
|
138
147
|
/** Every outbound request gives up after this long, unless the destination is given another `timeoutMs`. */
|
|
@@ -467,15 +476,17 @@ interface WebhookConfig {
|
|
|
467
476
|
}
|
|
468
477
|
interface WebhookDestinationOptions extends HttpDeps {
|
|
469
478
|
/**
|
|
470
|
-
* The signing secret: base64 of at least
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
479
|
+
* The signing secret: base64 of at least 24 random bytes (the spec
|
|
480
|
+
* recommends 24 to 64), usually with the `whsec_` prefix Standard Webhooks
|
|
481
|
+
* tools issue. The prefix is optional; the rest is always base64-decoded,
|
|
482
|
+
* as every Standard Webhooks library does, so a receiver verifies with the
|
|
483
|
+
* same string. A secret that is not base64, or is shorter, fails
|
|
484
|
+
* permanently. Several secrets (new and old, during a rotation) sign with
|
|
485
|
+
* each, space-separated in `webhook-signature`, so the receiver verifies
|
|
486
|
+
* with either. Or a function that finds them for a destination's config.
|
|
487
|
+
* Never put it in config.
|
|
477
488
|
*/
|
|
478
|
-
secret: string | OptionResolver<string>;
|
|
489
|
+
secret: string | readonly string[] | OptionResolver<string | readonly string[]>;
|
|
479
490
|
/** Allow `http:` URLs. Default false. */
|
|
480
491
|
allowInsecureUrls?: boolean | undefined;
|
|
481
492
|
/** Allow localhost and private, loopback and link-local address literals. Default false. */
|
|
@@ -502,7 +513,10 @@ interface WebhookDestinationOptions extends HttpDeps {
|
|
|
502
513
|
/** The JSON body a webhook receives. */
|
|
503
514
|
interface WebhookPayload {
|
|
504
515
|
type: string;
|
|
505
|
-
/**
|
|
516
|
+
/**
|
|
517
|
+
* ISO time the event happened: the submission's `submittedAt`, or the send
|
|
518
|
+
* time when it has none. The `webhook-timestamp` header is the send time.
|
|
519
|
+
*/
|
|
506
520
|
timestamp: string;
|
|
507
521
|
data: {
|
|
508
522
|
form: {
|
|
@@ -524,17 +538,26 @@ interface WebhookPayload {
|
|
|
524
538
|
row: Record<string, Json>;
|
|
525
539
|
};
|
|
526
540
|
}
|
|
541
|
+
/** The shortest signing secret, decoded: Standard Webhooks recommends 24 to 64 bytes. */
|
|
542
|
+
declare const MIN_WEBHOOK_SECRET_BYTES = 24;
|
|
527
543
|
/**
|
|
528
544
|
* A new signing secret: `whsec_` and standard base64 of 32 random bytes, the
|
|
529
545
|
* form Standard Webhooks libraries read. Show it to the receiver once; keep it
|
|
530
546
|
* out of config.
|
|
531
547
|
*/
|
|
532
548
|
declare function newWebhookSecret(): string;
|
|
533
|
-
/**
|
|
534
|
-
|
|
549
|
+
/**
|
|
550
|
+
* The `webhook-signature` value for a message: `v1,<base64>`, or one such
|
|
551
|
+
* signature per secret, space-separated, when given several (a rotation).
|
|
552
|
+
*/
|
|
553
|
+
declare function signWebhook(secret: string | readonly string[], id: string, timestamp: number, body: string): Promise<string>;
|
|
535
554
|
interface VerifyWebhookInput {
|
|
536
|
-
/**
|
|
537
|
-
|
|
555
|
+
/**
|
|
556
|
+
* The same secret the sender signs with (base64, optionally
|
|
557
|
+
* `whsec_`-prefixed), or several (new and old, during a rotation): any one
|
|
558
|
+
* matching signature passes.
|
|
559
|
+
*/
|
|
560
|
+
secret: string | readonly string[];
|
|
538
561
|
/** The request's headers: a `Headers` or a plain object. */
|
|
539
562
|
headers: Headers | Record<string, string | string[] | undefined>;
|
|
540
563
|
/** The raw body, exactly as received. */
|
|
@@ -682,12 +705,25 @@ declare function googleOAuthAccessToken(client: GoogleOAuthClient, refreshToken:
|
|
|
682
705
|
* problem, never the key.
|
|
683
706
|
*/
|
|
684
707
|
declare function secretKeyBytes(key: string | Uint8Array): Uint8Array<ArrayBuffer>;
|
|
708
|
+
/** Options for `deriveSecretKey`. */
|
|
709
|
+
interface DeriveSecretKeyOptions {
|
|
710
|
+
/**
|
|
711
|
+
* The HKDF salt: bytes, or text taken as its UTF-8 bytes. Default empty,
|
|
712
|
+
* which is what every key derived before this option existed used, so
|
|
713
|
+
* leave it out to open those. For new keys a fixed, app-wide random value
|
|
714
|
+
* (say 32 bytes from `openssl rand -base64 32`, kept as config) is
|
|
715
|
+
* recommended (RFC 5869). It need not be secret, but must never change
|
|
716
|
+
* once anything is sealed with it.
|
|
717
|
+
*/
|
|
718
|
+
salt?: string | Uint8Array | undefined;
|
|
719
|
+
}
|
|
685
720
|
/**
|
|
686
721
|
* An AES-GCM key for one purpose, derived from the app secret with HKDF-SHA-256
|
|
687
|
-
* (
|
|
688
|
-
* kind of secret; keep it
|
|
722
|
+
* (`info` naming the purpose; the salt empty unless `options.salt` is given).
|
|
723
|
+
* Use a different `info` for each kind of secret; keep it, and the salt,
|
|
724
|
+
* fixed once anything is sealed with them.
|
|
689
725
|
*/
|
|
690
|
-
declare function deriveSecretKey(key: string | Uint8Array, info: string): Promise<WebCryptoKey>;
|
|
726
|
+
declare function deriveSecretKey(key: string | Uint8Array, info: string, options?: DeriveSecretKeyOptions): Promise<WebCryptoKey>;
|
|
691
727
|
/** Encrypts `plaintext` bound to `aad` (the row it belongs to): `v1.<iv>.<ciphertext>`. */
|
|
692
728
|
declare function sealSecret(key: WebCryptoKey, plaintext: string, aad: string): Promise<string>;
|
|
693
729
|
/**
|
|
@@ -697,28 +733,6 @@ declare function sealSecret(key: WebCryptoKey, plaintext: string, aad: string):
|
|
|
697
733
|
*/
|
|
698
734
|
declare function openSecret(key: WebCryptoKey, sealed: string, aad: string): Promise<string>;
|
|
699
735
|
|
|
700
|
-
/**
|
|
701
|
-
* The outbox runner: claim a batch of due deliveries, send each to its
|
|
702
|
-
* destination, and record what happened. The store is the app's (a SQL
|
|
703
|
-
* outbox, a queue, a KV list): it hands over claimed deliveries and takes
|
|
704
|
-
* back outcomes, and decides how claims and leases work. The runner owns the
|
|
705
|
-
* rest: the destination's condition (`config.when`), batching deliveries to
|
|
706
|
-
* one destination into one request where the destination can, keeping its
|
|
707
|
-
* state, and turning each result into an outcome with a retry time.
|
|
708
|
-
*
|
|
709
|
-
* Outcomes:
|
|
710
|
-
* - `sent`: delivered (or already there, on a redelivery).
|
|
711
|
-
* - `filtered`: the submission doesn't match the destination's condition; nothing was sent, nothing to retry.
|
|
712
|
-
* - `skipped`: the destination deliberately sent nothing (`notSent`); never retried.
|
|
713
|
-
* - `retry`: a retryable failure. With the service's own Retry-After it is
|
|
714
|
-
* deferred without counting an attempt (`counted: false`); otherwise it backs
|
|
715
|
-
* off by attempt (`counted: true`), until `maxAttempts`.
|
|
716
|
-
* - `failed`: permanent, an unknown kind, or out of attempts.
|
|
717
|
-
*
|
|
718
|
-
* It never throws for a delivery's failure, and never logs answers, contact
|
|
719
|
-
* details or secrets: only ids, kinds and the destinations' safe messages.
|
|
720
|
-
*/
|
|
721
|
-
|
|
722
736
|
/** One claimed delivery, as the app's store hands it over. */
|
|
723
737
|
interface ClaimedDelivery {
|
|
724
738
|
/** The delivery's id: stable across its retries (the email idempotency key, the webhook-id). */
|
|
@@ -772,6 +786,8 @@ type DeliveryOutcome = {
|
|
|
772
786
|
status: "failed";
|
|
773
787
|
error: string;
|
|
774
788
|
httpStatus?: number;
|
|
789
|
+
/** The receiver asked to be switched off (a webhook's 410 Gone): disable the destination. */
|
|
790
|
+
disable?: true;
|
|
775
791
|
};
|
|
776
792
|
interface ClaimRequest<Filter> {
|
|
777
793
|
/** Most deliveries to claim. */
|
|
@@ -834,11 +850,17 @@ interface DeliveryRunner<Filter = undefined> {
|
|
|
834
850
|
/** One claim, its sends and their records. Never rejects for a delivery's failure; a failing `claim` rejects. */
|
|
835
851
|
run(options?: RunOptions<Filter>): Promise<DeliveryReport>;
|
|
836
852
|
}
|
|
837
|
-
declare const DEFAULT_MAX_ATTEMPTS
|
|
838
|
-
declare const DEFAULT_MAX_DEFERRALS
|
|
839
|
-
declare const DEFAULT_BATCH_SIZE
|
|
840
|
-
/**
|
|
841
|
-
|
|
853
|
+
declare const DEFAULT_MAX_ATTEMPTS: number;
|
|
854
|
+
declare const DEFAULT_MAX_DEFERRALS: number;
|
|
855
|
+
declare const DEFAULT_BATCH_SIZE: number;
|
|
856
|
+
/**
|
|
857
|
+
* 5 minutes, quadrupling each attempt, at most 24 hours: 5m, 20m, 80m, 5h20m,
|
|
858
|
+
* 21h20m, then 24h. Across the default 8 attempts that is about 3 days, as
|
|
859
|
+
* Standard Webhooks suggests. Each wait is jittered by up to ±20%, so
|
|
860
|
+
* deliveries that failed together (a receiver's outage) don't all come back
|
|
861
|
+
* at once. `random` (default `Math.random`) is for tests.
|
|
862
|
+
*/
|
|
863
|
+
declare const defaultBackoff: (attempt: number, random?: () => number) => number;
|
|
842
864
|
/** Turns a destination's result into an outcome for a delivery on its `attempt`. */
|
|
843
865
|
declare function deliveryOutcome(result: DeliveryResult, attempt: number, options?: {
|
|
844
866
|
now?: number | undefined;
|
|
@@ -850,4 +872,4 @@ declare function deliveryOutcome(result: DeliveryResult, attempt: number, option
|
|
|
850
872
|
}): DeliveryOutcome;
|
|
851
873
|
declare function createDeliveryRunner<Filter = undefined>(options: DeliveryRunnerOptions<Filter>): DeliveryRunner<Filter>;
|
|
852
874
|
|
|
853
|
-
export { type Cell, type ClaimRequest, type ClaimedDelivery, DEDUPE_WINDOW, DEFAULT_BATCH_SIZE, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_DEFERRALS, DEFAULT_SHEET_NAME, DRIVE_FILE_SCOPE, DeliveryError, type DeliveryFailure, type DeliveryItem, type DeliveryOptions, type DeliveryOutcome, type DeliveryReport, type DeliveryResult, type DeliveryRunner, type DeliveryRunnerOptions, type DeliverySubmission, type Destination, type DestinationConfig, type EmailConfig, type EmailContent, type EmailDestinationOptions, type EmailMessage, type EmailProvider, type EmailRenderInput, GOOGLE_TOKEN_URL, type GoogleOAuthClient, type GoogleOAuthTokenOptions, type GoogleServiceAccount, type GoogleTokenOptions, HEADER_SCAN_ROWS, type HookKind, HookUrlError, type HttpDeps, MAX_CONDITION_DEPTH, MAX_HOOK_URL_LENGTH, MAX_RECIPIENTS, type OptionResolver, REQUEST_TIMEOUT_MS, RESEND_API, type RefreshedGoogleToken, type ResendOptions, type ResolveContext, type ResolveHost, type ResponseRow, type RowOptions, type RunOptions, SENSITIVE_MASK, SHEETS_API, SHEETS_SCOPE, SLACK_HOSTS, SLACK_VALUE_LIMIT, type SheetConfig, type SheetState, type SheetsDestinationOptions, type SlackDestinationOptions, type SlackMessageInput, type SlackMessageOptions, type VerifyWebhookInput, type WebCryptoKey, type WebhookConfig, type WebhookDestinationOptions, type WebhookPayload, answerCell, checkHookHost, checkWebhookUrl, clearGoogleOAuthTokenCache, clearGoogleTokenCache, columnLetter, conditionOf, createDeliveryRunner, defaultBackoff, deliveryFailure, deliveryOutcome, deriveSecretKey, emailBody, emailDestination, escapeFormula, escapeHtml, escapeSlack, googleAccessToken, googleOAuthAccessToken, headerSafe, hookHost, httpError, idempotencyKey, isCondition, isPrivateHost, isPublicAddress, isRetryableStatus, isSafeAddress, isSafeFrom, mergeHeader, newWebhookSecret, openSecret, parseHookUrl, passesCondition, refreshGoogleAccessToken, renderEmail, resendProvider, responseRow, retryAfterSeconds, rowFor, sealSecret, secretKeyBytes, sheetsDestination, signJwt, signWebhook, slackDestination, slackMessage, verifyWebhook, visibleInputs, webhookDestination, webhookPayload };
|
|
875
|
+
export { type Cell, type ClaimRequest, type ClaimedDelivery, DEDUPE_WINDOW, DEFAULT_BATCH_SIZE, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_DEFERRALS, DEFAULT_SHEET_NAME, DRIVE_FILE_SCOPE, DeliveryError, type DeliveryFailure, type DeliveryItem, type DeliveryOptions, type DeliveryOutcome, type DeliveryReport, type DeliveryResult, type DeliveryRunner, type DeliveryRunnerOptions, type DeliverySubmission, type DeriveSecretKeyOptions, type Destination, type DestinationConfig, type EmailConfig, type EmailContent, type EmailDestinationOptions, type EmailMessage, type EmailProvider, type EmailRenderInput, GOOGLE_TOKEN_URL, type GoogleOAuthClient, type GoogleOAuthTokenOptions, type GoogleServiceAccount, type GoogleTokenOptions, HEADER_SCAN_ROWS, type HookKind, HookUrlError, type HttpDeps, MAX_CONDITION_DEPTH, MAX_HOOK_URL_LENGTH, MAX_RECIPIENTS, MIN_WEBHOOK_SECRET_BYTES, type OptionResolver, REQUEST_TIMEOUT_MS, RESEND_API, type RefreshedGoogleToken, type ResendOptions, type ResolveContext, type ResolveHost, type ResponseRow, type RowOptions, type RunOptions, SENSITIVE_MASK, SHEETS_API, SHEETS_SCOPE, SLACK_HOSTS, SLACK_VALUE_LIMIT, type SheetConfig, type SheetState, type SheetsDestinationOptions, type SlackDestinationOptions, type SlackMessageInput, type SlackMessageOptions, type VerifyWebhookInput, type WebCryptoKey, type WebhookConfig, type WebhookDestinationOptions, type WebhookPayload, answerCell, checkHookHost, checkWebhookUrl, clearGoogleOAuthTokenCache, clearGoogleTokenCache, columnLetter, conditionOf, createDeliveryRunner, defaultBackoff, deliveryFailure, deliveryOutcome, deriveSecretKey, emailBody, emailDestination, escapeFormula, escapeHtml, escapeSlack, googleAccessToken, googleOAuthAccessToken, headerSafe, hookHost, httpError, idempotencyKey, isCondition, isPrivateHost, isPublicAddress, isRetryableStatus, isSafeAddress, isSafeFrom, mergeHeader, newWebhookSecret, openSecret, parseHookUrl, passesCondition, refreshGoogleAccessToken, renderEmail, resendProvider, responseRow, retryAfterSeconds, rowFor, sealSecret, secretKeyBytes, sheetsDestination, signJwt, signWebhook, slackDestination, slackMessage, verifyWebhook, visibleInputs, webhookDestination, webhookPayload };
|
package/dist/destinations.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J as Json, F as FormDefinition, a as FieldBlock, C as Condition } from './types-
|
|
1
|
+
import { J as Json, F as FormDefinition, a as FieldBlock, C as Condition } from './types-C0pUfew3.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The contract every destination keeps. A destination sends one checked
|
|
@@ -103,6 +103,12 @@ interface DeliveryFailure {
|
|
|
103
103
|
retryAfterSeconds?: number;
|
|
104
104
|
/** The HTTP status that refused it, if one did. */
|
|
105
105
|
status?: number;
|
|
106
|
+
/**
|
|
107
|
+
* The receiver asked to be switched off (a webhook answered 410 Gone, as
|
|
108
|
+
* Standard Webhooks specifies): disable the destination rather than keep
|
|
109
|
+
* sending to it. Always with `retryable: false`.
|
|
110
|
+
*/
|
|
111
|
+
disable?: true;
|
|
106
112
|
/** Safe to store and log: a status and a short reason, never secrets, answers or contact details. */
|
|
107
113
|
error: string;
|
|
108
114
|
}
|
|
@@ -129,10 +135,13 @@ declare class DeliveryError extends Error {
|
|
|
129
135
|
readonly retryable: boolean;
|
|
130
136
|
readonly retryAfterSeconds: number | undefined;
|
|
131
137
|
readonly status: number | undefined;
|
|
138
|
+
/** The receiver asked to be switched off (`DeliveryFailure.disable`); never retryable. */
|
|
139
|
+
readonly disable: boolean;
|
|
132
140
|
constructor(message: string, options?: {
|
|
133
141
|
retryable?: boolean | undefined;
|
|
134
142
|
retryAfterSeconds?: number | undefined;
|
|
135
143
|
status?: number | undefined;
|
|
144
|
+
disable?: boolean | undefined;
|
|
136
145
|
});
|
|
137
146
|
}
|
|
138
147
|
/** Every outbound request gives up after this long, unless the destination is given another `timeoutMs`. */
|
|
@@ -467,15 +476,17 @@ interface WebhookConfig {
|
|
|
467
476
|
}
|
|
468
477
|
interface WebhookDestinationOptions extends HttpDeps {
|
|
469
478
|
/**
|
|
470
|
-
* The signing secret: base64 of at least
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
479
|
+
* The signing secret: base64 of at least 24 random bytes (the spec
|
|
480
|
+
* recommends 24 to 64), usually with the `whsec_` prefix Standard Webhooks
|
|
481
|
+
* tools issue. The prefix is optional; the rest is always base64-decoded,
|
|
482
|
+
* as every Standard Webhooks library does, so a receiver verifies with the
|
|
483
|
+
* same string. A secret that is not base64, or is shorter, fails
|
|
484
|
+
* permanently. Several secrets (new and old, during a rotation) sign with
|
|
485
|
+
* each, space-separated in `webhook-signature`, so the receiver verifies
|
|
486
|
+
* with either. Or a function that finds them for a destination's config.
|
|
487
|
+
* Never put it in config.
|
|
477
488
|
*/
|
|
478
|
-
secret: string | OptionResolver<string>;
|
|
489
|
+
secret: string | readonly string[] | OptionResolver<string | readonly string[]>;
|
|
479
490
|
/** Allow `http:` URLs. Default false. */
|
|
480
491
|
allowInsecureUrls?: boolean | undefined;
|
|
481
492
|
/** Allow localhost and private, loopback and link-local address literals. Default false. */
|
|
@@ -502,7 +513,10 @@ interface WebhookDestinationOptions extends HttpDeps {
|
|
|
502
513
|
/** The JSON body a webhook receives. */
|
|
503
514
|
interface WebhookPayload {
|
|
504
515
|
type: string;
|
|
505
|
-
/**
|
|
516
|
+
/**
|
|
517
|
+
* ISO time the event happened: the submission's `submittedAt`, or the send
|
|
518
|
+
* time when it has none. The `webhook-timestamp` header is the send time.
|
|
519
|
+
*/
|
|
506
520
|
timestamp: string;
|
|
507
521
|
data: {
|
|
508
522
|
form: {
|
|
@@ -524,17 +538,26 @@ interface WebhookPayload {
|
|
|
524
538
|
row: Record<string, Json>;
|
|
525
539
|
};
|
|
526
540
|
}
|
|
541
|
+
/** The shortest signing secret, decoded: Standard Webhooks recommends 24 to 64 bytes. */
|
|
542
|
+
declare const MIN_WEBHOOK_SECRET_BYTES = 24;
|
|
527
543
|
/**
|
|
528
544
|
* A new signing secret: `whsec_` and standard base64 of 32 random bytes, the
|
|
529
545
|
* form Standard Webhooks libraries read. Show it to the receiver once; keep it
|
|
530
546
|
* out of config.
|
|
531
547
|
*/
|
|
532
548
|
declare function newWebhookSecret(): string;
|
|
533
|
-
/**
|
|
534
|
-
|
|
549
|
+
/**
|
|
550
|
+
* The `webhook-signature` value for a message: `v1,<base64>`, or one such
|
|
551
|
+
* signature per secret, space-separated, when given several (a rotation).
|
|
552
|
+
*/
|
|
553
|
+
declare function signWebhook(secret: string | readonly string[], id: string, timestamp: number, body: string): Promise<string>;
|
|
535
554
|
interface VerifyWebhookInput {
|
|
536
|
-
/**
|
|
537
|
-
|
|
555
|
+
/**
|
|
556
|
+
* The same secret the sender signs with (base64, optionally
|
|
557
|
+
* `whsec_`-prefixed), or several (new and old, during a rotation): any one
|
|
558
|
+
* matching signature passes.
|
|
559
|
+
*/
|
|
560
|
+
secret: string | readonly string[];
|
|
538
561
|
/** The request's headers: a `Headers` or a plain object. */
|
|
539
562
|
headers: Headers | Record<string, string | string[] | undefined>;
|
|
540
563
|
/** The raw body, exactly as received. */
|
|
@@ -682,12 +705,25 @@ declare function googleOAuthAccessToken(client: GoogleOAuthClient, refreshToken:
|
|
|
682
705
|
* problem, never the key.
|
|
683
706
|
*/
|
|
684
707
|
declare function secretKeyBytes(key: string | Uint8Array): Uint8Array<ArrayBuffer>;
|
|
708
|
+
/** Options for `deriveSecretKey`. */
|
|
709
|
+
interface DeriveSecretKeyOptions {
|
|
710
|
+
/**
|
|
711
|
+
* The HKDF salt: bytes, or text taken as its UTF-8 bytes. Default empty,
|
|
712
|
+
* which is what every key derived before this option existed used, so
|
|
713
|
+
* leave it out to open those. For new keys a fixed, app-wide random value
|
|
714
|
+
* (say 32 bytes from `openssl rand -base64 32`, kept as config) is
|
|
715
|
+
* recommended (RFC 5869). It need not be secret, but must never change
|
|
716
|
+
* once anything is sealed with it.
|
|
717
|
+
*/
|
|
718
|
+
salt?: string | Uint8Array | undefined;
|
|
719
|
+
}
|
|
685
720
|
/**
|
|
686
721
|
* An AES-GCM key for one purpose, derived from the app secret with HKDF-SHA-256
|
|
687
|
-
* (
|
|
688
|
-
* kind of secret; keep it
|
|
722
|
+
* (`info` naming the purpose; the salt empty unless `options.salt` is given).
|
|
723
|
+
* Use a different `info` for each kind of secret; keep it, and the salt,
|
|
724
|
+
* fixed once anything is sealed with them.
|
|
689
725
|
*/
|
|
690
|
-
declare function deriveSecretKey(key: string | Uint8Array, info: string): Promise<WebCryptoKey>;
|
|
726
|
+
declare function deriveSecretKey(key: string | Uint8Array, info: string, options?: DeriveSecretKeyOptions): Promise<WebCryptoKey>;
|
|
691
727
|
/** Encrypts `plaintext` bound to `aad` (the row it belongs to): `v1.<iv>.<ciphertext>`. */
|
|
692
728
|
declare function sealSecret(key: WebCryptoKey, plaintext: string, aad: string): Promise<string>;
|
|
693
729
|
/**
|
|
@@ -697,28 +733,6 @@ declare function sealSecret(key: WebCryptoKey, plaintext: string, aad: string):
|
|
|
697
733
|
*/
|
|
698
734
|
declare function openSecret(key: WebCryptoKey, sealed: string, aad: string): Promise<string>;
|
|
699
735
|
|
|
700
|
-
/**
|
|
701
|
-
* The outbox runner: claim a batch of due deliveries, send each to its
|
|
702
|
-
* destination, and record what happened. The store is the app's (a SQL
|
|
703
|
-
* outbox, a queue, a KV list): it hands over claimed deliveries and takes
|
|
704
|
-
* back outcomes, and decides how claims and leases work. The runner owns the
|
|
705
|
-
* rest: the destination's condition (`config.when`), batching deliveries to
|
|
706
|
-
* one destination into one request where the destination can, keeping its
|
|
707
|
-
* state, and turning each result into an outcome with a retry time.
|
|
708
|
-
*
|
|
709
|
-
* Outcomes:
|
|
710
|
-
* - `sent`: delivered (or already there, on a redelivery).
|
|
711
|
-
* - `filtered`: the submission doesn't match the destination's condition; nothing was sent, nothing to retry.
|
|
712
|
-
* - `skipped`: the destination deliberately sent nothing (`notSent`); never retried.
|
|
713
|
-
* - `retry`: a retryable failure. With the service's own Retry-After it is
|
|
714
|
-
* deferred without counting an attempt (`counted: false`); otherwise it backs
|
|
715
|
-
* off by attempt (`counted: true`), until `maxAttempts`.
|
|
716
|
-
* - `failed`: permanent, an unknown kind, or out of attempts.
|
|
717
|
-
*
|
|
718
|
-
* It never throws for a delivery's failure, and never logs answers, contact
|
|
719
|
-
* details or secrets: only ids, kinds and the destinations' safe messages.
|
|
720
|
-
*/
|
|
721
|
-
|
|
722
736
|
/** One claimed delivery, as the app's store hands it over. */
|
|
723
737
|
interface ClaimedDelivery {
|
|
724
738
|
/** The delivery's id: stable across its retries (the email idempotency key, the webhook-id). */
|
|
@@ -772,6 +786,8 @@ type DeliveryOutcome = {
|
|
|
772
786
|
status: "failed";
|
|
773
787
|
error: string;
|
|
774
788
|
httpStatus?: number;
|
|
789
|
+
/** The receiver asked to be switched off (a webhook's 410 Gone): disable the destination. */
|
|
790
|
+
disable?: true;
|
|
775
791
|
};
|
|
776
792
|
interface ClaimRequest<Filter> {
|
|
777
793
|
/** Most deliveries to claim. */
|
|
@@ -834,11 +850,17 @@ interface DeliveryRunner<Filter = undefined> {
|
|
|
834
850
|
/** One claim, its sends and their records. Never rejects for a delivery's failure; a failing `claim` rejects. */
|
|
835
851
|
run(options?: RunOptions<Filter>): Promise<DeliveryReport>;
|
|
836
852
|
}
|
|
837
|
-
declare const DEFAULT_MAX_ATTEMPTS
|
|
838
|
-
declare const DEFAULT_MAX_DEFERRALS
|
|
839
|
-
declare const DEFAULT_BATCH_SIZE
|
|
840
|
-
/**
|
|
841
|
-
|
|
853
|
+
declare const DEFAULT_MAX_ATTEMPTS: number;
|
|
854
|
+
declare const DEFAULT_MAX_DEFERRALS: number;
|
|
855
|
+
declare const DEFAULT_BATCH_SIZE: number;
|
|
856
|
+
/**
|
|
857
|
+
* 5 minutes, quadrupling each attempt, at most 24 hours: 5m, 20m, 80m, 5h20m,
|
|
858
|
+
* 21h20m, then 24h. Across the default 8 attempts that is about 3 days, as
|
|
859
|
+
* Standard Webhooks suggests. Each wait is jittered by up to ±20%, so
|
|
860
|
+
* deliveries that failed together (a receiver's outage) don't all come back
|
|
861
|
+
* at once. `random` (default `Math.random`) is for tests.
|
|
862
|
+
*/
|
|
863
|
+
declare const defaultBackoff: (attempt: number, random?: () => number) => number;
|
|
842
864
|
/** Turns a destination's result into an outcome for a delivery on its `attempt`. */
|
|
843
865
|
declare function deliveryOutcome(result: DeliveryResult, attempt: number, options?: {
|
|
844
866
|
now?: number | undefined;
|
|
@@ -850,4 +872,4 @@ declare function deliveryOutcome(result: DeliveryResult, attempt: number, option
|
|
|
850
872
|
}): DeliveryOutcome;
|
|
851
873
|
declare function createDeliveryRunner<Filter = undefined>(options: DeliveryRunnerOptions<Filter>): DeliveryRunner<Filter>;
|
|
852
874
|
|
|
853
|
-
export { type Cell, type ClaimRequest, type ClaimedDelivery, DEDUPE_WINDOW, DEFAULT_BATCH_SIZE, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_DEFERRALS, DEFAULT_SHEET_NAME, DRIVE_FILE_SCOPE, DeliveryError, type DeliveryFailure, type DeliveryItem, type DeliveryOptions, type DeliveryOutcome, type DeliveryReport, type DeliveryResult, type DeliveryRunner, type DeliveryRunnerOptions, type DeliverySubmission, type Destination, type DestinationConfig, type EmailConfig, type EmailContent, type EmailDestinationOptions, type EmailMessage, type EmailProvider, type EmailRenderInput, GOOGLE_TOKEN_URL, type GoogleOAuthClient, type GoogleOAuthTokenOptions, type GoogleServiceAccount, type GoogleTokenOptions, HEADER_SCAN_ROWS, type HookKind, HookUrlError, type HttpDeps, MAX_CONDITION_DEPTH, MAX_HOOK_URL_LENGTH, MAX_RECIPIENTS, type OptionResolver, REQUEST_TIMEOUT_MS, RESEND_API, type RefreshedGoogleToken, type ResendOptions, type ResolveContext, type ResolveHost, type ResponseRow, type RowOptions, type RunOptions, SENSITIVE_MASK, SHEETS_API, SHEETS_SCOPE, SLACK_HOSTS, SLACK_VALUE_LIMIT, type SheetConfig, type SheetState, type SheetsDestinationOptions, type SlackDestinationOptions, type SlackMessageInput, type SlackMessageOptions, type VerifyWebhookInput, type WebCryptoKey, type WebhookConfig, type WebhookDestinationOptions, type WebhookPayload, answerCell, checkHookHost, checkWebhookUrl, clearGoogleOAuthTokenCache, clearGoogleTokenCache, columnLetter, conditionOf, createDeliveryRunner, defaultBackoff, deliveryFailure, deliveryOutcome, deriveSecretKey, emailBody, emailDestination, escapeFormula, escapeHtml, escapeSlack, googleAccessToken, googleOAuthAccessToken, headerSafe, hookHost, httpError, idempotencyKey, isCondition, isPrivateHost, isPublicAddress, isRetryableStatus, isSafeAddress, isSafeFrom, mergeHeader, newWebhookSecret, openSecret, parseHookUrl, passesCondition, refreshGoogleAccessToken, renderEmail, resendProvider, responseRow, retryAfterSeconds, rowFor, sealSecret, secretKeyBytes, sheetsDestination, signJwt, signWebhook, slackDestination, slackMessage, verifyWebhook, visibleInputs, webhookDestination, webhookPayload };
|
|
875
|
+
export { type Cell, type ClaimRequest, type ClaimedDelivery, DEDUPE_WINDOW, DEFAULT_BATCH_SIZE, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_DEFERRALS, DEFAULT_SHEET_NAME, DRIVE_FILE_SCOPE, DeliveryError, type DeliveryFailure, type DeliveryItem, type DeliveryOptions, type DeliveryOutcome, type DeliveryReport, type DeliveryResult, type DeliveryRunner, type DeliveryRunnerOptions, type DeliverySubmission, type DeriveSecretKeyOptions, type Destination, type DestinationConfig, type EmailConfig, type EmailContent, type EmailDestinationOptions, type EmailMessage, type EmailProvider, type EmailRenderInput, GOOGLE_TOKEN_URL, type GoogleOAuthClient, type GoogleOAuthTokenOptions, type GoogleServiceAccount, type GoogleTokenOptions, HEADER_SCAN_ROWS, type HookKind, HookUrlError, type HttpDeps, MAX_CONDITION_DEPTH, MAX_HOOK_URL_LENGTH, MAX_RECIPIENTS, MIN_WEBHOOK_SECRET_BYTES, type OptionResolver, REQUEST_TIMEOUT_MS, RESEND_API, type RefreshedGoogleToken, type ResendOptions, type ResolveContext, type ResolveHost, type ResponseRow, type RowOptions, type RunOptions, SENSITIVE_MASK, SHEETS_API, SHEETS_SCOPE, SLACK_HOSTS, SLACK_VALUE_LIMIT, type SheetConfig, type SheetState, type SheetsDestinationOptions, type SlackDestinationOptions, type SlackMessageInput, type SlackMessageOptions, type VerifyWebhookInput, type WebCryptoKey, type WebhookConfig, type WebhookDestinationOptions, type WebhookPayload, answerCell, checkHookHost, checkWebhookUrl, clearGoogleOAuthTokenCache, clearGoogleTokenCache, columnLetter, conditionOf, createDeliveryRunner, defaultBackoff, deliveryFailure, deliveryOutcome, deriveSecretKey, emailBody, emailDestination, escapeFormula, escapeHtml, escapeSlack, googleAccessToken, googleOAuthAccessToken, headerSafe, hookHost, httpError, idempotencyKey, isCondition, isPrivateHost, isPublicAddress, isRetryableStatus, isSafeAddress, isSafeFrom, mergeHeader, newWebhookSecret, openSecret, parseHookUrl, passesCondition, refreshGoogleAccessToken, renderEmail, resendProvider, responseRow, retryAfterSeconds, rowFor, sealSecret, secretKeyBytes, sheetsDestination, signJwt, signWebhook, slackDestination, slackMessage, verifyWebhook, visibleInputs, webhookDestination, webhookPayload };
|