@keystrokehq/resend 0.0.15 → 0.0.16-integration-id-canonicalization.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.
Files changed (56) hide show
  1. package/README.md +41 -145
  2. package/dist/credential-sets/index.d.mts +2 -0
  3. package/dist/credential-sets/index.mjs +3 -0
  4. package/dist/emails-DNEKKuhw.mjs +590 -0
  5. package/dist/index.d.mts +4 -1
  6. package/dist/index.mjs +5 -1
  7. package/dist/operations/index.d.mts +2 -0
  8. package/dist/operations/index.mjs +3 -0
  9. package/dist/resend.credential-set-BVQIXE4k.mjs +18 -0
  10. package/dist/resend.credential-set-CO_XYnvV.d.mts +16 -0
  11. package/dist/schemas/index.d.mts +1292 -0
  12. package/dist/schemas/index.mjs +3 -0
  13. package/dist/verify-resend-domain.operation-BusUhEql.d.mts +1818 -0
  14. package/dist/verify-resend-domain.operation-ClVQJYPC.mjs +1481 -0
  15. package/package.json +13 -77
  16. package/dist/_official/index.d.mts +0 -2
  17. package/dist/_official/index.mjs +0 -3
  18. package/dist/_runtime/index.d.mts +0 -1
  19. package/dist/_runtime/index.mjs +0 -1
  20. package/dist/api-keys.d.mts +0 -57
  21. package/dist/api-keys.mjs +0 -90
  22. package/dist/broadcasts.d.mts +0 -219
  23. package/dist/broadcasts.mjs +0 -178
  24. package/dist/client.d.mts +0 -27
  25. package/dist/client.mjs +0 -40
  26. package/dist/connection.d.mts +0 -2
  27. package/dist/connection.mjs +0 -3
  28. package/dist/contact-properties.d.mts +0 -123
  29. package/dist/contact-properties.mjs +0 -115
  30. package/dist/contacts.d.mts +0 -187
  31. package/dist/contacts.mjs +0 -225
  32. package/dist/domains.d.mts +0 -274
  33. package/dist/domains.mjs +0 -160
  34. package/dist/emails-receiving.d.mts +0 -164
  35. package/dist/emails-receiving.mjs +0 -114
  36. package/dist/emails.d.mts +0 -282
  37. package/dist/emails.mjs +0 -241
  38. package/dist/events.d.mts +0 -571
  39. package/dist/events.mjs +0 -178
  40. package/dist/factory-C91g4Zm2.mjs +0 -8
  41. package/dist/integration-DEgw-tXs.d.mts +0 -46
  42. package/dist/integration-DXosbRPM.mjs +0 -29
  43. package/dist/logs.d.mts +0 -64
  44. package/dist/logs.mjs +0 -61
  45. package/dist/schemas.d.mts +0 -77
  46. package/dist/schemas.mjs +0 -68
  47. package/dist/segments.d.mts +0 -96
  48. package/dist/segments.mjs +0 -120
  49. package/dist/templates.d.mts +0 -171
  50. package/dist/templates.mjs +0 -151
  51. package/dist/topics.d.mts +0 -109
  52. package/dist/topics.mjs +0 -113
  53. package/dist/verification.d.mts +0 -49
  54. package/dist/verification.mjs +0 -139
  55. package/dist/webhooks.d.mts +0 -269
  56. package/dist/webhooks.mjs +0 -124
package/README.md CHANGED
@@ -1,183 +1,79 @@
1
1
  # @keystrokehq/resend
2
2
 
3
- Resend integration for Keystroke workflows — transactional email, broadcasts, contacts, segments, templates, domains, and Svix-signed webhook triggers.
3
+ Resend integration for Keystroke workflows — transactional email, broadcasts, contacts, segments, templates, domains, and Svix-signed webhook event schemas.
4
4
 
5
- ## Overview
5
+ ## Package layout (strict-end)
6
6
 
