@samva/webhooks 0.12.0 → 0.14.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 CHANGED
@@ -4,14 +4,17 @@ Verify signed Samva webhook deliveries in Node.js, Bun, Cloudflare Workers, and
4
4
  Crypto-compatible runtimes.
5
5
 
6
6
  ```ts
7
- import { verifyRequest } from "@samva/webhooks";
7
+ import { isKnownEvent, verifyRequest } from "@samva/webhooks";
8
8
 
9
9
  const verified = await verifyRequest(request, process.env.SAMVA_WEBHOOK_SECRET!);
10
+ if (isKnownEvent(verified.event) && verified.event.type === "message.bounced") {
11
+ await suppressRecipient(verified.event.data.recipient, verified.event.data.occurredAt);
12
+ }
10
13
  await persistAndHandleOnce(verified.id, verified.event);
11
14
  ```
12
15
 
13
16
  Verification reads the exact request body, validates the Standard Webhooks signature and replay
14
- window, and returns `{ id, event }`. `verified.id` matches the `webhook-id` header. Preserve the raw
17
+ window and the event-specific payload, and returns `{ id, event }`. `verified.id` matches the `webhook-id` header. Preserve the raw
15
18
  request body and keep the signing secret on the server.
16
19
 
17
20
  Effect applications can use the optional Effect entrypoint:
