@keystrokehq/resend 0.0.9 → 0.0.16-integration-id-canonicalization.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 +41 -145
- package/dist/credential-sets/index.d.mts +2 -0
- package/dist/credential-sets/index.mjs +3 -0
- package/dist/emails-DNEKKuhw.mjs +590 -0
- package/dist/index.d.mts +4 -1
- package/dist/index.mjs +5 -1
- package/dist/operations/index.d.mts +2 -0
- package/dist/operations/index.mjs +3 -0
- package/dist/resend.credential-set-BVQIXE4k.mjs +18 -0
- package/dist/resend.credential-set-CO_XYnvV.d.mts +16 -0
- package/dist/schemas/index.d.mts +1292 -0
- package/dist/schemas/index.mjs +3 -0
- package/dist/verify-resend-domain.operation-BusUhEql.d.mts +1818 -0
- package/dist/verify-resend-domain.operation-ClVQJYPC.mjs +1481 -0
- package/package.json +11 -75
- package/dist/_official/index.d.mts +0 -2
- package/dist/_official/index.mjs +0 -3
- package/dist/_runtime/index.d.mts +0 -1
- package/dist/_runtime/index.mjs +0 -1
- package/dist/api-keys.d.mts +0 -67
- package/dist/api-keys.mjs +0 -90
- package/dist/broadcasts.d.mts +0 -238
- package/dist/broadcasts.mjs +0 -178
- package/dist/client.d.mts +0 -26
- package/dist/client.mjs +0 -40
- package/dist/connection.d.mts +0 -2
- package/dist/connection.mjs +0 -3
- package/dist/contact-properties.d.mts +0 -139
- package/dist/contact-properties.mjs +0 -115
- package/dist/contacts.d.mts +0 -218
- package/dist/contacts.mjs +0 -225
- package/dist/domains.d.mts +0 -293
- package/dist/domains.mjs +0 -160
- package/dist/emails-receiving.d.mts +0 -177
- package/dist/emails-receiving.mjs +0 -114
- package/dist/emails.d.mts +0 -307
- package/dist/emails.mjs +0 -241
- package/dist/events.d.mts +0 -571
- package/dist/events.mjs +0 -178
- package/dist/factory-CE4vHYLx.mjs +0 -7
- package/dist/http-BLe4ICIc.mjs +0 -84
- package/dist/integration-C00bEk7H.d.mts +0 -48
- package/dist/integration-C5YM61yl.mjs +0 -118
- package/dist/logs.d.mts +0 -71
- package/dist/logs.mjs +0 -61
- package/dist/schemas.d.mts +0 -77
- package/dist/schemas.mjs +0 -68
- package/dist/segments.d.mts +0 -112
- package/dist/segments.mjs +0 -120
- package/dist/templates.d.mts +0 -193
- package/dist/templates.mjs +0 -151
- package/dist/topics.d.mts +0 -125
- package/dist/topics.mjs +0 -113
- package/dist/verification.d.mts +0 -49
- package/dist/verification.mjs +0 -139
- package/dist/webhooks.d.mts +0 -285
- 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
|
|
3
|
+
Resend integration for Keystroke workflows — transactional email, broadcasts, contacts, segments, templates, domains, and Svix-signed webhook event schemas.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Package layout (strict-end)
|
|
6
6
|
|
|
7
|
-
This package
|
|
7
|
+
This package exports four subpaths:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20
|
+
Single user credential set id: **`resend`**.
|
|
24
21
|
|
|
25
22
|
Required:
|
|
26
23
|
|
|
27
|
-
- `RESEND_API_KEY` —
|
|
24
|
+
- `RESEND_API_KEY` — API key from the Resend dashboard (`re_…` prefix).
|
|
28
25
|
|
|
29
26
|
Optional:
|
|
30
27
|
|
|
31
|
-
- `RESEND_WEBHOOK_SIGNING_SECRETS` —
|
|
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
|
|
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 {
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
+
## Operations (66)
|
|
80
43
|
|
|
81
|
-
|
|
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
|
-
|
|
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
|
|
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.**
|
|
168
|
-
- **Rate limit.** Default
|
|
169
|
-
- **
|
|
170
|
-
- **
|
|
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
|
|
177
|
-
- Webhook
|
|
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
|
|