7
- This package wraps the [Resend](https://resend.com) v1 REST API and exposes:
7
+ This package exports four subpaths:
8
8
 
9
- - **66 operations** across 12 resource domains.
10
- - **17 direct-binding webhook trigger helpers** (11 email, 3 domain, 3 contact) with Svix v1 signature verification.
11
- - An idempotent `ensureResendWebhook` helper that registers a webhook endpoint, reconciles its event subscription, and returns the per-endpoint signing secret.
9
+ | Subpath | Contents |
10
+ |---------|----------|
11
+ | `@keystrokehq/resend` | Re-exports credential sets, operations, and schemas |
12
+ | `@keystrokehq/resend/credential-sets` | `resendCredentialSet`, `ResendCredentials` |
13
+ | `@keystrokehq/resend/operations` | 66 `Operation` primitives (one file per operation under `src/operations/`) |
14
+ | `@keystrokehq/resend/schemas` | Shared Zod schemas, webhook event envelopes, domain response shapes |
12
15
 
13
- No runtime dependency on the official `resend` npm package — the client is a thin wrapper over the shared `createJsonRestClient` helper from `@keystrokehq/integration-authoring`, and the Svix verifier is hand-rolled on top of Node's `crypto` module. See [`IMPLEMENTATION_NOTES.md`](./IMPLEMENTATION_NOTES.md) § 3 for the SDK rejection rationale.
14
-
15
- ## Installation
16
-
17
- ```bash
18
- pnpm add @keystrokehq/resend
19
- ```
16
+ Internal helpers live under `src/utils/` (`createResendClient`, Svix webhook verification). They are not public package exports.
20
17
 
21
18
  ## Credentials
22
19
 
23
- The public connection is manual API-key auth.
20
+ Single user credential set id: **`resend`**.
24
21
 
25
22
  Required:
26
23
 
27
- - `RESEND_API_KEY` — an API key from your Resend dashboard (`re_…`).
24
+ - `RESEND_API_KEY` — API key from the Resend dashboard (`re_…` prefix).
28
25
 
29
26
  Optional:
30
27
 
31
- - `RESEND_WEBHOOK_SIGNING_SECRETS` — a map of `{ webhookId: whsec_… }`. Populate it automatically via `ensureResendWebhook` (see below) before binding webhook triggers.
28
+ - `RESEND_WEBHOOK_SIGNING_SECRETS` — map of `{ endpointId: whsec_… }` per webhook endpoint. Populate when registering webhooks (`create-resend-webhook` returns a signing secret) so inbound Svix payloads can be verified at runtime.
32
29
 
33
- There is no OAuth flow and no Keystroke-owned shared client secret. API keys are team-scoped — one Keystroke connection = one Resend team.
30
+ There is no OAuth flow. API keys are team-scoped.
34
31
 
35
32
  ## Quickstart
36
33
 
37
- Import the connection and two helpers you'll use most:
38
-
39
- ```ts
40
- import { resend, type ResendCredentials } from '@keystrokehq/resend/connection';
41
- import { sendEmail } from '@keystrokehq/resend/emails';
42
- import { triggers } from '@keystrokehq/resend/triggers';
43
- ```
44
-
45
- ### Send a transactional email
46
-
47
- `sendEmail` is a Keystroke operation. Drop it into a workflow step that has the Resend connection attached; the workflow runtime hands it typed credentials.
48
-
49
34
  ```ts
50
- import { sendEmail } from '@keystrokehq/resend/emails';
51
-
52
- sendEmail({
53
- id: 'welcome_email',
54
- // Keystroke wires input at workflow-compile time; the shape below is
55
- // the validated input of sendEmail.
56
- input: {
57
- from: 'Acme <onboarding@acme.example>',
58
- to: ['delivered@resend.dev'],
59
- subject: 'Welcome to Acme',
60
- html: '<p>Glad you are here.</p>',
61
- // Optional; forwarded as the Idempotency-Key header (24h TTL).
62
- idempotency_key: 'welcome-2026-04-20',
63
- },
64
- });
35
+ import { resendCredentialSet } from '@keystrokehq/resend/credential-sets';
36
+ import { sendEmailOperation } from '@keystrokehq/resend/operations';
37
+ import { resendWebhookEventSchema } from '@keystrokehq/resend/schemas';
65
38
  ```
66
39
 
67
- ### Subscribe to delivery events
68
-
69
- All Resend webhooks go through one signed HTTPS POST channel. Bind one helper per event type:
70
-
71
- ```ts
72
- import { triggers } from '@keystrokehq/resend/triggers';
73
-
74
- const onBounce = triggers.emailBounced({
75
- name: 'Resend bounce handler',
76
- });
77
- ```
40
+ Workflow steps reference operations by id (e.g. `resend.send-resend-email`). The runtime resolves `context.credentials.resend` from the bound credential set.
78
41
 
79
- `triggers.emailOpened` filters out Apple Mail Privacy Protection cache-opens (`data.is_machine_opened === true`) by default — if you want those too, pass a custom `filter` in the binding options.
42
+ ## Operations (66)
80
43
 
81
- ### Wire the webhook endpoint
44
+ | Domain | Count |
45
+ |--------|------:|
46
+ | emails (sent) | 8 |
47
+ | emails (receiving) | 4 |
48
+ | broadcasts | 6 |
49
+ | contacts | 10 |
50
+ | contact-properties | 5 |
51
+ | segments | 5 |
52
+ | templates | 7 |
53
+ | topics | 5 |
54
+ | domains | 6 |
55
+ | api-keys | 3 |
56
+ | webhooks (endpoint CRUD) | 5 |
57
+ | logs | 2 |
82
58
 
83
- Before a trigger binding can verify payloads it needs the per-endpoint `whsec_…` signing secret on the credential set. Run this once per environment:
84
-
85
- ```ts
86
- import { ensureResendWebhook } from '@keystrokehq/resend/triggers';
87
-
88
- const result = await ensureResendWebhook({
89
- credentials,
90
- endpointUrl: 'https://workflows.example.com/hooks/resend',
91
- events: ['email.delivered', 'email.bounced', 'email.complained'],
92
- });
93
- // result.webhookId, result.signingSecret, result.created, result.updated
94
- ```
95
-
96
- Then persist `result.signingSecret` under `credentials.RESEND_WEBHOOK_SIGNING_SECRETS[result.webhookId]`. The trigger verifier iterates every secret in that map, which also handles rotation: add a new webhook, store its secret alongside the old one, and remove the old webhook once you've cut over.
97
-
98
- ## Resource domains
99
-
100
- Every endpoint on the public Resend v1 API is wrapped.
101
-
102
- | Subpath | Endpoints covered |
103
- |---------|-------------------|
104
- | `@keystrokehq/resend/emails` | `POST /emails`, `POST /emails/batch`, `GET /emails`, `GET /emails/{id}`, `PATCH /emails/{id}`, `POST /emails/{id}/cancel`, `GET /emails/{id}/attachments`, `GET /emails/{id}/attachments/{id}` |
105
- | `@keystrokehq/resend/emails-receiving` | `GET /emails/receiving`, `GET /emails/receiving/{id}`, `GET /emails/receiving/{id}/attachments`, `GET /emails/receiving/{id}/attachments/{id}` |
106
- | `@keystrokehq/resend/templates` | CRUD + duplicate + publish |
107
- | `@keystrokehq/resend/broadcasts` | CRUD + send |
108
- | `@keystrokehq/resend/contacts` | CRUD + segment-membership + topic-subscriptions |
109
- | `@keystrokehq/resend/contact-properties` | CRUD |
110
- | `@keystrokehq/resend/segments` | CRUD + list-contacts (no update — segments are filter-defined) |
111
- | `@keystrokehq/resend/topics` | CRUD |
112
- | `@keystrokehq/resend/domains` | CRUD + verify |
113
- | `@keystrokehq/resend/api-keys` | Create, list, delete (no get/update on the Resend API) |
114
- | `@keystrokehq/resend/webhooks` | CRUD (endpoint CRUD — for direct-binding triggers use `/triggers`) |
115
- | `@keystrokehq/resend/logs` | List, retrieve (plan-gated) |
116
-
117
- ### Support-surface imports
118
-
119
- Use these when you need to wire secondary pieces (raw client, schema types, event constants, verification helpers):
120
-
121
- - `@keystrokehq/resend/connection` — `resend`, `ResendCredentials`, `resendAuthSchema`.
122
- - `@keystrokehq/resend/client` — `createResendClient`, `ResendClient`, `RESEND_BASE_URL`, `RESEND_USER_AGENT`.
123
- - `@keystrokehq/resend/schemas` — list envelope, pagination, region / TLS / permission enums.
124
- - `@keystrokehq/resend/events` — event name constants and payload schemas.
125
- - `@keystrokehq/resend/verification` — `verifyResendWebhookRequest`, `parseResendWebhookBody`, Svix header constants.
126
-
127
- ### Hidden surfaces (do not import from application code)
128
-
129
- `@keystrokehq/resend/_official` and `@keystrokehq/resend/_runtime` exist for `@keystrokehq/official-integration-catalog`. End users should not import them.
59
+ Webhook **endpoint CRUD** lives in `./operations`. Event payload schemas live in `./schemas` (`events.ts`). Svix verification helpers are internal (`src/utils/verification.ts`).
130
60
 
131
61
  ## Safety model
132
62
 
133
- Writes and deletes are marked `needsApproval: true`. Read-only list/retrieve operations are not. Callers can override either way per-operation, but the defaults reflect Resend's destructive-action surface.
134
-
135
- ## Webhook verification (standalone)
136
-
137
- If you want to verify a Resend webhook outside the Keystroke trigger runtime:
138
-
139
- ```ts
140
- import {
141
- verifyResendWebhookRequest,
142
- parseResendWebhookBody,
143
- } from '@keystrokehq/resend/verification';
144
- import { resendWebhookEventSchema } from '@keystrokehq/resend/events';
145
-
146
- function handle(request: {
147
- rawBody: string;
148
- headers: Record<string, string | string[] | undefined>;
149
- }) {
150
- const verified = verifyResendWebhookRequest({
151
- rawBody: request.rawBody,
152
- headers: request.headers,
153
- signingSecret: process.env.RESEND_WEBHOOK_SECRET ?? '',
154
- });
155
- if (!verified.ok) {
156
- return { status: 401 as const, reason: verified.reason };
157
- }
158
-
159
- const body = parseResendWebhookBody(request.rawBody);
160
- const event = resendWebhookEventSchema.parse(body);
161
- return { status: 200 as const, event };
162
- }
163
- ```
63
+ Writes and deletes default to `needsApproval: true`. Read-only list/retrieve operations do not.
164
64
 
165
65
  ## Caveats
166
66
 
167
- - **User-Agent is mandatory.** The Resend API returns HTTP 403 with error code 1010 if no `User-Agent` is attached. The client sets one automatically.
168
- - **Rate limit.** Default is 5 requests/second per team. Retries are not automatic callers should implement backoff, or forward an `Idempotency-Key` on `sendEmail`/`sendBatchEmails` so retries are safe.
169
- - **Apple Mail Privacy Protection.** `triggers.emailOpened` silently drops `is_machine_opened: true` events. Override the `filter` to opt in.
170
- - **React rendering is not server-side.** The official SDK's `react` body field is intentionally not accepted render React Email components to HTML upstream and pass the string via `html`.
171
- - **CSV imports do not emit `contact.created`.** Documented limitation. If you need that signal, poll `listContacts` with cursor persistence.
172
- - **Signing-secret rotation.** Resend does not expose in-place rotation. Cut over by creating a second webhook, storing its new secret alongside the old one in `RESEND_WEBHOOK_SIGNING_SECRETS`, and deleting the old endpoint once traffic has flipped. The trigger verifier iterates every secret in the map.
67
+ - **User-Agent is mandatory.** Missing `User-Agent` returns HTTP 403 (error code 1010). The internal client sets one automatically.
68
+ - **Rate limit.** Default 5 req/s per team — implement backoff or use `Idempotency-Key` on send operations.
69
+ - **React rendering is not server-side.** Pass rendered HTML via `html`; the SDK `react` field is not accepted.
70
+ - **Signing-secret rotation.** Create a new webhook, store both secrets in `RESEND_WEBHOOK_SIGNING_SECRETS`, then delete the old endpoint.
173
71
 
174
72
  ## References
175
73
 
176
- - API docs index: <https://resend.com/docs/api-reference/introduction>
177
- - Webhook event types: <https://resend.com/docs/dashboard/webhooks/event-types>
74
+ - API docs: <https://resend.com/docs/api-reference/introduction>
75
+ - Webhook events: <https://resend.com/docs/dashboard/webhooks/event-types>
178
76
  - Webhook verification: <https://resend.com/docs/webhooks/verify-webhooks-requests>
179
- - Pagination: <https://resend.com/docs/api-reference/pagination>
180
- - OpenAPI spec: <https://github.com/resend/resend-openapi>
181
77
 
182
78
  ## License
183
79
 
@@ -0,0 +1,2 @@
1
+ import { n as resendCredentialSet, t as ResendCredentials } from "../resend.credential-set-CO_XYnvV.mjs";
2
+ export { type ResendCredentials, resendCredentialSet };
@@ -0,0 +1,3 @@
1
+ import { t as resendCredentialSet } from "../resend.credential-set-BVQIXE4k.mjs";
2
+
3
+ export { resendCredentialSet };