@@ -27,3 +30,21 @@ const program = Effect.gen(function* () {
27
30
  ```
28
31
 
29
32
  Install the `effect` version this package lists in `peerDependencies` when using that entrypoint.
33
+
34
+ `VerifiedWebhook.event` is a `WebhookEvent`: a known `SamvaWebhookEvent` or an
35
+ `UnknownWebhookEvent` with `type: string` and `data: unknown`. Call `isKnownEvent(event)` before
36
+ branching on `event.type` to narrow known payloads. Per-event types such as `MessageBouncedPayload`
37
+ and `ContactUnsubscribedPayload` are exported from both entrypoints.
38
+
39
+ Signature verification is the authenticity gate. Signed new event types pass through as untyped
40
+ events; extra envelope and payload fields are accepted and preserved. Only malformed envelopes or
41
+ invalid payloads for known event types fail with `MalformedWebhookPayloadError`. Update the package
42
+ to gain types for new events. Bounce and complaint events publish once per affected address, each
43
+ with its own `webhook-id`; deduplicate using that ID rather than `messageId`.
44
+
45
+ For separate decoding, import `MessageBouncedEventSchema` or `SamvaWebhookEventSchema` from
46
+ `@samva/webhooks/schemas` (or the Effect entrypoint) and use `Schema.decodeUnknownSync`.
47
+ `WebhookEventJsonSchemas` exports the same wire contracts for JSON Schema validators.
48
+
49
+ Signing secrets are `whsec_` followed by Base64-encoded secret bytes. Copy the entire secret from
50
+ Samva; the suffix is Base64, not hex or Base64url.
@@ -0,0 +1,4 @@
1
+ import type { SamvaWebhookEvent, WebhookEvent } from "./types.gen.js";
2
+ /** Narrow an event to a structurally valid payload known to this package. */
3
+ export declare const isKnownEvent: (value: WebhookEvent) => value is SamvaWebhookEvent;
4
+ export declare const validateEvent: (value: unknown) => value is WebhookEvent;
package/dist/effect.d.ts CHANGED
@@ -38,6 +38,9 @@ export declare const verify: (options: VerifyOptions) => Effect.Effect<VerifiedW
38
38
  export declare const verifyRequest: (request: Request, secret: string, options?: {
39
39
  readonly toleranceSeconds?: number | undefined;
40
40
  } | undefined) => Effect.Effect<VerifiedWebhook, AnyWebhookVerificationError, never>;
41
- export { DEFAULT_TOLERANCE_SECONDS, WEBHOOK_ID_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER, generateWebhookSecret, signWebhook, } from "./protocol.js";
41
+ export { DEFAULT_TOLERANCE_SECONDS, WEBHOOK_ID_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER, isKnownEvent, generateWebhookSecret, signWebhook, } from "./protocol.js";
42
42
  export type { AnyWebhookVerificationError, SamvaWebhookEvent, VerifiedWebhook, WebhookHeaderName, } from "./protocol.js";
43
43
  export { InvalidWebhookHeadersError, InvalidWebhookSecretError, MalformedWebhookPayloadError, WebhookCryptoError, WebhookSignatureError, WebhookTimestampError, WebhookVerificationError, } from "./protocol.js";
44
+ export type * from "./types.gen.js";
45
+ export { WebhookEventJsonSchemas } from "./json-schemas.gen.js";
46
+ export * from "./schemas.gen.js";
package/dist/effect.js CHANGED
@@ -1,4 +1,6 @@
1
- import { _ as WebhookTimestampError, c as signWebhook, f as InvalidWebhookHeadersError, g as WebhookSignatureError, h as WebhookCryptoError, i as WEBHOOK_TIMESTAMP_HEADER, l as verifyWebhookAt, m as MalformedWebhookPayloadError, n as WEBHOOK_ID_HEADER, o as generateWebhookSecret, p as InvalidWebhookSecretError, r as WEBHOOK_SIGNATURE_HEADER, t as DEFAULT_TOLERANCE_SECONDS, v as WebhookVerificationError } from "./protocol-BGKUmvlI.js";
1
+ import { _ as WebhookTimestampError, c as signWebhook, f as InvalidWebhookHeadersError, g as WebhookSignatureError, h as WebhookCryptoError, i as WEBHOOK_TIMESTAMP_HEADER, l as verifyWebhookAt, m as MalformedWebhookPayloadError, n as WEBHOOK_ID_HEADER, o as generateWebhookSecret, p as InvalidWebhookSecretError, r as WEBHOOK_SIGNATURE_HEADER, t as DEFAULT_TOLERANCE_SECONDS, v as WebhookVerificationError, y as isKnownEvent } from "./protocol-CLrYczjc.js";
2
+ import { t as WebhookEventJsonSchemas } from "./json-schemas.gen-eya_ZDps.js";
3
+ import { ContactCreatedEventSchema, ContactDeletedEventSchema, ContactResubscribedEventSchema, ContactSubscribedEventSchema, ContactUnsubscribedEventSchema, ContactUpdatedEventSchema, ConversationArchivedEventSchema, ConversationCreatedEventSchema, ConversationUpdatedEventSchema, DomainUpdatedEventSchema, DomainWarmingUpdatedEventSchema, MailboxActionPendingApprovalEventSchema, MailboxMessageDiscardedEventSchema, MailboxMessageQuarantinedEventSchema, MailboxMessageReceivedEventSchema, MailboxMessageReleasedEventSchema, MailboxMessageSentEventSchema, MessageBouncedEventSchema, MessageClickedEventSchema, MessageComplainedEventSchema, MessageDeliveredEventSchema, MessageFailedEventSchema, MessageOpenedEventSchema, MessageReadEventSchema, MessageReceivedEventSchema, MessageSentEventSchema, SamvaWebhookEventSchema, WebhookCreatedEventSchema, WebhookDeletedEventSchema, WebhookTestEventSchema, WebhookUpdatedEventSchema } from "./schemas.gen.js";
2
4
  import { Clock, Effect } from "effect";
3
5
  //#region src/effect.ts
4
6
  /**
@@ -73,6 +75,6 @@ const verifyRequest = Effect.fn("Webhooks.verifyRequest")(function* (request, se
73
75
  });
74
76
  });
75
77
  //#endregion
76
- export { DEFAULT_TOLERANCE_SECONDS, InvalidWebhookHeadersError, InvalidWebhookSecretError, MalformedWebhookPayloadError, WEBHOOK_ID_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER, WebhookCryptoError, WebhookSignatureError, WebhookTimestampError, WebhookVerificationError, generateWebhookSecret, signWebhook, verify, verifyRequest };
78
+ export { ContactCreatedEventSchema, ContactDeletedEventSchema, ContactResubscribedEventSchema, ContactSubscribedEventSchema, ContactUnsubscribedEventSchema, ContactUpdatedEventSchema, ConversationArchivedEventSchema, ConversationCreatedEventSchema, ConversationUpdatedEventSchema, DEFAULT_TOLERANCE_SECONDS, DomainUpdatedEventSchema, DomainWarmingUpdatedEventSchema, InvalidWebhookHeadersError, InvalidWebhookSecretError, MailboxActionPendingApprovalEventSchema, MailboxMessageDiscardedEventSchema, MailboxMessageQuarantinedEventSchema, MailboxMessageReceivedEventSchema, MailboxMessageReleasedEventSchema, MailboxMessageSentEventSchema, MalformedWebhookPayloadError, MessageBouncedEventSchema, MessageClickedEventSchema, MessageComplainedEventSchema, MessageDeliveredEventSchema, MessageFailedEventSchema, MessageOpenedEventSchema, MessageReadEventSchema, MessageReceivedEventSchema, MessageSentEventSchema, SamvaWebhookEventSchema, WEBHOOK_ID_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER, WebhookCreatedEventSchema, WebhookCryptoError, WebhookDeletedEventSchema, WebhookEventJsonSchemas, WebhookSignatureError, WebhookTestEventSchema, WebhookTimestampError, WebhookUpdatedEventSchema, WebhookVerificationError, generateWebhookSecret, isKnownEvent, signWebhook, verify, verifyRequest };
77
79
 
78
80
  //# sourceMappingURL=effect.js.map