@voltro/plugin-webhooks 0.22.1 → 0.24.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/CHANGELOG.md +427 -0
- package/dist/index.d.ts +177 -0
- package/dist/index.js +134 -134
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -666,6 +666,183 @@ export declare const verifySignature: (scheme: SignatureScheme, rawBody: Uint8Ar
|
|
|
666
666
|
*/
|
|
667
667
|
export declare type VersionState = 'current' | 'behind' | 'ahead';
|
|
668
668
|
|
|
669
|
+
/**
|
|
670
|
+
* One row per delivery attempt — NOT per emit. An emit fans out to
|
|
671
|
+
* N targets; each target then runs ≤ `maxAttempts` deliveries. The
|
|
672
|
+
* primary key is `(deliveryId, attempt)`; `deliveryId` is shared
|
|
673
|
+
* across retries of the SAME (event, payload, target) tuple so the
|
|
674
|
+
* dashboard groups them.
|
|
675
|
+
*
|
|
676
|
+
* Status lifecycle: `pending` (queued — the target was paused at emit
|
|
677
|
+
* time, or the attempt is rate-deferred to the next window) →
|
|
678
|
+
* `inFlight` → `succeeded` | `failed` | `retryScheduled`. On retry the
|
|
679
|
+
* workflow creates a new `(deliveryId, attempt+1)` row; on
|
|
680
|
+
* resume/deferral the SAME attempt-1 row transitions out of `pending`.
|
|
681
|
+
*/
|
|
682
|
+
export declare const _voltroWebhookDeliveriesTable: Table<"_voltro_webhook_deliveries", FieldDefinitions<{
|
|
683
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
684
|
+
/** Grouping key for retries of the same delivery. See above. */
|
|
685
|
+
readonly deliveryId: ColumnBuilder<string, "text", boolean>;
|
|
686
|
+
/** FK to `_voltro_webhook_targets.id`. */
|
|
687
|
+
readonly targetId: ColumnBuilder<string, "text", boolean>;
|
|
688
|
+
/** Event id at emit time — denormalised so dashboard listings
|
|
689
|
+
* don't need to JOIN through `_voltro_webhook_targets` (which
|
|
690
|
+
* may have been deleted by the time someone audits this row). */
|
|
691
|
+
readonly event: ColumnBuilder<string, "text", boolean>;
|
|
692
|
+
/** The emit's `eventId` (shared by every target fan-out of one
|
|
693
|
+
* emit) — lets `resumeTarget`'s flush re-trigger a queued delivery
|
|
694
|
+
* with its ORIGINAL event id, and correlates rows across targets. */
|
|
695
|
+
readonly eventId: ColumnBuilder<string | null, "text", boolean>;
|
|
696
|
+
/** Attempt counter (1-indexed). */
|
|
697
|
+
readonly attempt: ColumnBuilder<number, "integer", boolean>;
|
|
698
|
+
readonly status: ColumnBuilder<"failed" | "succeeded" | "pending" | "inFlight" | "retryScheduled", "text", boolean>;
|
|
699
|
+
/** Payload as sent over the wire. Stored verbatim — re-rendering
|
|
700
|
+
* from a referenced event row would lose the snapshot if the
|
|
701
|
+
* source event was deleted. */
|
|
702
|
+
readonly payload: ColumnBuilder<unknown, "json", boolean>;
|
|
703
|
+
/** HTTP status code returned. `null` for transport errors (DNS,
|
|
704
|
+
* TLS, timeout) — `errorMessage` carries the detail. */
|
|
705
|
+
readonly responseStatus: ColumnBuilder<number | null, "integer", boolean>;
|
|
706
|
+
/** Response body sample (clipped to 8 KB). Lets the dashboard
|
|
707
|
+
* show the recipient's error reply inline. */
|
|
708
|
+
readonly responseBody: ColumnBuilder<string | null, "text", boolean>;
|
|
709
|
+
/** Transport-layer error message ("ENOTFOUND", "ETIMEDOUT", TLS
|
|
710
|
+
* handshake failure). Null on HTTP-layer errors (those carry
|
|
711
|
+
* `responseStatus`). */
|
|
712
|
+
readonly errorMessage: ColumnBuilder<string | null, "text", boolean>;
|
|
713
|
+
/** End-to-end attempt latency in ms — includes DNS, TLS, request,
|
|
714
|
+
* response read. Useful for the dashboard's "slowest endpoint"
|
|
715
|
+
* ranking. */
|
|
716
|
+
readonly latencyMs: ColumnBuilder<number | null, "integer", boolean>;
|
|
717
|
+
/** When this attempt was scheduled (NOT when it was sent — sent
|
|
718
|
+
* time is approximately `scheduledAt + queueDelay`). */
|
|
719
|
+
readonly scheduledAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
720
|
+
/** When the next retry is due (set ONLY when `status =
|
|
721
|
+
* retryScheduled`). Lets the workflow's sleep block read its
|
|
722
|
+
* wake time from the persisted row across restarts. */
|
|
723
|
+
readonly nextAttemptAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
724
|
+
}> & {
|
|
725
|
+
tenantId: ColumnDefinition<string>;
|
|
726
|
+
} & {
|
|
727
|
+
readonly createdAt: ColumnDefinition<Date, "timestamp", true>;
|
|
728
|
+
readonly updatedAt: ColumnDefinition<Date, "timestamp", true>;
|
|
729
|
+
readonly createdBy: ColumnDefinition<string | null, "reference", boolean>;
|
|
730
|
+
readonly updatedBy: ColumnDefinition<string | null, "reference", boolean>;
|
|
731
|
+
}, true, never>;
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Fixed-window rate-limit counters — one row per (scope, minute
|
|
735
|
+
* bucket), where scope is `target:<targetId>` (per-target
|
|
736
|
+
* `rateLimitPerMinute`) or `event:<eventId>` (an outgoing event's
|
|
737
|
+
* `globalRateLimit`). The delivery workflow claims a slot via a CAS
|
|
738
|
+
* loop over `count` (see `rateLimit.ts`) BEFORE every wire POST, so
|
|
739
|
+
* the cap holds across replicas — the counter lives here, never in
|
|
740
|
+
* process memory.
|
|
741
|
+
*
|
|
742
|
+
* Deliberately NOT tenant-scoped: rows carry only a scope key + an
|
|
743
|
+
* integer count (no payload, no secret, no tenant data), and the
|
|
744
|
+
* background delivery workflow that writes them has no request
|
|
745
|
+
* subject. The deterministic PK `<scope>@<bucket>` is the
|
|
746
|
+
* `insertIgnore` conflict target for the first-in-window create race.
|
|
747
|
+
*/
|
|
748
|
+
export declare const _voltroWebhookRateWindowsTable: Table<"_voltro_webhook_rate_windows", FieldDefinitions<{
|
|
749
|
+
/** Deterministic `<scope>@<bucket>` — always supplied explicitly by
|
|
750
|
+
* the CAS writer (the prefix scheme only fires for omitted ids,
|
|
751
|
+
* which never happens here). */
|
|
752
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
753
|
+
/** `target:<targetId>` | `event:<eventId>`. */
|
|
754
|
+
readonly scope: ColumnBuilder<string, "text", boolean>;
|
|
755
|
+
/** Epoch-minute bucket (`floor(now / windowMs)`). */
|
|
756
|
+
readonly bucket: ColumnBuilder<number, "integer", boolean>;
|
|
757
|
+
/** Slots consumed in this window. */
|
|
758
|
+
readonly count: ColumnBuilder<number, "integer", true>;
|
|
759
|
+
readonly createdAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
760
|
+
readonly updatedAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
761
|
+
}>, true, never>;
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* One row per subscribed delivery target. Created via
|
|
765
|
+
* `webhooks.subscribe(...)`. Read-only from app code; mutate via
|
|
766
|
+
* the `webhooks` service so the framework can run validation +
|
|
767
|
+
* generate secrets + invalidate caches.
|
|
768
|
+
*/
|
|
769
|
+
export declare const _voltroWebhookTargetsTable: Table<"_voltro_webhook_targets", FieldDefinitions<{
|
|
770
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
771
|
+
/** Event id from the outgoing-event descriptor (e.g. `'order.completed'`). */
|
|
772
|
+
readonly event: ColumnBuilder<string, "text", boolean>;
|
|
773
|
+
/** Active subscription URL the delivery posts to. */
|
|
774
|
+
readonly url: ColumnBuilder<string, "text", boolean>;
|
|
775
|
+
/** Per-target signing secret. Generated at subscribe time when not
|
|
776
|
+
* supplied. Stored as-is — encryption is a deployment concern
|
|
777
|
+
* (Postgres-at-rest, KMS-wrapped column, vault sidecar). */
|
|
778
|
+
readonly secret: ColumnBuilder<string, "text", boolean>;
|
|
779
|
+
/** Serialised `SignatureScheme` discriminated union — see `signing.ts`.
|
|
780
|
+
* Stored as JSON so future schemes don't require a schema migration. */
|
|
781
|
+
readonly signing: ColumnBuilder<unknown, "json", boolean>;
|
|
782
|
+
/** Serialised `RetryPolicy` — see `retry.ts`. */
|
|
783
|
+
readonly retry: ColumnBuilder<unknown, "json", boolean>;
|
|
784
|
+
/** Optional predicate filter (subset of `Predicate`) — the engine
|
|
785
|
+
* evaluates this against each emit's payload to decide whether
|
|
786
|
+
* this target receives the delivery. */
|
|
787
|
+
readonly filter: ColumnBuilder<unknown, "json", boolean>;
|
|
788
|
+
/** Optional custom headers merged with the framework's
|
|
789
|
+
* Content-Type + signature header. Values larger than 2 KB are
|
|
790
|
+
* rejected at subscribe time. */
|
|
791
|
+
readonly headers: ColumnBuilder<unknown, "json", boolean>;
|
|
792
|
+
/** Per-target rate limit — at most N wire POSTs per minute to this
|
|
793
|
+
* target, enforced by the delivery workflow via a shared-store
|
|
794
|
+
* fixed-window counter (`_voltro_webhook_rate_windows`, so the cap
|
|
795
|
+
* holds across replicas). Excess deliveries are DEFERRED: parked as
|
|
796
|
+
* `status='pending'` rows and durable-slept until the next window
|
|
797
|
+
* opens — they're never dropped silently. */
|
|
798
|
+
readonly rateLimitPerMinute: ColumnBuilder<number | null, "integer", boolean>;
|
|
799
|
+
/** Soft-disable without deleting the row — the dashboard's
|
|
800
|
+
* "Pause" affordance flips this. While paused, emits against this
|
|
801
|
+
* target accumulate as `_voltro_webhook_deliveries` rows with
|
|
802
|
+
* status `'pending'` (no POST happens); `resumeTarget` flushes
|
|
803
|
+
* them through the delivery workflow in emit order. */
|
|
804
|
+
readonly active: ColumnBuilder<boolean, "boolean", true>;
|
|
805
|
+
/** Format the payload is delivered as. `json` is the default and
|
|
806
|
+
* what every modern integration expects. `form`
|
|
807
|
+
* (`application/x-www-form-urlencoded`, bracketed-key flattening)
|
|
808
|
+
* and `xml` (`application/xml`, `<webhook>`-rooted) exist for
|
|
809
|
+
* SOAP-era partners; the delivery workflow re-encodes the payload
|
|
810
|
+
* into this format and signs the re-encoded bytes. */
|
|
811
|
+
readonly format: ColumnBuilder<"json" | "form" | "xml", "text", true>;
|
|
812
|
+
/** Auto-disable threshold — after this many CONSECUTIVE terminal
|
|
813
|
+
* delivery failures the target is auto-paused (dead-letter guard).
|
|
814
|
+
* `null` (the default) disables the feature. When it trips, the
|
|
815
|
+
* target flips to `active=false` and subsequent emits QUEUE as
|
|
816
|
+
* `status='pending'` rows (same as a manual pause — nothing is
|
|
817
|
+
* dropped); a manual `resumeTarget` re-activates, flushes the queue,
|
|
818
|
+
* and clears the streak. */
|
|
819
|
+
readonly autoDisableAfter: ColumnBuilder<number | null, "integer", boolean>;
|
|
820
|
+
/** Consecutive terminal-failure streak. Incremented on each terminal
|
|
821
|
+
* `failed` delivery, reset to 0 on any `succeeded`. Drives
|
|
822
|
+
* `autoDisableAfter`. Multi-replica-correct via a CAS loop
|
|
823
|
+
* (`autoDisable.ts`). */
|
|
824
|
+
readonly consecutiveFailures: ColumnBuilder<number, "integer", true>;
|
|
825
|
+
/** When the auto-disable last fired (`null` = never / cleared by a
|
|
826
|
+
* manual resume). Surfaced on the inspect panel. */
|
|
827
|
+
readonly autoDisabledAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
828
|
+
/** The terminal failure reason that tripped the auto-disable
|
|
829
|
+
* (`null` = not auto-disabled). Surfaced on the inspect panel. */
|
|
830
|
+
readonly autoDisableReason: ColumnBuilder<string | null, "text", boolean>;
|
|
831
|
+
/** Schema version bound at subscribe time. Lets the dashboard
|
|
832
|
+
* show which targets are still pinned to an older event version
|
|
833
|
+
* after the producer bumps it. */
|
|
834
|
+
readonly payloadVersion: ColumnBuilder<number, "integer", true>;
|
|
835
|
+
/** Human-readable label surfaced in the dashboard listing. */
|
|
836
|
+
readonly description: ColumnBuilder<string | null, "text", boolean>;
|
|
837
|
+
}> & {
|
|
838
|
+
tenantId: ColumnDefinition<string>;
|
|
839
|
+
} & {
|
|
840
|
+
readonly createdAt: ColumnDefinition<Date, "timestamp", true>;
|
|
841
|
+
readonly updatedAt: ColumnDefinition<Date, "timestamp", true>;
|
|
842
|
+
readonly createdBy: ColumnDefinition<string | null, "reference", boolean>;
|
|
843
|
+
readonly updatedBy: ColumnDefinition<string | null, "reference", boolean>;
|
|
844
|
+
}, true, never>;
|
|
845
|
+
|
|
669
846
|
/**
|
|
670
847
|
* Thrown by `WebhooksService.replay` when no delivery row exists for the
|
|
671
848
|
* given `deliveryId` — the row can't be re-triggered because the
|