@agentpress/sdk 0.2.70

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 ADDED
@@ -0,0 +1,402 @@
1
+ # @agentpress/sdk
2
+
3
+ Zero-dependency TypeScript SDK for the AgentPress webhook API.
4
+
5
+ - **Package:** `@agentpress/sdk` (npm, public)
6
+ - **Output:** Dual ESM (`.mjs`) + CJS (`.cjs`)
7
+ - **Node:** >= 22.0.0
8
+ - **Dependencies:** None (uses `node:crypto` for HMAC-SHA256)
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @agentpress/sdk
14
+ # or
15
+ bun add @agentpress/sdk
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```typescript
21
+ import { AgentPress } from "@agentpress/sdk";
22
+
23
+ const client = new AgentPress({
24
+ webhookSecret: "whsec_your_secret_here",
25
+ });
26
+
27
+ // Send a webhook
28
+ await client.webhooks.send({
29
+ action: "my_action",
30
+ payload: { eventType: "test", data: { key: "value" } },
31
+ });
32
+ ```
33
+
34
+ ## Constructor Options
35
+
36
+ ```typescript
37
+ const client = new AgentPress({
38
+ webhookSecret: "whsec_...", // Required for send/verify (must start with "whsec_")
39
+ baseUrl: "https://api.agent.press", // Default
40
+ timeout: 30_000, // Default, in milliseconds
41
+ org: "default-org", // Default org slug
42
+ apiKey: "sk_...", // Optional, reserved for future API auth
43
+ onRequest: (url, init) => {}, // Optional hook, called before every request
44
+ onResponse: (url, response) => {}, // Optional hook, receives a cloned Response
45
+ });
46
+ ```
47
+
48
+ All options are optional. `webhookSecret` is required only when calling `send`, `verify`, or `verifyOrThrow`.
49
+
50
+ **Validation rules:**
51
+ - `webhookSecret` must start with `"whsec_"` or a `ConfigurationError` is thrown
52
+ - `timeout` must be a positive finite number
53
+ - Trailing slashes on `baseUrl` are stripped automatically
54
+
55
+ ## API Reference
56
+
57
+ The client exposes two namespaces: `client.webhooks` and `client.actions`.
58
+
59
+ ### client.webhooks.send(params)
60
+
61
+ Signs and sends an arbitrary webhook payload via HMAC-SHA256.
62
+
63
+ ```typescript
64
+ const response = await client.webhooks.send({
65
+ action: "my_webhook_action",
66
+ payload: {
67
+ eventType: "order.completed",
68
+ externalId: "order-456",
69
+ data: { total: 99.99 },
70
+ },
71
+ });
72
+ ```
73
+
74
+ **Endpoint:** `POST {baseUrl}/webhooks/actions/{org}/{action}`
75
+
76
+ **Params (`WebhookSendParams`):**
77
+
78
+ | Field | Type | Description |
79
+ |-------|------|-------------|
80
+ | `action` | `string` | Webhook action identifier (used in URL path) |
81
+ | `payload` | `Record<string, unknown>` | Arbitrary JSON payload to sign and send |
82
+
83
+ **Returns (`WebhookResponse`):**
84
+
85
+ ```typescript
86
+ {
87
+ success: boolean;
88
+ actionId?: string; // ID of created action
89
+ alreadyExists?: boolean; // Duplicate externalId
90
+ skipped?: boolean;
91
+ data?: Record<string, unknown>;
92
+ }
93
+ ```
94
+
95
+ **Throws:** `ConfigurationError` (missing secret), `HttpError` (non-2xx), `TimeoutError`
96
+
97
+ **Signing details:** Each request gets three headers automatically:
98
+ - `svix-id` -- unique message ID (`msg_<uuid>`)
99
+ - `svix-timestamp` -- Unix seconds
100
+ - `svix-signature` -- `v1,<base64 HMAC-SHA256>`
101
+
102
+ The signature input is `${msgId}.${timestamp}.${body}`.
103
+
104
+ ---
105
+
106
+ ### client.webhooks.verify(params)
107
+
108
+ Verifies an inbound Svix webhook signature. Returns `true` if valid, `false` if invalid or expired.
109
+
110
+ ```typescript
111
+ const isValid = client.webhooks.verify({
112
+ payload: rawRequestBody, // string or Buffer
113
+ headers: {
114
+ "svix-id": req.headers["svix-id"],
115
+ "svix-timestamp": req.headers["svix-timestamp"],
116
+ "svix-signature": req.headers["svix-signature"],
117
+ },
118
+ });
119
+
120
+ if (!isValid) {
121
+ return new Response("Unauthorized", { status: 401 });
122
+ }
123
+ ```
124
+
125
+ **Params (`WebhookVerifyParams`):**
126
+
127
+ | Field | Type | Description |
128
+ |-------|------|-------------|
129
+ | `payload` | `string \| Buffer` | Raw request body |
130
+ | `headers["svix-id"]` | `string` | Message ID header |
131
+ | `headers["svix-timestamp"]` | `string` | Unix timestamp header |
132
+ | `headers["svix-signature"]` | `string` | Signature header (may contain space-separated signatures) |
133
+
134
+ **Verification rules:**
135
+ - Timestamp must be within 5 minutes of current time (replay protection)
136
+ - Uses timing-safe comparison (`timingSafeEqual`)
137
+ - Supports multiple space-separated signatures in the header (any match = valid)
138
+
139
+ **Throws:** `ConfigurationError` if `webhookSecret` was not provided
140
+
141
+ ---
142
+
143
+ ### client.webhooks.verifyOrThrow(params)
144
+
145
+ Same as `verify` but throws `WebhookSignatureError` on invalid signature. Useful in middleware.
146
+
147
+ ```typescript
148
+ try {
149
+ client.webhooks.verifyOrThrow({
150
+ payload: rawBody,
151
+ headers: {
152
+ "svix-id": headers["svix-id"],
153
+ "svix-timestamp": headers["svix-timestamp"],
154
+ "svix-signature": headers["svix-signature"],
155
+ },
156
+ });
157
+ // Signature is valid, proceed
158
+ } catch (error) {
159
+ if (error instanceof WebhookSignatureError) {
160
+ return new Response("Invalid signature", { status: 401 });
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### client.webhooks.constructEvent(params)
166
+
167
+ Verify and parse an inbound webhook from AgentPress in one step. Combines signature verification with JSON parsing and returns a typed `ActionCallbackPayload`. This is the recommended way to handle incoming webhooks.
168
+
169
+ ```typescript
170
+ import { AgentPress, type ActionCallbackPayload } from "@agentpress/sdk";
171
+
172
+ const client = new AgentPress({ webhookSecret: "whsec_..." });
173
+
174
+ // Express example
175
+ app.post("/webhooks/agentpress", express.raw({ type: "application/json" }), (req, res) => {
176
+ const event = client.webhooks.constructEvent({
177
+ payload: req.body, // raw body string or Buffer
178
+ headers: {
179
+ "svix-id": req.headers["svix-id"] as string,
180
+ "svix-timestamp": req.headers["svix-timestamp"] as string,
181
+ "svix-signature": req.headers["svix-signature"] as string,
182
+ },
183
+ });
184
+
185
+ console.log(event.status); // "completed" | "failed" | ...
186
+ console.log(event.agentResponse); // { text: "...", toolCalls: [...] }
187
+
188
+ res.status(200).json({ received: true });
189
+ });
190
+ ```
191
+
192
+ **Params:** Same as `verify` / `verifyOrThrow` (`WebhookVerifyParams`).
193
+
194
+ **Returns (`ActionCallbackPayload`):**
195
+
196
+ | Field | Type | Description |
197
+ |-------|------|-------------|
198
+ | `actionId` | `string` | Action identifier |
199
+ | `status` | `ActionStatus` | `"completed"`, `"failed"`, `"rejected"`, etc. |
200
+ | `actionType` | `string` | The action type (e.g., `"order.created"`) |
201
+ | `completedAt` | `string` | ISO 8601 timestamp |
202
+ | `sourceData` | `Record<string, unknown>` | Original data from the inbound webhook |
203
+ | `externalId` | `string \| null` | External system identifier |
204
+ | `userId` | `string \| null` | AgentPress user ID |
205
+ | `threadId` | `string \| null` | Thread ID if a conversation was created |
206
+ | `agentResponse` | `AgentResponse` | Agent's text response and tool call results |
207
+ | `errorMessage` | `string \| null` | Error details if the action failed |
208
+ | `rejectionReason` | `string \| null` | Reason if rejected by a human reviewer |
209
+
210
+ **Throws:** `WebhookSignatureError` (invalid/expired signature), `ConfigurationError` (missing secret), `AgentPressError` (invalid JSON)
211
+
212
+ ---
213
+
214
+ ### client.actions.approve(actionId, params)
215
+
216
+ Approve a staged action, optionally modifying the tool call arguments before execution.
217
+
218
+ ```typescript
219
+ // Approve as-is
220
+ await client.actions.approve("act_123", {
221
+ action: "my_webhook_action",
222
+ });
223
+
224
+ // Approve with modified arguments
225
+ await client.actions.approve("act_123", {
226
+ action: "my_webhook_action",
227
+ editedToolCall: {
228
+ toolName: "sendEmail",
229
+ arguments: { subject: "Updated subject" },
230
+ },
231
+ });
232
+ ```
233
+
234
+ **Endpoint:** `POST {baseUrl}/webhooks/actions/{org}/{action}/manage/{actionId}/approve`
235
+
236
+ **Params:**
237
+
238
+ | Field | Type | Description |
239
+ |-------|------|-------------|
240
+ | `actionId` | `string` | Action ID (first positional argument) |
241
+ | `params.action` | `string` | Webhook action identifier (from callback's `webhookAction` field) |
242
+ | `params.editedToolCall` | `object` (optional) | Modified tool call to use instead of the original |
243
+
244
+ **Returns (`ActionManageResponse`):**
245
+
246
+ ```typescript
247
+ {
248
+ success: boolean;
249
+ actionId: string;
250
+ status: ActionStatus;
251
+ }
252
+ ```
253
+
254
+ **Throws:** `ConfigurationError` (missing secret), `HttpError` (non-2xx), `TimeoutError`
255
+
256
+ ---
257
+
258
+ ### client.actions.reject(actionId, params)
259
+
260
+ Reject a staged action with an optional reason.
261
+
262
+ ```typescript
263
+ await client.actions.reject("act_456", {
264
+ action: "my_webhook_action",
265
+ reason: "Insufficient context to proceed",
266
+ });
267
+ ```
268
+
269
+ **Endpoint:** `POST {baseUrl}/webhooks/actions/{org}/{action}/manage/{actionId}/reject`
270
+
271
+ **Params:**
272
+
273
+ | Field | Type | Description |
274
+ |-------|------|-------------|
275
+ | `actionId` | `string` | Action ID (first positional argument) |
276
+ | `params.action` | `string` | Webhook action identifier (from callback's `webhookAction` field) |
277
+ | `params.reason` | `string` (optional) | Reason for rejection |
278
+
279
+ **Returns:** `ActionManageResponse` (same as `approve`)
280
+
281
+ **Throws:** `ConfigurationError` (missing secret), `HttpError` (non-2xx), `TimeoutError`
282
+
283
+ ---
284
+
285
+ ## Error Handling
286
+
287
+ All errors extend `AgentPressError`. Import and use `instanceof` for specific handling.
288
+
289
+ ```typescript
290
+ import {
291
+ AgentPress,
292
+ AgentPressError,
293
+ ConfigurationError,
294
+ HttpError,
295
+ TimeoutError,
296
+ WebhookSignatureError,
297
+ } from "@agentpress/sdk";
298
+
299
+ try {
300
+ await client.webhooks.send({ action: "test", payload: {} });
301
+ } catch (error) {
302
+ if (error instanceof HttpError) {
303
+ // Non-2xx response from the server
304
+ console.log(error.statusCode); // e.g. 400, 404, 500
305
+ console.log(error.responseBody); // Raw response text
306
+ console.log(error.url); // Full request URL
307
+ } else if (error instanceof TimeoutError) {
308
+ // Request exceeded the configured timeout
309
+ } else if (error instanceof ConfigurationError) {
310
+ // Missing webhookSecret, invalid timeout, etc.
311
+ } else if (error instanceof WebhookSignatureError) {
312
+ // Only from verifyOrThrow -- invalid or expired signature
313
+ } else if (error instanceof AgentPressError) {
314
+ // Base class: fetch failures, unexpected non-JSON responses
315
+ }
316
+ }
317
+ ```
318
+
319
+ **Error hierarchy:**
320
+
321
+ ```
322
+ AgentPressError (base)
323
+ ConfigurationError -- invalid options or missing webhookSecret
324
+ HttpError -- non-2xx response (has statusCode, responseBody, url)
325
+ TimeoutError -- request exceeded timeout
326
+ WebhookSignatureError -- invalid/expired signature (from verifyOrThrow only)
327
+ ```
328
+
329
+ ## Exported Types
330
+
331
+ ```typescript
332
+ import type {
333
+ ActionCallbackPayload, // Inbound webhook payload from constructEvent()
334
+ ActionEventType, // "action.pending_approval" | "action.approved" | ...
335
+ ActionManageResponse, // Response from actions.approve() / actions.reject()
336
+ ActionStatus, // "pending" | "staged" | "approved" | "rejected" | "completed" | "failed" | "expired"
337
+ AgentPressOptions, // Constructor options
338
+ AgentResponse, // Agent text response + tool calls
339
+ ApproveActionParams, // actions.approve() params
340
+ RejectActionParams, // actions.reject() params
341
+ StagedToolCall, // Tool call awaiting approval
342
+ ToolCallResult, // Individual tool call (name, arguments, result)
343
+ WebhookResponse, // Response from send
344
+ WebhookSendParams, // send params
345
+ WebhookVerifyParams, // verify / verifyOrThrow / constructEvent params
346
+ } from "@agentpress/sdk";
347
+ ```
348
+
349
+ ## Full Example: Receiving Action Callbacks
350
+
351
+ ```typescript
352
+ import express from "express";
353
+ import { AgentPress, WebhookSignatureError, type ActionCallbackPayload } from "@agentpress/sdk";
354
+
355
+ const app = express();
356
+ const client = new AgentPress({ webhookSecret: process.env.WEBHOOK_SECRET });
357
+
358
+ // Recommended: use constructEvent() for verify + parse in one step
359
+ app.post("/webhooks/agentpress", express.raw({ type: "application/json" }), (req, res) => {
360
+ let event: ActionCallbackPayload;
361
+ try {
362
+ event = client.webhooks.constructEvent({
363
+ payload: req.body,
364
+ headers: {
365
+ "svix-id": req.headers["svix-id"] as string,
366
+ "svix-timestamp": req.headers["svix-timestamp"] as string,
367
+ "svix-signature": req.headers["svix-signature"] as string,
368
+ },
369
+ });
370
+ } catch (error) {
371
+ if (error instanceof WebhookSignatureError) {
372
+ return res.status(401).json({ error: "Invalid signature" });
373
+ }
374
+ throw error;
375
+ }
376
+
377
+ // event is fully typed as ActionCallbackPayload
378
+ console.log(`Action ${event.actionId} ${event.status}`);
379
+ if (event.agentResponse.text) {
380
+ console.log("Agent said:", event.agentResponse.text);
381
+ }
382
+
383
+ res.json({ received: true });
384
+ });
385
+ ```
386
+
387
+ ## File Structure
388
+
389
+ ```
390
+ packages/sdk/src/
391
+ index.ts -- Public barrel export
392
+ client.ts -- AgentPress class, option validation + resolution
393
+ http.ts -- HttpClient (fetch wrapper with timeout, hooks, error parsing)
394
+ errors.ts -- Error class hierarchy
395
+ types.ts -- All exported types and interfaces
396
+ utils.ts -- randomMessageId() helper (msg_<uuid>)
397
+ actions/
398
+ client.ts -- ActionsClient (approve, reject)
399
+ webhooks/
400
+ client.ts -- WebhooksClient (send, verify, verifyOrThrow, constructEvent)
401
+ signing.ts -- HMAC-SHA256 Svix-compatible sign + verify functions
402
+ ```