@agentpress/sdk 0.4.10 → 0.4.12
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/dist/index.cjs.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["SIGNATURE_PREFIX","joseErrors","verifySig","verifyKeyRotationImpl"],"sources":["../src/errors.ts","../src/utils.ts","../src/webhooks/signing.ts","../src/actions/client.ts","../src/http.ts","../src/partners/client.ts","../src/userApprovals/client.ts","../src/webhooks/keyRotation.ts","../src/webhooks/client.ts","../src/client.ts","../src/types.ts"],"sourcesContent":["/**\n * Base error class for all SDK errors. Catch this to handle any error\n * thrown by the AgentPress SDK regardless of specific type.\n */\nexport class AgentPressError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentPressError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown at construction time when `AgentPressOptions` contains invalid values\n * (e.g., non-positive timeout, malformed `webhookSecret`).\n */\nexport class ConfigurationError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when the API returns a non-2xx HTTP response.\n *\n * Properties:\n * - `statusCode` - HTTP status code (e.g., 401, 404, 500)\n * - `responseBody` - Raw response body text for debugging\n * - `url` - The full request URL that failed\n */\nexport class HttpError extends AgentPressError {\n public readonly statusCode: number;\n public readonly responseBody: string;\n public readonly url: string;\n\n constructor(statusCode: number, responseBody: string, url: string) {\n super(`HTTP ${statusCode} from ${url}`);\n this.name = \"HttpError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n this.url = url;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a request exceeds the configured `timeout` (default 30s). */\nexport class TimeoutError extends AgentPressError {\n constructor(url: string, timeout: number) {\n super(`Request to ${url} timed out after ${timeout}ms`);\n this.name = \"TimeoutError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown by {@link WebhooksClient.verifyOrThrow} when an inbound webhook signature is invalid or expired. */\nexport class WebhookSignatureError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookSignatureError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link PartnerTokenError}. Maps 1:1 to RFC 6750 `error_description` values. */\nexport type PartnerTokenErrorReason =\n | \"signature_invalid\"\n | \"issuer_mismatch\"\n | \"audience_mismatch\"\n | \"expired\"\n | \"not_yet_valid\"\n | \"missing_claim\"\n | \"ext_provider_mismatch\"\n | \"algorithm_not_allowed\"\n | \"kid_missing_or_unknown\"\n | \"malformed\";\n\n/**\n * Thrown by {@link PartnersClient.verifyToken} when a Partner MCP Spec v1 JWT\n * fails verification. Partners map `reason` to their RFC 6750 `WWW-Authenticate`\n * response (`401 invalid_token` for all reasons in this class).\n */\nexport class PartnerTokenError extends AgentPressError {\n public readonly reason: PartnerTokenErrorReason;\n\n constructor(reason: PartnerTokenErrorReason, message: string) {\n super(message);\n this.name = \"PartnerTokenError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link KeyRotationVerifyError}. */\nexport type KeyRotationVerifyErrorReason =\n | \"invalid_signature\"\n | \"invalid_signature_format\"\n | \"timestamp_out_of_window\"\n | \"invalid_timestamp\"\n | \"payload_too_large\"\n | \"malformed_payload\";\n\n/**\n * Thrown by {@link WebhooksClient.verifyKeyRotation} when a `signing_key_rotation`\n * webhook fails HMAC / timestamp / payload validation.\n */\nexport class KeyRotationVerifyError extends AgentPressError {\n public readonly reason: KeyRotationVerifyErrorReason;\n\n constructor(reason: KeyRotationVerifyErrorReason, message: string) {\n super(message);\n this.name = \"KeyRotationVerifyError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nexport function randomMessageId(): string {\n return `msg_${randomUUID()}`;\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nconst SIGNATURE_PREFIX = \"v1,\";\nconst DEFAULT_TOLERANCE_SECONDS = 5 * 60; // 5 minutes\n\n/**\n * Sign a webhook payload using Svix-compatible HMAC-SHA256.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param msgId - Unique message ID (e.g., \"msg_<uuid>\")\n * @param timestamp - Unix timestamp in seconds\n * @param body - JSON stringified payload\n * @returns Signature string in format \"v1,<base64>\"\n */\nexport function sign(\n secret: string,\n msgId: string,\n timestamp: number,\n body: string,\n): string {\n const secretBytes = Buffer.from(secret.replace(/^whsec_/, \"\"), \"base64\");\n const message = `${msgId}.${timestamp}.${body}`;\n const signature = createHmac(\"sha256\", secretBytes)\n .update(message)\n .digest(\"base64\");\n return `${SIGNATURE_PREFIX}${signature}`;\n}\n\n/**\n * Verify a Svix webhook signature.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param payload - Raw request body (string or Buffer)\n * @param headers - Svix headers object\n * @param toleranceSeconds - Max age of signature in seconds (default: 5 min)\n * @returns true if valid, false if invalid or expired\n */\nexport function verify(\n secret: string,\n payload: string | Buffer,\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n },\n toleranceSeconds: number = DEFAULT_TOLERANCE_SECONDS,\n): boolean {\n const msgId = headers[\"svix-id\"];\n const timestampStr = headers[\"svix-timestamp\"];\n const signatureHeader = headers[\"svix-signature\"];\n\n const timestamp = parseInt(timestampStr, 10);\n if (Number.isNaN(timestamp)) return false;\n\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > toleranceSeconds) return false;\n\n const body =\n typeof payload === \"string\" ? payload : payload.toString(\"utf-8\");\n const expected = sign(secret, msgId, timestamp, body);\n\n const signatures = signatureHeader.split(\" \");\n const expectedBuf = Buffer.from(expected);\n\n for (const sig of signatures) {\n const sigBuf = Buffer.from(sig);\n if (\n sigBuf.length === expectedBuf.length &&\n timingSafeEqual(sigBuf, expectedBuf)\n ) {\n return true;\n }\n }\n\n return false;\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionManageResponse,\n ApproveActionParams,\n RejectActionParams,\n ResolvedOptions,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for programmatically approving or rejecting staged actions.\n * Uses HMAC-SHA256 signing (Svix-compatible), identical to {@link WebhooksClient}.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Approve a staged action\n * await client.actions.approve(\"act_123\", {\n * action: \"my_webhook_action\",\n * });\n *\n * // Reject with a reason\n * await client.actions.reject(\"act_456\", {\n * action: \"my_webhook_action\",\n * reason: \"Insufficient data\",\n * });\n * ```\n */\nexport class ActionsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Approve a staged action, optionally modifying the tool call.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async approve(\n actionId: string,\n params: ApproveActionParams,\n ): Promise<ActionManageResponse> {\n const body: Record<string, unknown> = {};\n if (params.editedToolCall !== undefined) {\n body.editedToolCall = params.editedToolCall;\n }\n if (params.remember !== undefined) {\n body.remember = params.remember;\n }\n return this.manage(actionId, params.action, \"approve\", body);\n }\n\n /**\n * Reject a staged action.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async reject(\n actionId: string,\n params: RejectActionParams,\n ): Promise<ActionManageResponse> {\n return this.manage(actionId, params.action, \"reject\", {\n reason: params.reason,\n });\n }\n\n private async manage(\n actionId: string,\n webhookAction: string,\n operation: \"approve\" | \"reject\",\n body: Record<string, unknown>,\n ): Promise<ActionManageResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for action management operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${webhookAction}/manage/${actionId}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<ActionManageResponse>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { AgentPressError, HttpError, TimeoutError } from \"./errors\";\nimport type { ResolvedOptions } from \"./types\";\n\n/**\n * Internal shared HTTP client. Not part of the public API -- used by\n * namespace clients (e.g., `WebhooksClient`) to make authenticated requests.\n * @internal\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly onRequest?: ResolvedOptions[\"onRequest\"];\n private readonly onResponse?: ResolvedOptions[\"onResponse\"];\n\n constructor(options: ResolvedOptions) {\n this.baseUrl = options.baseUrl;\n this.timeout = options.timeout;\n this.onRequest = options.onRequest;\n this.onResponse = options.onResponse;\n }\n\n /**\n * Send an HTTP request to the API. Constructs the full URL from `baseUrl` + `path`,\n * applies the configured timeout via `AbortSignal`, fires `onRequest`/`onResponse`\n * hooks, and parses the JSON response.\n *\n * @throws {TimeoutError} If the request exceeds the configured timeout.\n * @throws {HttpError} If the API returns a non-2xx status code.\n * @throws {AgentPressError} On network failures or non-JSON responses.\n */\n async request<T>(path: string, init: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers = new Headers(init.headers);\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const requestInit: RequestInit = {\n ...init,\n headers,\n signal: AbortSignal.timeout(this.timeout),\n };\n\n this.onRequest?.(url, requestInit);\n\n let response: Response;\n try {\n response = await fetch(url, requestInit);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n (error.name === \"TimeoutError\" || error.name === \"AbortError\")\n ) {\n throw new TimeoutError(url, this.timeout);\n }\n const message =\n error instanceof Error ? error.message : \"Unknown fetch error\";\n throw new AgentPressError(`Request to ${url} failed: ${message}`);\n }\n\n this.onResponse?.(url, response.clone());\n\n const text = await response.text();\n\n if (!response.ok) {\n throw new HttpError(response.status, text, url);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new AgentPressError(\n `Expected JSON response from ${url} but received: ${text.slice(0, 200)}`,\n );\n }\n }\n}\n","import {\n createRemoteJWKSet,\n type JWTVerifyGetKey,\n errors as joseErrors,\n jwtVerify,\n} from \"jose\";\n\nimport { ConfigurationError, PartnerTokenError } from \"../errors\";\nimport type {\n PartnerTokenClaims,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"../types\";\n\nconst ALGORITHMS = [\"EdDSA\"] as const;\n\ntype RemoteJwks = ReturnType<typeof createRemoteJWKSet>;\n\n/**\n * Client for Partner MCP Spec v1 helpers. Created automatically when\n * {@link AgentPressOptions.partnerMcp} is provided.\n *\n * State (JWKS cache) is per-instance, NOT module-global, so staging and\n * production clients can run side-by-side without cross-talk.\n */\nexport class PartnersClient {\n private readonly options: ResolvedOptions;\n private readonly partnerMcp: ResolvedPartnerMcpOptions | undefined;\n private jwks: RemoteJwks | null = null;\n private jwksKeyFn: JWTVerifyGetKey | null = null;\n\n constructor(options: ResolvedOptions) {\n this.options = options;\n this.partnerMcp = options.partnerMcp;\n }\n\n /**\n * Verify an inbound Partner MCP Spec v1 JWT against AgentPress's JWKS.\n *\n * Enforces the full spec: `algorithms: [\"EdDSA\"]` pinned; `iss`, `aud`,\n * `ext_provider` validated; `sub`, `jti`, `scope` required and non-empty;\n * `kid` header required; `exp` / `iat` validated with ±30s skew (configurable).\n *\n * @param token - Bare JWT string (no `Bearer ` prefix).\n * @returns Typed {@link PartnerTokenClaims}.\n * @throws {PartnerTokenError} with a typed `reason` for RFC 6750 mapping.\n * @throws {ConfigurationError} if `partnerMcp` is not configured.\n */\n async verifyToken(token: string): Promise<PartnerTokenClaims> {\n const cfg = this.requireConfig();\n const jwks = this.getJwks();\n\n let payload: Record<string, unknown>;\n let protectedHeader: { alg?: string; kid?: string; typ?: string };\n\n try {\n const result = await jwtVerify(token, jwks, {\n algorithms: [...ALGORITHMS],\n issuer: cfg.issuer,\n audience: cfg.audience,\n clockTolerance: cfg.clockTolerance,\n });\n payload = result.payload as Record<string, unknown>;\n protectedHeader = result.protectedHeader as {\n alg?: string;\n kid?: string;\n typ?: string;\n };\n } catch (err) {\n throw mapJoseError(err);\n }\n\n // kid header required by spec. jose does not enforce this on its own\n // when the key is resolvable — we enforce it explicitly so forged\n // tokens that elide the kid header can't slip through on a single-key\n // JWKS.\n if (!protectedHeader.kid || typeof protectedHeader.kid !== \"string\") {\n throw new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"JWT header missing required 'kid'\",\n );\n }\n\n const claims = payload as PartnerTokenClaims & Record<string, unknown>;\n\n // jose's jwtVerify checks `exp` (with clockTolerance) but not `iat`\n // future-time unless `maxTokenAge` is set. The spec requires both sides\n // of the skew window, so enforce the future-iat check explicitly.\n if (typeof claims.iat !== \"number\" || !Number.isFinite(claims.iat)) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'iat' claim must be a number\",\n );\n }\n const toleranceSeconds = toSeconds(cfg.clockTolerance);\n const nowSec = Math.floor(Date.now() / 1000);\n if (claims.iat - nowSec > toleranceSeconds) {\n throw new PartnerTokenError(\n \"not_yet_valid\",\n `'iat' is ${claims.iat - nowSec}s in the future, beyond ${toleranceSeconds}s tolerance`,\n );\n }\n\n if (typeof claims.sub !== \"string\" || claims.sub.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'sub' claim is required\");\n }\n if (typeof claims.jti !== \"string\" || claims.jti.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'jti' claim is required\");\n }\n if (typeof claims.scope !== \"string\") {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'scope' claim must be a string\",\n );\n }\n if (\n typeof claims.ext_provider !== \"string\" ||\n claims.ext_provider.length === 0\n ) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'ext_provider' claim is required\",\n );\n }\n if (claims.ext_provider !== cfg.expectedExtProvider) {\n throw new PartnerTokenError(\n \"ext_provider_mismatch\",\n `ext_provider '${claims.ext_provider}' does not match expected '${cfg.expectedExtProvider}'`,\n );\n }\n\n return claims;\n }\n\n /**\n * Force the JWKS cache to refetch immediately. Call this from your\n * `signing_key_rotation` webhook handler after verifying the webhook —\n * otherwise the cache picks up new keys on the next `kid` miss (which\n * works, but with one failed verify latency penalty).\n */\n async refreshJwks(): Promise<void> {\n const jwks = this.getJwks();\n // jose's RemoteJWKSet exposes `.reload()` for exactly this use case.\n const anyJwks = jwks as unknown as { reload?: () => Promise<void> };\n if (typeof anyJwks.reload === \"function\") {\n await anyJwks.reload();\n }\n }\n\n private requireConfig(): ResolvedPartnerMcpOptions {\n if (!this.partnerMcp) {\n throw new ConfigurationError(\n \"partnerMcp options are required for partner token operations\",\n );\n }\n return this.partnerMcp;\n }\n\n private getJwks(): RemoteJwks {\n const cfg = this.requireConfig();\n if (!this.jwks) {\n this.jwks = createRemoteJWKSet(new URL(cfg.jwksUrl), {\n cacheMaxAge: cfg.jwksCacheMaxAgeMs,\n cooldownDuration: 30_000,\n });\n this.jwksKeyFn = this.jwks as unknown as JWTVerifyGetKey;\n }\n return this.jwks;\n }\n}\n\nfunction toSeconds(tolerance: string | number): number {\n if (typeof tolerance === \"number\") return tolerance;\n const match = tolerance.trim().match(/^(\\d+)\\s*(s|m|h)$/i);\n if (!match) return 30;\n const n = Number.parseInt(match[1] as string, 10);\n const unit = (match[2] as string).toLowerCase();\n if (unit === \"s\") return n;\n if (unit === \"m\") return n * 60;\n if (unit === \"h\") return n * 3600;\n return 30;\n}\n\nfunction mapJoseError(err: unknown): PartnerTokenError {\n if (err instanceof PartnerTokenError) return err;\n\n if (err instanceof joseErrors.JWSSignatureVerificationFailed) {\n return new PartnerTokenError(\n \"signature_invalid\",\n \"JWT signature verification failed\",\n );\n }\n if (err instanceof joseErrors.JWKSNoMatchingKey) {\n return new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"No JWKS key matches the JWT 'kid' header\",\n );\n }\n if (err instanceof joseErrors.JOSEAlgNotAllowed) {\n return new PartnerTokenError(\n \"algorithm_not_allowed\",\n \"JWT 'alg' is not EdDSA\",\n );\n }\n if (err instanceof joseErrors.JWTExpired) {\n return new PartnerTokenError(\"expired\", \"JWT has expired\");\n }\n if (err instanceof joseErrors.JWTClaimValidationFailed) {\n const claim = (err as { claim?: string }).claim;\n if (claim === \"iss\") {\n return new PartnerTokenError(\n \"issuer_mismatch\",\n \"JWT 'iss' does not match expected issuer\",\n );\n }\n if (claim === \"aud\") {\n return new PartnerTokenError(\n \"audience_mismatch\",\n \"JWT 'aud' does not match expected audience\",\n );\n }\n if (claim === \"iat\") {\n return new PartnerTokenError(\n \"not_yet_valid\",\n \"JWT 'iat' is in the future beyond clock tolerance\",\n );\n }\n return new PartnerTokenError(\n \"missing_claim\",\n err.message || \"Claim validation failed\",\n );\n }\n if (\n err instanceof joseErrors.JWTInvalid ||\n err instanceof joseErrors.JWSInvalid\n ) {\n return new PartnerTokenError(\"malformed\", err.message || \"Malformed JWT\");\n }\n if (err instanceof Error) {\n return new PartnerTokenError(\"malformed\", err.message);\n }\n return new PartnerTokenError(\"malformed\", String(err));\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n CreateUserApprovalParams,\n DeleteUserApprovalParams,\n ListUserApprovalsParams,\n ListUserApprovalsResponse,\n ResolvedOptions,\n UpdateUserApprovalParams,\n UserToolApproval,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for managing per-user auto-approval rules — the SDK equivalent of the\n * console's `/account/auto-approvals` settings page. Uses HMAC-SHA256 signing\n * (Svix-compatible), identical to {@link ActionsClient.manage}.\n *\n * Each call is scoped to a single webhook (identified by `webhookIdentifier`),\n * which both selects the signing secret and scopes which approvals are visible.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Provision consent so future \"sendEmail\" triggers skip the approval prompt\n * await client.userApprovals.create({\n * webhookIdentifier: \"reviews\",\n * userId: \"user-uuid\",\n * actionWebhookId: \"webhook-uuid\",\n * toolName: \"sendEmail\",\n * mode: \"always_allow\",\n * });\n *\n * // List rules (optionally filtered by userId)\n * const { approvals } = await client.userApprovals.list({\n * webhookIdentifier: \"reviews\",\n * });\n *\n * // Revoke\n * await client.userApprovals.delete(approvalId, { webhookIdentifier: \"reviews\" });\n * ```\n */\nexport class UserApprovalsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * List auto-approval rules for a webhook. Optionally filter by `userId`.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async list(\n params: ListUserApprovalsParams,\n ): Promise<ListUserApprovalsResponse> {\n const body: Record<string, unknown> = {};\n if (params.userId !== undefined) body.userId = params.userId;\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n return this.send<ListUserApprovalsResponse>(\n params.webhookIdentifier,\n \"list\",\n body,\n );\n }\n\n /**\n * Create (or upsert) an auto-approval rule. If a rule with the same\n * `(userId, actionWebhookId, toolName)` triple already exists, it is\n * updated in place.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async create(params: CreateUserApprovalParams): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {\n userId: params.userId,\n actionWebhookId: params.actionWebhookId,\n toolName: params.toolName,\n mode: params.mode ?? \"always_allow\",\n };\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n \"create\",\n body,\n );\n }\n\n /**\n * Patch an existing auto-approval rule (change mode or expiry).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async update(\n id: string,\n params: UpdateUserApprovalParams,\n ): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {};\n if (params.mode !== undefined) body.mode = params.mode;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n `update/${id}`,\n body,\n );\n }\n\n /**\n * Revoke an auto-approval rule. Future triggers of the corresponding\n * `(user, webhook, tool)` combination will once again stage for approval.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async delete(\n id: string,\n params: DeleteUserApprovalParams,\n ): Promise<{ success: boolean }> {\n return this.send<{ success: boolean }>(\n params.webhookIdentifier,\n `delete/${id}`,\n {},\n );\n }\n\n /** Internal: HMAC-sign and POST the body to the scoped path. */\n private async send<T>(\n webhookIdentifier: string,\n operation: string,\n body: Record<string, unknown>,\n ): Promise<T> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for user approval management operations\",\n );\n }\n\n const path = `/webhooks/user-approvals/${this.options.org}/${webhookIdentifier}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<T>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nimport { ConfigurationError, KeyRotationVerifyError } from \"../errors\";\nimport type { KeyRotationEvent, KeyRotationVerifyParams } from \"../types\";\n\nconst MAX_PAYLOAD_BYTES = 8 * 1024; // 8 KB\nconst TIMESTAMP_SKEW_SECONDS = 300; // 5 minutes\nconst SIGNATURE_PREFIX = \"sha256=\";\n\n/**\n * Verify a `signing_key_rotation` webhook signed by AgentPress with\n * HMAC-SHA256 over the raw request body. Returns the typed\n * {@link KeyRotationEvent} payload.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping.\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\nexport function verifyKeyRotation(\n secret: string | undefined,\n params: KeyRotationVerifyParams,\n): KeyRotationEvent {\n if (!secret) {\n throw new ConfigurationError(\n \"webhookSecret is required for key rotation webhook verification\",\n );\n }\n\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n\n const byteLength =\n typeof params.payload === \"string\"\n ? Buffer.byteLength(params.payload, \"utf-8\")\n : params.payload.length;\n if (byteLength > MAX_PAYLOAD_BYTES) {\n throw new KeyRotationVerifyError(\n \"payload_too_large\",\n `Payload exceeds ${MAX_PAYLOAD_BYTES} bytes`,\n );\n }\n\n const signatureHeader = readHeader(params.headers, \"x-agentpress-signature\");\n const timestampHeader = readHeader(params.headers, \"x-agentpress-timestamp\");\n\n if (!signatureHeader?.startsWith(SIGNATURE_PREFIX)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n `Signature header missing or does not start with '${SIGNATURE_PREFIX}'`,\n );\n }\n const providedHex = signatureHeader\n .slice(SIGNATURE_PREFIX.length)\n .toLowerCase();\n if (!/^[0-9a-f]+$/.test(providedHex)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n \"Signature is not a hex string\",\n );\n }\n\n if (!timestampHeader) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp header is required\",\n );\n }\n const timestamp = Number.parseInt(timestampHeader, 10);\n if (\n !Number.isFinite(timestamp) ||\n String(timestamp) !== timestampHeader.trim()\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp is not a valid unix seconds integer\",\n );\n }\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > TIMESTAMP_SKEW_SECONDS) {\n throw new KeyRotationVerifyError(\n \"timestamp_out_of_window\",\n `Timestamp skew ${Math.abs(now - timestamp)}s exceeds ${TIMESTAMP_SKEW_SECONDS}s tolerance`,\n );\n }\n\n const expectedHex = createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n const providedBuf = Buffer.from(providedHex, \"hex\");\n const expectedBuf = Buffer.from(expectedHex, \"hex\");\n if (\n providedBuf.length !== expectedBuf.length ||\n !timingSafeEqual(providedBuf, expectedBuf)\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_signature\",\n \"HMAC signature mismatch\",\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload is not valid JSON\",\n );\n }\n\n return validatePayload(parsed);\n}\n\nfunction readHeader(\n headers: Record<string, string | undefined>,\n name: string,\n): string | undefined {\n // Headers are case-insensitive; normalize without mutating the caller's object.\n const lowered = name.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lowered && typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n\nfunction validatePayload(raw: unknown): KeyRotationEvent {\n if (!raw || typeof raw !== \"object\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload must be a JSON object\",\n );\n }\n const obj = raw as Record<string, unknown>;\n if (obj.event !== \"signing_key_rotation\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `Unexpected event '${String(obj.event)}'`,\n );\n }\n if (obj.type !== \"scheduled\" && obj.type !== \"emergency\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'type' must be 'scheduled' or 'emergency'\",\n );\n }\n for (const key of [\n \"retiredKid\",\n \"newCurrentKid\",\n \"retiredAt\",\n \"effectiveAt\",\n \"jwksUrl\",\n ]) {\n if (typeof obj[key] !== \"string\" || (obj[key] as string).length === 0) {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `'${key}' must be a non-empty string`,\n );\n }\n }\n if (obj.reason !== undefined && typeof obj.reason !== \"string\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'reason' must be a string when present\",\n );\n }\n\n const event: KeyRotationEvent = {\n event: \"signing_key_rotation\",\n type: obj.type as \"scheduled\" | \"emergency\",\n retiredKid: obj.retiredKid as string,\n newCurrentKid: obj.newCurrentKid as string,\n retiredAt: obj.retiredAt as string,\n effectiveAt: obj.effectiveAt as string,\n jwksUrl: obj.jwksUrl as string,\n };\n if (typeof obj.reason === \"string\") {\n event.reason = obj.reason;\n }\n return event;\n}\n","import {\n AgentPressError,\n ConfigurationError,\n WebhookSignatureError,\n} from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionCallbackPayload,\n KeyRotationEvent,\n KeyRotationVerifyParams,\n ResolvedOptions,\n WebhookResponse,\n WebhookSendParams,\n WebhookVerifyParams,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { verifyKeyRotation as verifyKeyRotationImpl } from \"./keyRotation\";\nimport { sign, verify as verifySig } from \"./signing\";\n\nexport class WebhooksClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Send an arbitrary webhook payload to AgentPress.\n * Signs the payload with HMAC-SHA256 (Svix-compatible).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async send(params: WebhookSendParams): Promise<WebhookResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${params.action}`;\n const body = JSON.stringify(params.payload);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(this.options.webhookSecret, msgId, timestamp, body);\n\n return this.http.request<WebhookResponse>(path, {\n method: \"POST\",\n body,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n\n /**\n * Verify an inbound Svix webhook signature.\n *\n * @returns true if valid, false if invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verify(params: WebhookVerifyParams): boolean {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook verification\",\n );\n }\n\n return verifySig(\n this.options.webhookSecret,\n params.payload,\n params.headers,\n );\n }\n\n /**\n * Verify an inbound Svix webhook signature, throwing on failure.\n * Useful for middleware patterns where invalid signatures should halt processing.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verifyOrThrow(params: WebhookVerifyParams): void {\n if (!this.verify(params)) {\n throw new WebhookSignatureError(\"Invalid webhook signature\");\n }\n }\n\n /**\n * Verify and parse an inbound webhook from AgentPress.\n * Combines signature verification with JSON parsing and type casting.\n * This is the recommended way to handle incoming webhooks.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws AgentPressError if payload is not valid JSON\n */\n constructEvent(params: WebhookVerifyParams): ActionCallbackPayload {\n this.verifyOrThrow(params);\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n try {\n return JSON.parse(body) as ActionCallbackPayload;\n } catch {\n throw new AgentPressError(\"Webhook payload is not valid JSON\");\n }\n }\n\n /**\n * Verify an inbound `signing_key_rotation` webhook (HMAC-SHA256 + timestamp\n * + typed payload) from AgentPress. See the Partner MCP Spec v1 for the\n * full contract.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping\n * (401 for signature errors, 400 for malformed payload, 413 for oversize).\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\n verifyKeyRotation(params: KeyRotationVerifyParams): KeyRotationEvent {\n return verifyKeyRotationImpl(this.options.webhookSecret, params);\n }\n}\n","import { ActionsClient } from \"./actions/client\";\nimport { ConfigurationError } from \"./errors\";\nimport { HttpClient } from \"./http\";\nimport { PartnersClient } from \"./partners/client\";\nimport type {\n AgentPressOptions,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"./types\";\nimport { UserApprovalsClient } from \"./userApprovals/client\";\nimport { WebhooksClient } from \"./webhooks/client\";\n\n/**\n * Main entry point for the AgentPress SDK. Provides namespaced access to API\n * resources (e.g., `client.webhooks.send()`, `client.actions.approve()`).\n * Validates all configuration options at construction time, so invalid config fails fast.\n *\n * @example\n * ```ts\n * const client = new AgentPress({\n * apiKey: \"ak_...\",\n * webhookSecret: \"whsec_...\",\n * });\n * await client.webhooks.send({ action: \"my_action\", payload: { ... } });\n * await client.actions.approve(\"act_123\", { action: \"my_action\" });\n * ```\n */\nexport class AgentPress {\n /** Webhook operations: send outbound webhooks and verify inbound signatures. */\n public readonly webhooks: WebhooksClient;\n /** Action management: approve or reject staged actions. */\n public readonly actions: ActionsClient;\n /** Per-user auto-approval rules (read / create / update / delete). */\n public readonly userApprovals: UserApprovalsClient;\n /** Partner MCP Spec v1 helpers (inbound JWT verification, JWKS refresh). */\n public readonly partners: PartnersClient;\n\n /**\n * @param options - SDK configuration. All fields are optional with sensible defaults.\n * @throws {ConfigurationError} If `timeout` is non-positive or `webhookSecret` has an invalid prefix.\n */\n constructor(options: AgentPressOptions = {}) {\n const resolved = resolveOptions(options);\n const http = new HttpClient(resolved);\n this.webhooks = new WebhooksClient(resolved, http);\n this.actions = new ActionsClient(resolved, http);\n this.userApprovals = new UserApprovalsClient(resolved, http);\n this.partners = new PartnersClient(resolved);\n }\n}\n\nfunction resolveOptions(options: AgentPressOptions): ResolvedOptions {\n const baseUrl = (options.baseUrl ?? \"https://api.agent.press\").replace(\n /\\/+$/,\n \"\",\n );\n const timeout = options.timeout ?? 30_000;\n const org = options.org ?? \"default-org\";\n\n if (timeout <= 0 || !Number.isFinite(timeout)) {\n throw new ConfigurationError(\"timeout must be a positive number\");\n }\n\n if (\n options.webhookSecret !== undefined &&\n !options.webhookSecret.startsWith(\"whsec_\")\n ) {\n throw new ConfigurationError('webhookSecret must start with \"whsec_\"');\n }\n\n return {\n baseUrl,\n timeout,\n org,\n webhookSecret: options.webhookSecret,\n apiKey: options.apiKey,\n partnerMcp: resolvePartnerMcp(options.partnerMcp),\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n };\n}\n\nfunction resolvePartnerMcp(\n options: AgentPressOptions[\"partnerMcp\"],\n): ResolvedPartnerMcpOptions | undefined {\n if (!options) return undefined;\n\n if (typeof options.jwksUrl !== \"string\" || options.jwksUrl.length === 0) {\n throw new ConfigurationError(\"partnerMcp.jwksUrl is required\");\n }\n try {\n // Validate early so a bad URL fails at construction, not on first verify.\n new URL(options.jwksUrl);\n } catch {\n throw new ConfigurationError(\"partnerMcp.jwksUrl must be a valid URL\");\n }\n if (typeof options.issuer !== \"string\" || options.issuer.length === 0) {\n throw new ConfigurationError(\"partnerMcp.issuer is required\");\n }\n if (typeof options.audience !== \"string\" || options.audience.length === 0) {\n throw new ConfigurationError(\"partnerMcp.audience is required\");\n }\n if (\n typeof options.expectedExtProvider !== \"string\" ||\n options.expectedExtProvider.length === 0\n ) {\n throw new ConfigurationError(\"partnerMcp.expectedExtProvider is required\");\n }\n\n const clockTolerance = options.clockTolerance ?? \"30s\";\n const jwksCacheMaxAgeMs = options.jwksCacheMaxAgeMs ?? 3_600_000;\n if (jwksCacheMaxAgeMs <= 0 || !Number.isFinite(jwksCacheMaxAgeMs)) {\n throw new ConfigurationError(\n \"partnerMcp.jwksCacheMaxAgeMs must be a positive number\",\n );\n }\n\n return {\n jwksUrl: options.jwksUrl,\n issuer: options.issuer,\n audience: options.audience,\n expectedExtProvider: options.expectedExtProvider,\n clockTolerance,\n jwksCacheMaxAgeMs,\n };\n}\n","/** Constructor options for the {@link AgentPress} client. All fields are optional. */\nexport interface AgentPressOptions {\n /** Svix webhook signing secret for verifying inbound webhooks. Must start with `\"whsec_\"`. */\n webhookSecret?: string;\n /** API key for authenticated requests. */\n apiKey?: string;\n /** @default \"https://api.agent.press\" */\n baseUrl?: string;\n /** Request timeout in milliseconds. Must be a positive finite number. @default 30000 */\n timeout?: number;\n /** Organization identifier sent with requests. @default \"default-org\" */\n org?: string;\n /**\n * Partner MCP Spec v1 configuration. Required only if you call\n * {@link PartnersClient.verifyToken} or {@link WebhooksClient.verifyKeyRotation}.\n *\n * Each environment (staging / production) needs its own {@link AgentPress}\n * instance with its own `partnerMcp` block — never share a client between\n * environments. JWKS cache state is per-instance, so side-by-side staging\n * and prod clients have no cross-talk.\n */\n partnerMcp?: PartnerMcpOptions;\n /** Hook called before every outbound HTTP request (useful for logging/tracing). */\n onRequest?: (url: string, init: RequestInit) => void;\n /** Hook called after every HTTP response is received. */\n onResponse?: (url: string, response: Response) => void;\n}\n\n/** Partner MCP Spec v1 configuration. See {@link AgentPressOptions.partnerMcp}. */\nexport interface PartnerMcpOptions {\n /**\n * Full URL to the issuing AgentPress org's JWKS.\n * Per-org as of Partner MCP Spec v1 (per-org signing keys), e.g.\n * `https://api.agent.press/orgs/<org-slug>/.well-known/jwks.json`.\n * The org admin who registered you as a partner will give you the\n * exact URL along with their `<org-slug>`.\n */\n jwksUrl: string;\n /**\n * Exact match for the JWT `iss` claim. Per-org scoped, e.g.\n * `https://api.agent.press/orgs/<org-slug>`. The JWKS URL above is\n * always `<issuer>/.well-known/jwks.json`.\n */\n issuer: string;\n /** Exact match for the JWT `aud` claim — your partner MCP's stable URL. */\n audience: string;\n /** Required value for the `ext_provider` claim, e.g. `\"localfalcon\"`. */\n expectedExtProvider: string;\n /**\n * Clock skew tolerance for `iat` / `exp` validation. Accepts a jose duration\n * string (`\"30s\"`, `\"1m\"`) or a number of seconds.\n * @default \"30s\"\n */\n clockTolerance?: string | number;\n /**\n * JWKS cache max age in milliseconds. Cache is per-instance, not module-global.\n * @default 3_600_000 (1 hour)\n */\n jwksCacheMaxAgeMs?: number;\n}\n\n/** A verified Partner MCP Spec v1 JWT claim set. */\nexport interface PartnerTokenClaims {\n /** The external user id (verified non-empty). */\n sub: string;\n /** Space-separated scope string, per RFC 8693. May be empty but always present. */\n scope: string;\n /** External auth provider name; verified against {@link PartnerMcpOptions.expectedExtProvider}. */\n ext_provider: string;\n /** Unique token id. Non-empty. Partners build replay caches keyed by this. */\n jti: string;\n /** Already validated against {@link PartnerMcpOptions.issuer}; returned for audit logs. */\n iss: string;\n /** Already validated against {@link PartnerMcpOptions.audience}; returned for audit logs. */\n aud: string;\n /** Unix seconds. */\n iat: number;\n /** Unix seconds. */\n exp: number;\n /** AgentPress org identifier, optional. */\n org_id?: string;\n /** AgentPress thread identifier, optional. */\n thread_id?: string;\n /** Reserved for multi-tenant partner flows. */\n settings_id?: string;\n /** Forward-compat: any additional claims pass through. */\n [key: string]: unknown;\n}\n\n/** Parameters for {@link WebhooksClient.verifyKeyRotation}. */\nexport interface KeyRotationVerifyParams {\n /** Raw request body (string or Buffer) — must not be parsed/modified. */\n payload: string | Buffer;\n /**\n * Incoming HTTP headers. Accepts plain `Record<string, string | undefined>`\n * so Hono / Fastify / Express / Fetch / Worker all work interchangeably.\n * Must include `x-agentpress-signature` and `x-agentpress-timestamp`.\n */\n headers: Record<string, string | undefined>;\n}\n\n/** A verified `signing_key_rotation` webhook payload. */\nexport interface KeyRotationEvent {\n event: \"signing_key_rotation\";\n type: \"scheduled\" | \"emergency\";\n retiredKid: string;\n newCurrentKid: string;\n /** ISO 8601 timestamp. */\n retiredAt: string;\n /** ISO 8601 timestamp. */\n effectiveAt: string;\n /** Matches the configured partner JWKS URL. */\n jwksUrl: string;\n /** Present only on `type: \"emergency\"` rotations. */\n reason?: string;\n}\n\n/** Parameters for {@link WebhooksClient.send}. */\nexport interface WebhookSendParams {\n /** Webhook action name (matches an action rule on the server). */\n action: string;\n /** Arbitrary payload data forwarded to the webhook handler. */\n payload: Record<string, unknown>;\n}\n\n/** Parameters for verifying an inbound webhook signature via {@link WebhooksClient.verify} or {@link WebhooksClient.verifyOrThrow}. */\nexport interface WebhookVerifyParams {\n /** Raw request body (string or Buffer) -- must not be parsed/modified. */\n payload: string | Buffer;\n /** Svix signature headers from the incoming request. */\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n };\n}\n\n/** Response from webhook send operations. */\nexport interface WebhookResponse {\n success: boolean;\n /** UUID of the created action (present on successful creation). */\n actionId?: string;\n /** `true` if an action with the same `externalId` already existed (idempotency). */\n alreadyExists?: boolean;\n skipped?: boolean;\n data?: Record<string, unknown>;\n}\n\n// ── Action Lifecycle Event Types ────────────────────────────────────\n\n/** Action lifecycle event types emitted by AgentPress. */\nexport type ActionEventType =\n | \"action.pending_approval\"\n | \"action.approved\"\n | \"action.completed\"\n | \"action.failed\"\n | \"action.rejected\"\n | \"action.expired\";\n\n/** All public action callback event types emitted by AgentPress. */\nexport const ACTION_EVENT_TYPES: readonly ActionEventType[] = [\n \"action.pending_approval\",\n \"action.approved\",\n \"action.completed\",\n \"action.failed\",\n \"action.rejected\",\n \"action.expired\",\n] as const;\n\n/** Structured approval summary for a staged tool call. */\nexport interface StagedToolCallSummary {\n /** Short action phrase, suitable for headings. */\n title: string;\n /** Full approval request sentence with the key action details. */\n detail: string;\n}\n\n/** A tool call staged for approval lifecycle callbacks. */\nexport interface StagedToolCall {\n toolName: string;\n toolCallId: string;\n arguments: Record<string, unknown>;\n /**\n * Generated approval summary. New callbacks use the structured shape; legacy\n * callbacks may contain a plain string.\n */\n summary?: string | StagedToolCallSummary;\n}\n\n/** Parameters for {@link ActionsClient.approve}. */\nexport interface ApproveActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Optionally modify the tool call arguments before execution. */\n editedToolCall?: {\n toolName: string;\n arguments: Record<string, unknown>;\n };\n /**\n * If `\"webhook\"`, also auto-approves future triggers of the same\n * `(user, webhook, tool)` combination — same effect as the UI's\n * \"Always allow for this webhook\" option.\n *\n * - `\"once\"` — approve only this action (default behavior).\n * - `\"webhook\"` — approve and remember for future triggers.\n */\n remember?: \"once\" | \"webhook\";\n}\n\n/** Parameters for {@link ActionsClient.reject}. */\nexport interface RejectActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Reason for rejection. */\n reason?: string;\n}\n\n/** Response from action approve/reject operations. */\nexport interface ActionManageResponse {\n success: boolean;\n actionId: string;\n status: ActionStatus;\n}\n\n// ── Outbound Webhook (Action Callback) Types ──────────────────────────\n\n/** Status of an action in the AgentPress system. */\nexport type ActionStatus =\n | \"pending\"\n | \"staged\"\n | \"approved\"\n | \"executing\"\n | \"rejected\"\n | \"completed\"\n | \"failed\"\n | \"expired\";\n\n/** A tool call made by the agent during action processing. */\nexport interface ToolCallResult {\n toolName: string;\n arguments: Record<string, unknown>;\n result: unknown;\n}\n\n/** The agent's response after processing an action. */\nexport interface AgentResponse {\n /** The agent's text response, if any. */\n text: string | null;\n /** Tool calls made by the agent during processing. */\n toolCalls: ToolCallResult[];\n}\n\n/**\n * Payload received from AgentPress outbound webhooks (post-event callbacks).\n * This is what your server receives for approval, terminal, and failure events.\n */\nexport interface ActionCallbackPayload {\n actionId: string;\n status: ActionStatus;\n actionType: string;\n /** Lifecycle event type (e.g., \"action.pending_approval\", \"action.completed\"). */\n eventType: ActionEventType;\n /** Webhook action identifier used to create this action. Needed for approve/reject. */\n webhookAction: string | null;\n /** Tool staged for approval lifecycle events when available. */\n stagedToolCall: StagedToolCall | null;\n /** ISO 8601 timestamp of when this callback event occurred. */\n occurredAt: string;\n /** ISO 8601 timestamp retained for backwards compatibility. */\n completedAt: string;\n /** Human-readable execution summary when populated on the action. */\n resultSummary: string | null;\n /** Original data from the inbound webhook that triggered this action. */\n sourceData: Record<string, unknown>;\n /** External system identifier. */\n externalId: string | null;\n /** AgentPress user ID associated with this action. */\n userId: string | null;\n /** Thread ID if the action created a conversation. */\n threadId: string | null;\n /** The agent's response including text and tool call results. */\n agentResponse: AgentResponse;\n /** Error message if the action failed. */\n errorMessage: string | null;\n /** Reason provided if the action was rejected by a human reviewer. */\n rejectionReason: string | null;\n /** Additional custom fields from post-event configuration. */\n [key: string]: unknown;\n}\n\n// ── User Tool Approvals ─────────────────────────────────────────────\n\n/** Mode of a user tool approval rule. */\nexport type ApprovalMode = \"always_allow\" | \"always_deny\";\n\n/**\n * A persisted rule that auto-approves (or auto-denies) a specific\n * `(user, webhook, tool)` triple, bypassing the per-action approval prompt.\n * Dates are ISO 8601 strings on the wire.\n */\nexport interface UserToolApproval {\n id: string;\n orgId: string;\n userId: string;\n actionWebhookId: string;\n toolName: string;\n mode: ApprovalMode;\n /** ISO 8601 timestamp. `null` means never expires. */\n expiresAt: string | null;\n /** ISO 8601 timestamp. */\n createdAt: string;\n /** ISO 8601 timestamp. */\n updatedAt: string;\n}\n\n/** Parameters for {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsParams {\n /** Webhook identifier (slug) — required to scope the signing secret and the result. */\n webhookIdentifier: string;\n /**\n * Filter to a single user's approvals. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId?: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`.\n */\n authProvider?: string;\n}\n\n/** Response from {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsResponse {\n approvals: UserToolApproval[];\n}\n\n/** Parameters for {@link UserApprovalsClient.create}. */\nexport interface CreateUserApprovalParams {\n /** Webhook identifier (slug) — required to scope the signing secret. */\n webhookIdentifier: string;\n /**\n * User identifier this rule applies to. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`. The user must have authenticated through the\n * provider at least once for resolution to succeed.\n */\n authProvider?: string;\n /** UUID of the `action_webhooks` row. Must match the webhook identified by `webhookIdentifier`. */\n actionWebhookId: string;\n /** Name of the tool this rule covers. */\n toolName: string;\n /** @default \"always_allow\" */\n mode?: ApprovalMode;\n /** `null` or omitted = never expires. */\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.update}. */\nexport interface UpdateUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n mode?: ApprovalMode;\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.delete}. */\nexport interface DeleteUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n}\n\n/** @internal Resolved (validated, defaulted) options. Not exported from the public API. */\nexport interface ResolvedOptions {\n baseUrl: string;\n timeout: number;\n org: string;\n webhookSecret?: string;\n apiKey?: string;\n partnerMcp?: ResolvedPartnerMcpOptions;\n onRequest?: AgentPressOptions[\"onRequest\"];\n onResponse?: AgentPressOptions[\"onResponse\"];\n}\n\n/** @internal Resolved (validated, defaulted) partner MCP options. */\nexport interface ResolvedPartnerMcpOptions {\n jwksUrl: string;\n issuer: string;\n audience: string;\n expectedExtProvider: string;\n clockTolerance: string | number;\n jwksCacheMaxAgeMs: number;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["SIGNATURE_PREFIX","joseErrors","verifySig","verifyKeyRotationImpl"],"sources":["../src/errors.ts","../src/utils.ts","../src/webhooks/signing.ts","../src/actions/client.ts","../src/http.ts","../src/partners/client.ts","../src/userApprovals/client.ts","../src/webhooks/keyRotation.ts","../src/webhooks/client.ts","../src/client.ts","../src/types.ts"],"sourcesContent":["/**\n * Base error class for all SDK errors. Catch this to handle any error\n * thrown by the AgentPress SDK regardless of specific type.\n */\nexport class AgentPressError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentPressError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown at construction time when `AgentPressOptions` contains invalid values\n * (e.g., non-positive timeout, malformed `webhookSecret`).\n */\nexport class ConfigurationError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when the API returns a non-2xx HTTP response.\n *\n * Properties:\n * - `statusCode` - HTTP status code (e.g., 401, 404, 500)\n * - `responseBody` - Raw response body text for debugging\n * - `url` - The full request URL that failed\n */\nexport class HttpError extends AgentPressError {\n public readonly statusCode: number;\n public readonly responseBody: string;\n public readonly url: string;\n\n constructor(statusCode: number, responseBody: string, url: string) {\n super(`HTTP ${statusCode} from ${url}`);\n this.name = \"HttpError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n this.url = url;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a request exceeds the configured `timeout` (default 30s). */\nexport class TimeoutError extends AgentPressError {\n constructor(url: string, timeout: number) {\n super(`Request to ${url} timed out after ${timeout}ms`);\n this.name = \"TimeoutError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown by {@link WebhooksClient.verifyOrThrow} when an inbound webhook signature is invalid or expired. */\nexport class WebhookSignatureError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookSignatureError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link PartnerTokenError}. Maps 1:1 to RFC 6750 `error_description` values. */\nexport type PartnerTokenErrorReason =\n | \"signature_invalid\"\n | \"issuer_mismatch\"\n | \"audience_mismatch\"\n | \"expired\"\n | \"not_yet_valid\"\n | \"missing_claim\"\n | \"ext_provider_mismatch\"\n | \"algorithm_not_allowed\"\n | \"kid_missing_or_unknown\"\n | \"malformed\";\n\n/**\n * Thrown by {@link PartnersClient.verifyToken} when a Partner MCP Spec v1 JWT\n * fails verification. Partners map `reason` to their RFC 6750 `WWW-Authenticate`\n * response (`401 invalid_token` for all reasons in this class).\n */\nexport class PartnerTokenError extends AgentPressError {\n public readonly reason: PartnerTokenErrorReason;\n\n constructor(reason: PartnerTokenErrorReason, message: string) {\n super(message);\n this.name = \"PartnerTokenError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link KeyRotationVerifyError}. */\nexport type KeyRotationVerifyErrorReason =\n | \"invalid_signature\"\n | \"invalid_signature_format\"\n | \"timestamp_out_of_window\"\n | \"invalid_timestamp\"\n | \"payload_too_large\"\n | \"malformed_payload\";\n\n/**\n * Thrown by {@link WebhooksClient.verifyKeyRotation} when a `signing_key_rotation`\n * webhook fails HMAC / timestamp / payload validation.\n */\nexport class KeyRotationVerifyError extends AgentPressError {\n public readonly reason: KeyRotationVerifyErrorReason;\n\n constructor(reason: KeyRotationVerifyErrorReason, message: string) {\n super(message);\n this.name = \"KeyRotationVerifyError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nexport function randomMessageId(): string {\n return `msg_${randomUUID()}`;\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nconst SIGNATURE_PREFIX = \"v1,\";\nconst DEFAULT_TOLERANCE_SECONDS = 5 * 60; // 5 minutes\n\n/**\n * Sign a webhook payload using Svix-compatible HMAC-SHA256.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param msgId - Unique message ID (e.g., \"msg_<uuid>\")\n * @param timestamp - Unix timestamp in seconds\n * @param body - JSON stringified payload\n * @returns Signature string in format \"v1,<base64>\"\n */\nexport function sign(\n secret: string,\n msgId: string,\n timestamp: number,\n body: string,\n): string {\n const secretBytes = Buffer.from(secret.replace(/^whsec_/, \"\"), \"base64\");\n const message = `${msgId}.${timestamp}.${body}`;\n const signature = createHmac(\"sha256\", secretBytes)\n .update(message)\n .digest(\"base64\");\n return `${SIGNATURE_PREFIX}${signature}`;\n}\n\n/**\n * Verify a Svix webhook signature.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param payload - Raw request body (string or Buffer)\n * @param headers - Svix headers object\n * @param toleranceSeconds - Max age of signature in seconds (default: 5 min)\n * @returns true if valid, false if invalid or expired\n */\nexport function verify(\n secret: string,\n payload: string | Buffer,\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n },\n toleranceSeconds: number = DEFAULT_TOLERANCE_SECONDS,\n): boolean {\n const msgId = headers[\"svix-id\"];\n const timestampStr = headers[\"svix-timestamp\"];\n const signatureHeader = headers[\"svix-signature\"];\n\n const timestamp = parseInt(timestampStr, 10);\n if (Number.isNaN(timestamp)) return false;\n\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > toleranceSeconds) return false;\n\n const body =\n typeof payload === \"string\" ? payload : payload.toString(\"utf-8\");\n const expected = sign(secret, msgId, timestamp, body);\n\n const signatures = signatureHeader.split(\" \");\n const expectedBuf = Buffer.from(expected);\n\n for (const sig of signatures) {\n const sigBuf = Buffer.from(sig);\n if (\n sigBuf.length === expectedBuf.length &&\n timingSafeEqual(sigBuf, expectedBuf)\n ) {\n return true;\n }\n }\n\n return false;\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionManageResponse,\n ApproveActionParams,\n RejectActionParams,\n ResolvedOptions,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for programmatically approving or rejecting staged actions.\n * Uses HMAC-SHA256 signing (Svix-compatible), identical to {@link WebhooksClient}.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Approve a staged action\n * await client.actions.approve(\"act_123\", {\n * action: \"my_webhook_action\",\n * });\n *\n * // Reject with a reason\n * await client.actions.reject(\"act_456\", {\n * action: \"my_webhook_action\",\n * reason: \"Insufficient data\",\n * });\n * ```\n */\nexport class ActionsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Approve a staged action, optionally modifying the tool call.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async approve(\n actionId: string,\n params: ApproveActionParams,\n ): Promise<ActionManageResponse> {\n const body: Record<string, unknown> = {};\n if (params.editedToolCall !== undefined) {\n body.editedToolCall = params.editedToolCall;\n }\n if (params.remember !== undefined) {\n body.remember = params.remember;\n }\n return this.manage(actionId, params.action, \"approve\", body);\n }\n\n /**\n * Reject a staged action.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async reject(\n actionId: string,\n params: RejectActionParams,\n ): Promise<ActionManageResponse> {\n return this.manage(actionId, params.action, \"reject\", {\n reason: params.reason,\n });\n }\n\n private async manage(\n actionId: string,\n webhookAction: string,\n operation: \"approve\" | \"reject\",\n body: Record<string, unknown>,\n ): Promise<ActionManageResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for action management operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${webhookAction}/manage/${actionId}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<ActionManageResponse>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { AgentPressError, HttpError, TimeoutError } from \"./errors\";\nimport type { ResolvedOptions } from \"./types\";\n\n/**\n * Internal shared HTTP client. Not part of the public API -- used by\n * namespace clients (e.g., `WebhooksClient`) to make authenticated requests.\n * @internal\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly onRequest?: ResolvedOptions[\"onRequest\"];\n private readonly onResponse?: ResolvedOptions[\"onResponse\"];\n\n constructor(options: ResolvedOptions) {\n this.baseUrl = options.baseUrl;\n this.timeout = options.timeout;\n this.onRequest = options.onRequest;\n this.onResponse = options.onResponse;\n }\n\n /**\n * Send an HTTP request to the API. Constructs the full URL from `baseUrl` + `path`,\n * applies the configured timeout via `AbortSignal`, fires `onRequest`/`onResponse`\n * hooks, and parses the JSON response.\n *\n * @throws {TimeoutError} If the request exceeds the configured timeout.\n * @throws {HttpError} If the API returns a non-2xx status code.\n * @throws {AgentPressError} On network failures or non-JSON responses.\n */\n async request<T>(path: string, init: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers = new Headers(init.headers);\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const requestInit: RequestInit = {\n ...init,\n headers,\n signal: AbortSignal.timeout(this.timeout),\n };\n\n this.onRequest?.(url, requestInit);\n\n let response: Response;\n try {\n response = await fetch(url, requestInit);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n (error.name === \"TimeoutError\" || error.name === \"AbortError\")\n ) {\n throw new TimeoutError(url, this.timeout);\n }\n const message =\n error instanceof Error ? error.message : \"Unknown fetch error\";\n throw new AgentPressError(`Request to ${url} failed: ${message}`);\n }\n\n this.onResponse?.(url, response.clone());\n\n const text = await response.text();\n\n if (!response.ok) {\n throw new HttpError(response.status, text, url);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new AgentPressError(\n `Expected JSON response from ${url} but received: ${text.slice(0, 200)}`,\n );\n }\n }\n}\n","import {\n createRemoteJWKSet,\n type JWTVerifyGetKey,\n errors as joseErrors,\n jwtVerify,\n} from \"jose\";\n\nimport { ConfigurationError, PartnerTokenError } from \"../errors\";\nimport type {\n PartnerTokenClaims,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"../types\";\n\nconst ALGORITHMS = [\"EdDSA\"] as const;\n\ntype RemoteJwks = ReturnType<typeof createRemoteJWKSet>;\n\n/**\n * Client for Partner MCP Spec v1 helpers. Created automatically when\n * {@link AgentPressOptions.partnerMcp} is provided.\n *\n * State (JWKS cache) is per-instance, NOT module-global, so staging and\n * production clients can run side-by-side without cross-talk.\n */\nexport class PartnersClient {\n private readonly options: ResolvedOptions;\n private readonly partnerMcp: ResolvedPartnerMcpOptions | undefined;\n private jwks: RemoteJwks | null = null;\n private jwksKeyFn: JWTVerifyGetKey | null = null;\n\n constructor(options: ResolvedOptions) {\n this.options = options;\n this.partnerMcp = options.partnerMcp;\n }\n\n /**\n * Verify an inbound Partner MCP Spec v1 JWT against AgentPress's JWKS.\n *\n * Enforces the full spec: `algorithms: [\"EdDSA\"]` pinned; `iss`, `aud`,\n * `ext_provider` validated; `sub`, `jti`, `scope` required and non-empty;\n * `kid` header required; `exp` / `iat` validated with ±30s skew (configurable).\n *\n * @param token - Bare JWT string (no `Bearer ` prefix).\n * @returns Typed {@link PartnerTokenClaims}.\n * @throws {PartnerTokenError} with a typed `reason` for RFC 6750 mapping.\n * @throws {ConfigurationError} if `partnerMcp` is not configured.\n */\n async verifyToken(token: string): Promise<PartnerTokenClaims> {\n const cfg = this.requireConfig();\n const jwks = this.getJwks();\n\n let payload: Record<string, unknown>;\n let protectedHeader: { alg?: string; kid?: string; typ?: string };\n\n try {\n const result = await jwtVerify(token, jwks, {\n algorithms: [...ALGORITHMS],\n issuer: cfg.issuer,\n audience: cfg.audience,\n clockTolerance: cfg.clockTolerance,\n });\n payload = result.payload as Record<string, unknown>;\n protectedHeader = result.protectedHeader as {\n alg?: string;\n kid?: string;\n typ?: string;\n };\n } catch (err) {\n throw mapJoseError(err);\n }\n\n // kid header required by spec. jose does not enforce this on its own\n // when the key is resolvable — we enforce it explicitly so forged\n // tokens that elide the kid header can't slip through on a single-key\n // JWKS.\n if (!protectedHeader.kid || typeof protectedHeader.kid !== \"string\") {\n throw new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"JWT header missing required 'kid'\",\n );\n }\n\n const claims = payload as PartnerTokenClaims & Record<string, unknown>;\n\n // jose's jwtVerify checks `exp` (with clockTolerance) but not `iat`\n // future-time unless `maxTokenAge` is set. The spec requires both sides\n // of the skew window, so enforce the future-iat check explicitly.\n if (typeof claims.iat !== \"number\" || !Number.isFinite(claims.iat)) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'iat' claim must be a number\",\n );\n }\n const toleranceSeconds = toSeconds(cfg.clockTolerance);\n const nowSec = Math.floor(Date.now() / 1000);\n if (claims.iat - nowSec > toleranceSeconds) {\n throw new PartnerTokenError(\n \"not_yet_valid\",\n `'iat' is ${claims.iat - nowSec}s in the future, beyond ${toleranceSeconds}s tolerance`,\n );\n }\n\n if (typeof claims.sub !== \"string\" || claims.sub.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'sub' claim is required\");\n }\n if (typeof claims.jti !== \"string\" || claims.jti.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'jti' claim is required\");\n }\n if (typeof claims.scope !== \"string\") {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'scope' claim must be a string\",\n );\n }\n if (\n typeof claims.ext_provider !== \"string\" ||\n claims.ext_provider.length === 0\n ) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'ext_provider' claim is required\",\n );\n }\n if (claims.ext_provider !== cfg.expectedExtProvider) {\n throw new PartnerTokenError(\n \"ext_provider_mismatch\",\n `ext_provider '${claims.ext_provider}' does not match expected '${cfg.expectedExtProvider}'`,\n );\n }\n\n return claims;\n }\n\n /**\n * Force the JWKS cache to refetch immediately. Call this from your\n * `signing_key_rotation` webhook handler after verifying the webhook —\n * otherwise the cache picks up new keys on the next `kid` miss (which\n * works, but with one failed verify latency penalty).\n */\n async refreshJwks(): Promise<void> {\n const jwks = this.getJwks();\n // jose's RemoteJWKSet exposes `.reload()` for exactly this use case.\n const anyJwks = jwks as unknown as { reload?: () => Promise<void> };\n if (typeof anyJwks.reload === \"function\") {\n await anyJwks.reload();\n }\n }\n\n private requireConfig(): ResolvedPartnerMcpOptions {\n if (!this.partnerMcp) {\n throw new ConfigurationError(\n \"partnerMcp options are required for partner token operations\",\n );\n }\n return this.partnerMcp;\n }\n\n private getJwks(): RemoteJwks {\n const cfg = this.requireConfig();\n if (!this.jwks) {\n this.jwks = createRemoteJWKSet(new URL(cfg.jwksUrl), {\n cacheMaxAge: cfg.jwksCacheMaxAgeMs,\n cooldownDuration: 30_000,\n });\n this.jwksKeyFn = this.jwks as unknown as JWTVerifyGetKey;\n }\n return this.jwks;\n }\n}\n\nfunction toSeconds(tolerance: string | number): number {\n if (typeof tolerance === \"number\") return tolerance;\n const match = tolerance.trim().match(/^(\\d+)\\s*(s|m|h)$/i);\n if (!match) return 30;\n const n = Number.parseInt(match[1] as string, 10);\n const unit = (match[2] as string).toLowerCase();\n if (unit === \"s\") return n;\n if (unit === \"m\") return n * 60;\n if (unit === \"h\") return n * 3600;\n return 30;\n}\n\nfunction mapJoseError(err: unknown): PartnerTokenError {\n if (err instanceof PartnerTokenError) return err;\n\n if (err instanceof joseErrors.JWSSignatureVerificationFailed) {\n return new PartnerTokenError(\n \"signature_invalid\",\n \"JWT signature verification failed\",\n );\n }\n if (err instanceof joseErrors.JWKSNoMatchingKey) {\n return new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"No JWKS key matches the JWT 'kid' header\",\n );\n }\n if (err instanceof joseErrors.JOSEAlgNotAllowed) {\n return new PartnerTokenError(\n \"algorithm_not_allowed\",\n \"JWT 'alg' is not EdDSA\",\n );\n }\n if (err instanceof joseErrors.JWTExpired) {\n return new PartnerTokenError(\"expired\", \"JWT has expired\");\n }\n if (err instanceof joseErrors.JWTClaimValidationFailed) {\n const claim = (err as { claim?: string }).claim;\n if (claim === \"iss\") {\n return new PartnerTokenError(\n \"issuer_mismatch\",\n \"JWT 'iss' does not match expected issuer\",\n );\n }\n if (claim === \"aud\") {\n return new PartnerTokenError(\n \"audience_mismatch\",\n \"JWT 'aud' does not match expected audience\",\n );\n }\n if (claim === \"iat\") {\n return new PartnerTokenError(\n \"not_yet_valid\",\n \"JWT 'iat' is in the future beyond clock tolerance\",\n );\n }\n return new PartnerTokenError(\n \"missing_claim\",\n err.message || \"Claim validation failed\",\n );\n }\n if (\n err instanceof joseErrors.JWTInvalid ||\n err instanceof joseErrors.JWSInvalid\n ) {\n return new PartnerTokenError(\"malformed\", err.message || \"Malformed JWT\");\n }\n if (err instanceof Error) {\n return new PartnerTokenError(\"malformed\", err.message);\n }\n return new PartnerTokenError(\"malformed\", String(err));\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n CreateUserApprovalParams,\n DeleteUserApprovalParams,\n ListUserApprovalsParams,\n ListUserApprovalsResponse,\n ResolvedOptions,\n UpdateUserApprovalParams,\n UserToolApproval,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for managing per-user auto-approval rules — the SDK equivalent of the\n * console's `/account/auto-approvals` settings page. Uses HMAC-SHA256 signing\n * (Svix-compatible), identical to {@link ActionsClient.manage}.\n *\n * Each call is scoped to a single webhook (identified by `webhookIdentifier`),\n * which both selects the signing secret and scopes which approvals are visible.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Provision consent so future \"sendEmail\" triggers skip the approval prompt\n * await client.userApprovals.create({\n * webhookIdentifier: \"reviews\",\n * userId: \"user-uuid\",\n * actionWebhookId: \"webhook-uuid\",\n * toolName: \"sendEmail\",\n * mode: \"always_allow\",\n * });\n *\n * // List rules (optionally filtered by userId)\n * const { approvals } = await client.userApprovals.list({\n * webhookIdentifier: \"reviews\",\n * });\n *\n * // Revoke\n * await client.userApprovals.delete(approvalId, { webhookIdentifier: \"reviews\" });\n * ```\n */\nexport class UserApprovalsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * List auto-approval rules for a webhook. Optionally filter by `userId`.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async list(\n params: ListUserApprovalsParams,\n ): Promise<ListUserApprovalsResponse> {\n const body: Record<string, unknown> = {};\n if (params.userId !== undefined) body.userId = params.userId;\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n return this.send<ListUserApprovalsResponse>(\n params.webhookIdentifier,\n \"list\",\n body,\n );\n }\n\n /**\n * Create (or upsert) an auto-approval rule. If a rule with the same\n * `(userId, actionWebhookId, toolName)` triple already exists, it is\n * updated in place.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async create(params: CreateUserApprovalParams): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {\n userId: params.userId,\n actionWebhookId: params.actionWebhookId,\n toolName: params.toolName,\n mode: params.mode ?? \"always_allow\",\n };\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n \"create\",\n body,\n );\n }\n\n /**\n * Patch an existing auto-approval rule (change mode or expiry).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async update(\n id: string,\n params: UpdateUserApprovalParams,\n ): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {};\n if (params.mode !== undefined) body.mode = params.mode;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n `update/${id}`,\n body,\n );\n }\n\n /**\n * Revoke an auto-approval rule. Future triggers of the corresponding\n * `(user, webhook, tool)` combination will once again stage for approval.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async delete(\n id: string,\n params: DeleteUserApprovalParams,\n ): Promise<{ success: boolean }> {\n return this.send<{ success: boolean }>(\n params.webhookIdentifier,\n `delete/${id}`,\n {},\n );\n }\n\n /** Internal: HMAC-sign and POST the body to the scoped path. */\n private async send<T>(\n webhookIdentifier: string,\n operation: string,\n body: Record<string, unknown>,\n ): Promise<T> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for user approval management operations\",\n );\n }\n\n const path = `/webhooks/user-approvals/${this.options.org}/${webhookIdentifier}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<T>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nimport { ConfigurationError, KeyRotationVerifyError } from \"../errors\";\nimport type { KeyRotationEvent, KeyRotationVerifyParams } from \"../types\";\n\nconst MAX_PAYLOAD_BYTES = 8 * 1024; // 8 KB\nconst TIMESTAMP_SKEW_SECONDS = 300; // 5 minutes\nconst SIGNATURE_PREFIX = \"sha256=\";\n\n/**\n * Verify a `signing_key_rotation` webhook signed by AgentPress with\n * HMAC-SHA256 over the raw request body. Returns the typed\n * {@link KeyRotationEvent} payload.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping.\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\nexport function verifyKeyRotation(\n secret: string | undefined,\n params: KeyRotationVerifyParams,\n): KeyRotationEvent {\n if (!secret) {\n throw new ConfigurationError(\n \"webhookSecret is required for key rotation webhook verification\",\n );\n }\n\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n\n const byteLength =\n typeof params.payload === \"string\"\n ? Buffer.byteLength(params.payload, \"utf-8\")\n : params.payload.length;\n if (byteLength > MAX_PAYLOAD_BYTES) {\n throw new KeyRotationVerifyError(\n \"payload_too_large\",\n `Payload exceeds ${MAX_PAYLOAD_BYTES} bytes`,\n );\n }\n\n const signatureHeader = readHeader(params.headers, \"x-agentpress-signature\");\n const timestampHeader = readHeader(params.headers, \"x-agentpress-timestamp\");\n\n if (!signatureHeader?.startsWith(SIGNATURE_PREFIX)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n `Signature header missing or does not start with '${SIGNATURE_PREFIX}'`,\n );\n }\n const providedHex = signatureHeader\n .slice(SIGNATURE_PREFIX.length)\n .toLowerCase();\n if (!/^[0-9a-f]+$/.test(providedHex)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n \"Signature is not a hex string\",\n );\n }\n\n if (!timestampHeader) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp header is required\",\n );\n }\n const timestamp = Number.parseInt(timestampHeader, 10);\n if (\n !Number.isFinite(timestamp) ||\n String(timestamp) !== timestampHeader.trim()\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp is not a valid unix seconds integer\",\n );\n }\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > TIMESTAMP_SKEW_SECONDS) {\n throw new KeyRotationVerifyError(\n \"timestamp_out_of_window\",\n `Timestamp skew ${Math.abs(now - timestamp)}s exceeds ${TIMESTAMP_SKEW_SECONDS}s tolerance`,\n );\n }\n\n const expectedHex = createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n const providedBuf = Buffer.from(providedHex, \"hex\");\n const expectedBuf = Buffer.from(expectedHex, \"hex\");\n if (\n providedBuf.length !== expectedBuf.length ||\n !timingSafeEqual(providedBuf, expectedBuf)\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_signature\",\n \"HMAC signature mismatch\",\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload is not valid JSON\",\n );\n }\n\n return validatePayload(parsed);\n}\n\nfunction readHeader(\n headers: Record<string, string | undefined>,\n name: string,\n): string | undefined {\n // Headers are case-insensitive; normalize without mutating the caller's object.\n const lowered = name.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lowered && typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n\nfunction validatePayload(raw: unknown): KeyRotationEvent {\n if (!raw || typeof raw !== \"object\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload must be a JSON object\",\n );\n }\n const obj = raw as Record<string, unknown>;\n if (obj.event !== \"signing_key_rotation\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `Unexpected event '${String(obj.event)}'`,\n );\n }\n if (obj.type !== \"scheduled\" && obj.type !== \"emergency\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'type' must be 'scheduled' or 'emergency'\",\n );\n }\n for (const key of [\n \"retiredKid\",\n \"newCurrentKid\",\n \"retiredAt\",\n \"effectiveAt\",\n \"jwksUrl\",\n ]) {\n if (typeof obj[key] !== \"string\" || (obj[key] as string).length === 0) {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `'${key}' must be a non-empty string`,\n );\n }\n }\n if (obj.reason !== undefined && typeof obj.reason !== \"string\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'reason' must be a string when present\",\n );\n }\n\n const event: KeyRotationEvent = {\n event: \"signing_key_rotation\",\n type: obj.type as \"scheduled\" | \"emergency\",\n retiredKid: obj.retiredKid as string,\n newCurrentKid: obj.newCurrentKid as string,\n retiredAt: obj.retiredAt as string,\n effectiveAt: obj.effectiveAt as string,\n jwksUrl: obj.jwksUrl as string,\n };\n if (typeof obj.reason === \"string\") {\n event.reason = obj.reason;\n }\n return event;\n}\n","import {\n AgentPressError,\n ConfigurationError,\n WebhookSignatureError,\n} from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionCallbackPayload,\n KeyRotationEvent,\n KeyRotationVerifyParams,\n ResolvedOptions,\n WebhookResponse,\n WebhookSendParams,\n WebhookVerifyParams,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { verifyKeyRotation as verifyKeyRotationImpl } from \"./keyRotation\";\nimport { sign, verify as verifySig } from \"./signing\";\n\nexport class WebhooksClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Send an arbitrary webhook payload to AgentPress.\n * Signs the payload with HMAC-SHA256 (Svix-compatible).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async send(params: WebhookSendParams): Promise<WebhookResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${params.action}`;\n const body = JSON.stringify(params.payload);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(this.options.webhookSecret, msgId, timestamp, body);\n\n return this.http.request<WebhookResponse>(path, {\n method: \"POST\",\n body,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n\n /**\n * Verify an inbound Svix webhook signature.\n *\n * @returns true if valid, false if invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verify(params: WebhookVerifyParams): boolean {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook verification\",\n );\n }\n\n return verifySig(\n this.options.webhookSecret,\n params.payload,\n params.headers,\n );\n }\n\n /**\n * Verify an inbound Svix webhook signature, throwing on failure.\n * Useful for middleware patterns where invalid signatures should halt processing.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verifyOrThrow(params: WebhookVerifyParams): void {\n if (!this.verify(params)) {\n throw new WebhookSignatureError(\"Invalid webhook signature\");\n }\n }\n\n /**\n * Verify and parse an inbound webhook from AgentPress.\n * Combines signature verification with JSON parsing and type casting.\n * This is the recommended way to handle incoming webhooks.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws AgentPressError if payload is not valid JSON\n */\n constructEvent(params: WebhookVerifyParams): ActionCallbackPayload {\n this.verifyOrThrow(params);\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n try {\n return JSON.parse(body) as ActionCallbackPayload;\n } catch {\n throw new AgentPressError(\"Webhook payload is not valid JSON\");\n }\n }\n\n /**\n * Verify an inbound `signing_key_rotation` webhook (HMAC-SHA256 + timestamp\n * + typed payload) from AgentPress. See the Partner MCP Spec v1 for the\n * full contract.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping\n * (401 for signature errors, 400 for malformed payload, 413 for oversize).\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\n verifyKeyRotation(params: KeyRotationVerifyParams): KeyRotationEvent {\n return verifyKeyRotationImpl(this.options.webhookSecret, params);\n }\n}\n","import { ActionsClient } from \"./actions/client\";\nimport { ConfigurationError } from \"./errors\";\nimport { HttpClient } from \"./http\";\nimport { PartnersClient } from \"./partners/client\";\nimport type {\n AgentPressOptions,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"./types\";\nimport { UserApprovalsClient } from \"./userApprovals/client\";\nimport { WebhooksClient } from \"./webhooks/client\";\n\n/**\n * Main entry point for the AgentPress SDK. Provides namespaced access to API\n * resources (e.g., `client.webhooks.send()`, `client.actions.approve()`).\n * Validates all configuration options at construction time, so invalid config fails fast.\n *\n * @example\n * ```ts\n * const client = new AgentPress({\n * apiKey: \"ak_...\",\n * webhookSecret: \"whsec_...\",\n * });\n * await client.webhooks.send({ action: \"my_action\", payload: { ... } });\n * await client.actions.approve(\"act_123\", { action: \"my_action\" });\n * ```\n */\nexport class AgentPress {\n /** Webhook operations: send outbound webhooks and verify inbound signatures. */\n public readonly webhooks: WebhooksClient;\n /** Action management: approve or reject staged actions. */\n public readonly actions: ActionsClient;\n /** Per-user auto-approval rules (read / create / update / delete). */\n public readonly userApprovals: UserApprovalsClient;\n /** Partner MCP Spec v1 helpers (inbound JWT verification, JWKS refresh). */\n public readonly partners: PartnersClient;\n\n /**\n * @param options - SDK configuration. All fields are optional with sensible defaults.\n * @throws {ConfigurationError} If `timeout` is non-positive or `webhookSecret` has an invalid prefix.\n */\n constructor(options: AgentPressOptions = {}) {\n const resolved = resolveOptions(options);\n const http = new HttpClient(resolved);\n this.webhooks = new WebhooksClient(resolved, http);\n this.actions = new ActionsClient(resolved, http);\n this.userApprovals = new UserApprovalsClient(resolved, http);\n this.partners = new PartnersClient(resolved);\n }\n}\n\nfunction resolveOptions(options: AgentPressOptions): ResolvedOptions {\n const baseUrl = (options.baseUrl ?? \"https://api.agent.press\").replace(\n /\\/+$/,\n \"\",\n );\n const timeout = options.timeout ?? 30_000;\n const org = options.org ?? \"default-org\";\n\n if (timeout <= 0 || !Number.isFinite(timeout)) {\n throw new ConfigurationError(\"timeout must be a positive number\");\n }\n\n if (\n options.webhookSecret !== undefined &&\n !options.webhookSecret.startsWith(\"whsec_\")\n ) {\n throw new ConfigurationError('webhookSecret must start with \"whsec_\"');\n }\n\n return {\n baseUrl,\n timeout,\n org,\n webhookSecret: options.webhookSecret,\n apiKey: options.apiKey,\n partnerMcp: resolvePartnerMcp(options.partnerMcp),\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n };\n}\n\nfunction resolvePartnerMcp(\n options: AgentPressOptions[\"partnerMcp\"],\n): ResolvedPartnerMcpOptions | undefined {\n if (!options) return undefined;\n\n if (typeof options.jwksUrl !== \"string\" || options.jwksUrl.length === 0) {\n throw new ConfigurationError(\"partnerMcp.jwksUrl is required\");\n }\n try {\n // Validate early so a bad URL fails at construction, not on first verify.\n new URL(options.jwksUrl);\n } catch {\n throw new ConfigurationError(\"partnerMcp.jwksUrl must be a valid URL\");\n }\n if (typeof options.issuer !== \"string\" || options.issuer.length === 0) {\n throw new ConfigurationError(\"partnerMcp.issuer is required\");\n }\n if (typeof options.audience !== \"string\" || options.audience.length === 0) {\n throw new ConfigurationError(\"partnerMcp.audience is required\");\n }\n if (\n typeof options.expectedExtProvider !== \"string\" ||\n options.expectedExtProvider.length === 0\n ) {\n throw new ConfigurationError(\"partnerMcp.expectedExtProvider is required\");\n }\n\n const clockTolerance = options.clockTolerance ?? \"30s\";\n const jwksCacheMaxAgeMs = options.jwksCacheMaxAgeMs ?? 3_600_000;\n if (jwksCacheMaxAgeMs <= 0 || !Number.isFinite(jwksCacheMaxAgeMs)) {\n throw new ConfigurationError(\n \"partnerMcp.jwksCacheMaxAgeMs must be a positive number\",\n );\n }\n\n return {\n jwksUrl: options.jwksUrl,\n issuer: options.issuer,\n audience: options.audience,\n expectedExtProvider: options.expectedExtProvider,\n clockTolerance,\n jwksCacheMaxAgeMs,\n };\n}\n","/** Constructor options for the {@link AgentPress} client. All fields are optional. */\nexport interface AgentPressOptions {\n /** Svix webhook signing secret for verifying inbound webhooks. Must start with `\"whsec_\"`. */\n webhookSecret?: string;\n /** API key for authenticated requests. */\n apiKey?: string;\n /** @default \"https://api.agent.press\" */\n baseUrl?: string;\n /** Request timeout in milliseconds. Must be a positive finite number. @default 30000 */\n timeout?: number;\n /** Organization identifier sent with requests. @default \"default-org\" */\n org?: string;\n /**\n * Partner MCP Spec v1 configuration. Required only if you call\n * {@link PartnersClient.verifyToken} or {@link WebhooksClient.verifyKeyRotation}.\n *\n * Each environment (staging / production) needs its own {@link AgentPress}\n * instance with its own `partnerMcp` block — never share a client between\n * environments. JWKS cache state is per-instance, so side-by-side staging\n * and prod clients have no cross-talk.\n */\n partnerMcp?: PartnerMcpOptions;\n /** Hook called before every outbound HTTP request (useful for logging/tracing). */\n onRequest?: (url: string, init: RequestInit) => void;\n /** Hook called after every HTTP response is received. */\n onResponse?: (url: string, response: Response) => void;\n}\n\n/** Partner MCP Spec v1 configuration. See {@link AgentPressOptions.partnerMcp}. */\nexport interface PartnerMcpOptions {\n /**\n * Full URL to the issuing AgentPress org's JWKS.\n * Per-org as of Partner MCP Spec v1 (per-org signing keys), e.g.\n * `https://api.agent.press/orgs/<org-slug>/.well-known/jwks.json`.\n * The org admin who registered you as a partner will give you the\n * exact URL along with their `<org-slug>`.\n */\n jwksUrl: string;\n /**\n * Exact match for the JWT `iss` claim. Per-org scoped, e.g.\n * `https://api.agent.press/orgs/<org-slug>`. The JWKS URL above is\n * always `<issuer>/.well-known/jwks.json`.\n */\n issuer: string;\n /** Exact match for the JWT `aud` claim — your partner MCP's stable URL. */\n audience: string;\n /** Required value for the `ext_provider` claim, e.g. `\"localfalcon\"`. */\n expectedExtProvider: string;\n /**\n * Clock skew tolerance for `iat` / `exp` validation. Accepts a jose duration\n * string (`\"30s\"`, `\"1m\"`) or a number of seconds.\n * @default \"30s\"\n */\n clockTolerance?: string | number;\n /**\n * JWKS cache max age in milliseconds. Cache is per-instance, not module-global.\n * @default 3_600_000 (1 hour)\n */\n jwksCacheMaxAgeMs?: number;\n}\n\n/** A verified Partner MCP Spec v1 JWT claim set. */\nexport interface PartnerTokenClaims {\n /** The external user id (verified non-empty). */\n sub: string;\n /** Space-separated scope string, per RFC 8693. May be empty but always present. */\n scope: string;\n /** External auth provider name; verified against {@link PartnerMcpOptions.expectedExtProvider}. */\n ext_provider: string;\n /** Unique token id. Non-empty. Partners build replay caches keyed by this. */\n jti: string;\n /** Already validated against {@link PartnerMcpOptions.issuer}; returned for audit logs. */\n iss: string;\n /** Already validated against {@link PartnerMcpOptions.audience}; returned for audit logs. */\n aud: string;\n /** Unix seconds. */\n iat: number;\n /** Unix seconds. */\n exp: number;\n /** AgentPress org identifier, optional. */\n org_id?: string;\n /** AgentPress thread identifier, optional. */\n thread_id?: string;\n /** Reserved for multi-tenant partner flows. */\n settings_id?: string;\n /** Forward-compat: any additional claims pass through. */\n [key: string]: unknown;\n}\n\n/** Parameters for {@link WebhooksClient.verifyKeyRotation}. */\nexport interface KeyRotationVerifyParams {\n /** Raw request body (string or Buffer) — must not be parsed/modified. */\n payload: string | Buffer;\n /**\n * Incoming HTTP headers. Accepts plain `Record<string, string | undefined>`\n * so Hono / Fastify / Express / Fetch / Worker all work interchangeably.\n * Must include `x-agentpress-signature` and `x-agentpress-timestamp`.\n */\n headers: Record<string, string | undefined>;\n}\n\n/** A verified `signing_key_rotation` webhook payload. */\nexport interface KeyRotationEvent {\n event: \"signing_key_rotation\";\n type: \"scheduled\" | \"emergency\";\n retiredKid: string;\n newCurrentKid: string;\n /** ISO 8601 timestamp. */\n retiredAt: string;\n /** ISO 8601 timestamp. */\n effectiveAt: string;\n /** Matches the configured partner JWKS URL. */\n jwksUrl: string;\n /** Present only on `type: \"emergency\"` rotations. */\n reason?: string;\n}\n\n/** Parameters for {@link WebhooksClient.send}. */\nexport interface WebhookSendParams {\n /** Webhook action name (matches an action rule on the server). */\n action: string;\n /** Arbitrary payload data forwarded to the webhook handler. */\n payload: Record<string, unknown>;\n}\n\n/** Parameters for verifying an inbound webhook signature via {@link WebhooksClient.verify} or {@link WebhooksClient.verifyOrThrow}. */\nexport interface WebhookVerifyParams {\n /** Raw request body (string or Buffer) -- must not be parsed/modified. */\n payload: string | Buffer;\n /** Svix signature headers from the incoming request. */\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n };\n}\n\n/** Response from webhook send operations. */\nexport interface WebhookResponse {\n success: boolean;\n /** UUID of the created action (present on successful creation). */\n actionId?: string;\n /** `true` if an action with the same `externalId` already existed (idempotency). */\n alreadyExists?: boolean;\n skipped?: boolean;\n data?: Record<string, unknown>;\n}\n\n// ── Action Lifecycle Event Types ────────────────────────────────────\n\n/** Action lifecycle event types emitted by AgentPress. */\nexport type ActionEventType =\n | \"action.pending_approval\"\n | \"action.approved\"\n | \"action.completed\"\n | \"action.failed\"\n | \"action.rejected\"\n | \"action.expired\";\n\n/** All public action callback event types emitted by AgentPress. */\nexport const ACTION_EVENT_TYPES: readonly ActionEventType[] = [\n \"action.pending_approval\",\n \"action.approved\",\n \"action.completed\",\n \"action.failed\",\n \"action.rejected\",\n \"action.expired\",\n] as const;\n\n/** Structured approval summary for a staged tool call. */\nexport interface StagedToolCallSummary {\n /** Short action phrase, suitable for headings. */\n title: string;\n /** Full approval request sentence with the key action details. */\n detail: string;\n}\n\n/** A tool call staged for approval lifecycle callbacks. */\nexport interface StagedToolCall {\n toolName: string;\n toolCallId: string;\n arguments: Record<string, unknown>;\n /**\n * Generated approval summary. New callbacks use the structured shape; legacy\n * callbacks may contain a plain string.\n */\n summary?: string | StagedToolCallSummary;\n}\n\n/** Parameters for {@link ActionsClient.approve}. */\nexport interface ApproveActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Optionally modify the tool call arguments before execution. */\n editedToolCall?: {\n toolName: string;\n arguments: Record<string, unknown>;\n };\n /**\n * If `\"webhook\"`, also auto-approves future triggers of the same\n * `(user, webhook, tool)` combination — same effect as the UI's\n * \"Always allow for this webhook\" option.\n *\n * - `\"once\"` — approve only this action (default behavior).\n * - `\"webhook\"` — approve and remember for future triggers.\n */\n remember?: \"once\" | \"webhook\";\n}\n\n/** Parameters for {@link ActionsClient.reject}. */\nexport interface RejectActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Reason for rejection. */\n reason?: string;\n}\n\n/** Response from action approve/reject operations. */\nexport interface ActionManageResponse {\n success: boolean;\n actionId: string;\n status: ActionStatus;\n}\n\n// ── Outbound Webhook (Action Callback) Types ──────────────────────────\n\n/** Status of an action in the AgentPress system. */\nexport type ActionStatus =\n | \"pending\"\n | \"staged\"\n | \"approved\"\n | \"executing\"\n | \"rejected\"\n | \"completed\"\n | \"failed\"\n | \"expired\";\n\n/** A tool call made by the agent during action processing. */\nexport interface ToolCallResult {\n toolName: string;\n arguments: Record<string, unknown>;\n result: unknown;\n}\n\n/** The agent's response after processing an action. */\nexport interface AgentResponse {\n /** The agent's text response, if any. */\n text: string | null;\n /** Tool calls made by the agent during processing. */\n toolCalls: ToolCallResult[];\n}\n\n/**\n * Payload received from AgentPress outbound webhooks (post-event callbacks).\n * This is what your server receives for approval, terminal, and failure events.\n */\nexport interface ActionCallbackPayload {\n actionId: string;\n status: ActionStatus;\n actionType: string;\n /** Lifecycle event type (e.g., \"action.pending_approval\", \"action.completed\"). */\n eventType: ActionEventType;\n /** Webhook action identifier used to create this action. Needed for approve/reject. */\n webhookAction: string | null;\n /** Tool staged for approval lifecycle events when available. */\n stagedToolCall: StagedToolCall | null;\n /** ISO 8601 timestamp of when this callback event occurred. */\n occurredAt: string;\n /** ISO 8601 timestamp retained for backwards compatibility. */\n completedAt: string;\n /** Human-readable execution summary when populated on the action. */\n resultSummary: string | null;\n /** Original data from the inbound webhook that triggered this action. */\n sourceData: Record<string, unknown>;\n /** External system identifier. */\n externalId: string | null;\n /** AgentPress user ID associated with this action. */\n userId: string | null;\n /** Thread ID if the action created a conversation. */\n threadId: string | null;\n /** The agent's response including text and tool call results. */\n agentResponse: AgentResponse;\n /** Error message if the action failed. */\n errorMessage: string | null;\n /** Reason provided if the action was rejected by a human reviewer. */\n rejectionReason: string | null;\n /** Additional custom fields from post-event configuration. */\n [key: string]: unknown;\n}\n\n// ── User Tool Approvals ─────────────────────────────────────────────\n\n/** Mode of a user tool approval rule. */\nexport type ApprovalMode = \"always_allow\" | \"always_deny\";\n\n/**\n * A persisted rule that auto-approves (or auto-denies) a specific\n * `(user, webhook, tool)` triple, bypassing the per-action approval prompt.\n * Dates are ISO 8601 strings on the wire.\n */\nexport interface UserToolApproval {\n id: string;\n orgId: string;\n userId: string;\n actionWebhookId: string;\n toolName: string;\n mode: ApprovalMode;\n /** ISO 8601 timestamp. `null` means never expires. */\n expiresAt: string | null;\n /** ISO 8601 timestamp. */\n createdAt: string;\n /** ISO 8601 timestamp. */\n updatedAt: string;\n}\n\n/** Parameters for {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsParams {\n /** Webhook identifier (slug) — required to scope the signing secret and the result. */\n webhookIdentifier: string;\n /**\n * Filter to a single user's approvals. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId?: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`.\n */\n authProvider?: string;\n}\n\n/** Response from {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsResponse {\n approvals: UserToolApproval[];\n}\n\n/** Parameters for {@link UserApprovalsClient.create}. */\nexport interface CreateUserApprovalParams {\n /** Webhook identifier (slug) — required to scope the signing secret. */\n webhookIdentifier: string;\n /**\n * User identifier this rule applies to. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`. The user must have authenticated through the\n * provider at least once for resolution to succeed.\n */\n authProvider?: string;\n /** UUID of the `action_webhooks` row. Must match the webhook identified by `webhookIdentifier`. */\n actionWebhookId: string;\n /** Name of the tool this rule covers. */\n toolName: string;\n /** @default \"always_allow\" */\n mode?: ApprovalMode;\n /** `null` or omitted = never expires. */\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.update}. */\nexport interface UpdateUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n mode?: ApprovalMode;\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.delete}. */\nexport interface DeleteUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n}\n\n/** @internal Resolved (validated, defaulted) options. Not exported from the public API. */\nexport interface ResolvedOptions {\n baseUrl: string;\n timeout: number;\n org: string;\n webhookSecret?: string;\n apiKey?: string;\n partnerMcp?: ResolvedPartnerMcpOptions;\n onRequest?: AgentPressOptions[\"onRequest\"];\n onResponse?: AgentPressOptions[\"onResponse\"];\n}\n\n/** @internal Resolved (validated, defaulted) partner MCP options. */\nexport interface ResolvedPartnerMcpOptions {\n jwksUrl: string;\n issuer: string;\n audience: string;\n expectedExtProvider: string;\n clockTolerance: string | number;\n jwksCacheMaxAgeMs: number;\n}\n"],"mappings":"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"}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["SIGNATURE_PREFIX","joseErrors","verifySig","verifyKeyRotationImpl"],"sources":["../src/errors.ts","../src/utils.ts","../src/webhooks/signing.ts","../src/actions/client.ts","../src/http.ts","../src/partners/client.ts","../src/userApprovals/client.ts","../src/webhooks/keyRotation.ts","../src/webhooks/client.ts","../src/client.ts","../src/types.ts"],"sourcesContent":["/**\n * Base error class for all SDK errors. Catch this to handle any error\n * thrown by the AgentPress SDK regardless of specific type.\n */\nexport class AgentPressError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentPressError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown at construction time when `AgentPressOptions` contains invalid values\n * (e.g., non-positive timeout, malformed `webhookSecret`).\n */\nexport class ConfigurationError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when the API returns a non-2xx HTTP response.\n *\n * Properties:\n * - `statusCode` - HTTP status code (e.g., 401, 404, 500)\n * - `responseBody` - Raw response body text for debugging\n * - `url` - The full request URL that failed\n */\nexport class HttpError extends AgentPressError {\n public readonly statusCode: number;\n public readonly responseBody: string;\n public readonly url: string;\n\n constructor(statusCode: number, responseBody: string, url: string) {\n super(`HTTP ${statusCode} from ${url}`);\n this.name = \"HttpError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n this.url = url;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a request exceeds the configured `timeout` (default 30s). */\nexport class TimeoutError extends AgentPressError {\n constructor(url: string, timeout: number) {\n super(`Request to ${url} timed out after ${timeout}ms`);\n this.name = \"TimeoutError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown by {@link WebhooksClient.verifyOrThrow} when an inbound webhook signature is invalid or expired. */\nexport class WebhookSignatureError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookSignatureError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link PartnerTokenError}. Maps 1:1 to RFC 6750 `error_description` values. */\nexport type PartnerTokenErrorReason =\n | \"signature_invalid\"\n | \"issuer_mismatch\"\n | \"audience_mismatch\"\n | \"expired\"\n | \"not_yet_valid\"\n | \"missing_claim\"\n | \"ext_provider_mismatch\"\n | \"algorithm_not_allowed\"\n | \"kid_missing_or_unknown\"\n | \"malformed\";\n\n/**\n * Thrown by {@link PartnersClient.verifyToken} when a Partner MCP Spec v1 JWT\n * fails verification. Partners map `reason` to their RFC 6750 `WWW-Authenticate`\n * response (`401 invalid_token` for all reasons in this class).\n */\nexport class PartnerTokenError extends AgentPressError {\n public readonly reason: PartnerTokenErrorReason;\n\n constructor(reason: PartnerTokenErrorReason, message: string) {\n super(message);\n this.name = \"PartnerTokenError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link KeyRotationVerifyError}. */\nexport type KeyRotationVerifyErrorReason =\n | \"invalid_signature\"\n | \"invalid_signature_format\"\n | \"timestamp_out_of_window\"\n | \"invalid_timestamp\"\n | \"payload_too_large\"\n | \"malformed_payload\";\n\n/**\n * Thrown by {@link WebhooksClient.verifyKeyRotation} when a `signing_key_rotation`\n * webhook fails HMAC / timestamp / payload validation.\n */\nexport class KeyRotationVerifyError extends AgentPressError {\n public readonly reason: KeyRotationVerifyErrorReason;\n\n constructor(reason: KeyRotationVerifyErrorReason, message: string) {\n super(message);\n this.name = \"KeyRotationVerifyError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nexport function randomMessageId(): string {\n return `msg_${randomUUID()}`;\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nconst SIGNATURE_PREFIX = \"v1,\";\nconst DEFAULT_TOLERANCE_SECONDS = 5 * 60; // 5 minutes\n\n/**\n * Sign a webhook payload using Svix-compatible HMAC-SHA256.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param msgId - Unique message ID (e.g., \"msg_<uuid>\")\n * @param timestamp - Unix timestamp in seconds\n * @param body - JSON stringified payload\n * @returns Signature string in format \"v1,<base64>\"\n */\nexport function sign(\n secret: string,\n msgId: string,\n timestamp: number,\n body: string,\n): string {\n const secretBytes = Buffer.from(secret.replace(/^whsec_/, \"\"), \"base64\");\n const message = `${msgId}.${timestamp}.${body}`;\n const signature = createHmac(\"sha256\", secretBytes)\n .update(message)\n .digest(\"base64\");\n return `${SIGNATURE_PREFIX}${signature}`;\n}\n\n/**\n * Verify a Svix webhook signature.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param payload - Raw request body (string or Buffer)\n * @param headers - Svix headers object\n * @param toleranceSeconds - Max age of signature in seconds (default: 5 min)\n * @returns true if valid, false if invalid or expired\n */\nexport function verify(\n secret: string,\n payload: string | Buffer,\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n },\n toleranceSeconds: number = DEFAULT_TOLERANCE_SECONDS,\n): boolean {\n const msgId = headers[\"svix-id\"];\n const timestampStr = headers[\"svix-timestamp\"];\n const signatureHeader = headers[\"svix-signature\"];\n\n const timestamp = parseInt(timestampStr, 10);\n if (Number.isNaN(timestamp)) return false;\n\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > toleranceSeconds) return false;\n\n const body =\n typeof payload === \"string\" ? payload : payload.toString(\"utf-8\");\n const expected = sign(secret, msgId, timestamp, body);\n\n const signatures = signatureHeader.split(\" \");\n const expectedBuf = Buffer.from(expected);\n\n for (const sig of signatures) {\n const sigBuf = Buffer.from(sig);\n if (\n sigBuf.length === expectedBuf.length &&\n timingSafeEqual(sigBuf, expectedBuf)\n ) {\n return true;\n }\n }\n\n return false;\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionManageResponse,\n ApproveActionParams,\n RejectActionParams,\n ResolvedOptions,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for programmatically approving or rejecting staged actions.\n * Uses HMAC-SHA256 signing (Svix-compatible), identical to {@link WebhooksClient}.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Approve a staged action\n * await client.actions.approve(\"act_123\", {\n * action: \"my_webhook_action\",\n * });\n *\n * // Reject with a reason\n * await client.actions.reject(\"act_456\", {\n * action: \"my_webhook_action\",\n * reason: \"Insufficient data\",\n * });\n * ```\n */\nexport class ActionsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Approve a staged action, optionally modifying the tool call.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async approve(\n actionId: string,\n params: ApproveActionParams,\n ): Promise<ActionManageResponse> {\n const body: Record<string, unknown> = {};\n if (params.editedToolCall !== undefined) {\n body.editedToolCall = params.editedToolCall;\n }\n if (params.remember !== undefined) {\n body.remember = params.remember;\n }\n return this.manage(actionId, params.action, \"approve\", body);\n }\n\n /**\n * Reject a staged action.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async reject(\n actionId: string,\n params: RejectActionParams,\n ): Promise<ActionManageResponse> {\n return this.manage(actionId, params.action, \"reject\", {\n reason: params.reason,\n });\n }\n\n private async manage(\n actionId: string,\n webhookAction: string,\n operation: \"approve\" | \"reject\",\n body: Record<string, unknown>,\n ): Promise<ActionManageResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for action management operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${webhookAction}/manage/${actionId}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<ActionManageResponse>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { AgentPressError, HttpError, TimeoutError } from \"./errors\";\nimport type { ResolvedOptions } from \"./types\";\n\n/**\n * Internal shared HTTP client. Not part of the public API -- used by\n * namespace clients (e.g., `WebhooksClient`) to make authenticated requests.\n * @internal\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly onRequest?: ResolvedOptions[\"onRequest\"];\n private readonly onResponse?: ResolvedOptions[\"onResponse\"];\n\n constructor(options: ResolvedOptions) {\n this.baseUrl = options.baseUrl;\n this.timeout = options.timeout;\n this.onRequest = options.onRequest;\n this.onResponse = options.onResponse;\n }\n\n /**\n * Send an HTTP request to the API. Constructs the full URL from `baseUrl` + `path`,\n * applies the configured timeout via `AbortSignal`, fires `onRequest`/`onResponse`\n * hooks, and parses the JSON response.\n *\n * @throws {TimeoutError} If the request exceeds the configured timeout.\n * @throws {HttpError} If the API returns a non-2xx status code.\n * @throws {AgentPressError} On network failures or non-JSON responses.\n */\n async request<T>(path: string, init: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers = new Headers(init.headers);\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const requestInit: RequestInit = {\n ...init,\n headers,\n signal: AbortSignal.timeout(this.timeout),\n };\n\n this.onRequest?.(url, requestInit);\n\n let response: Response;\n try {\n response = await fetch(url, requestInit);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n (error.name === \"TimeoutError\" || error.name === \"AbortError\")\n ) {\n throw new TimeoutError(url, this.timeout);\n }\n const message =\n error instanceof Error ? error.message : \"Unknown fetch error\";\n throw new AgentPressError(`Request to ${url} failed: ${message}`);\n }\n\n this.onResponse?.(url, response.clone());\n\n const text = await response.text();\n\n if (!response.ok) {\n throw new HttpError(response.status, text, url);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new AgentPressError(\n `Expected JSON response from ${url} but received: ${text.slice(0, 200)}`,\n );\n }\n }\n}\n","import {\n createRemoteJWKSet,\n type JWTVerifyGetKey,\n errors as joseErrors,\n jwtVerify,\n} from \"jose\";\n\nimport { ConfigurationError, PartnerTokenError } from \"../errors\";\nimport type {\n PartnerTokenClaims,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"../types\";\n\nconst ALGORITHMS = [\"EdDSA\"] as const;\n\ntype RemoteJwks = ReturnType<typeof createRemoteJWKSet>;\n\n/**\n * Client for Partner MCP Spec v1 helpers. Created automatically when\n * {@link AgentPressOptions.partnerMcp} is provided.\n *\n * State (JWKS cache) is per-instance, NOT module-global, so staging and\n * production clients can run side-by-side without cross-talk.\n */\nexport class PartnersClient {\n private readonly options: ResolvedOptions;\n private readonly partnerMcp: ResolvedPartnerMcpOptions | undefined;\n private jwks: RemoteJwks | null = null;\n private jwksKeyFn: JWTVerifyGetKey | null = null;\n\n constructor(options: ResolvedOptions) {\n this.options = options;\n this.partnerMcp = options.partnerMcp;\n }\n\n /**\n * Verify an inbound Partner MCP Spec v1 JWT against AgentPress's JWKS.\n *\n * Enforces the full spec: `algorithms: [\"EdDSA\"]` pinned; `iss`, `aud`,\n * `ext_provider` validated; `sub`, `jti`, `scope` required and non-empty;\n * `kid` header required; `exp` / `iat` validated with ±30s skew (configurable).\n *\n * @param token - Bare JWT string (no `Bearer ` prefix).\n * @returns Typed {@link PartnerTokenClaims}.\n * @throws {PartnerTokenError} with a typed `reason` for RFC 6750 mapping.\n * @throws {ConfigurationError} if `partnerMcp` is not configured.\n */\n async verifyToken(token: string): Promise<PartnerTokenClaims> {\n const cfg = this.requireConfig();\n const jwks = this.getJwks();\n\n let payload: Record<string, unknown>;\n let protectedHeader: { alg?: string; kid?: string; typ?: string };\n\n try {\n const result = await jwtVerify(token, jwks, {\n algorithms: [...ALGORITHMS],\n issuer: cfg.issuer,\n audience: cfg.audience,\n clockTolerance: cfg.clockTolerance,\n });\n payload = result.payload as Record<string, unknown>;\n protectedHeader = result.protectedHeader as {\n alg?: string;\n kid?: string;\n typ?: string;\n };\n } catch (err) {\n throw mapJoseError(err);\n }\n\n // kid header required by spec. jose does not enforce this on its own\n // when the key is resolvable — we enforce it explicitly so forged\n // tokens that elide the kid header can't slip through on a single-key\n // JWKS.\n if (!protectedHeader.kid || typeof protectedHeader.kid !== \"string\") {\n throw new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"JWT header missing required 'kid'\",\n );\n }\n\n const claims = payload as PartnerTokenClaims & Record<string, unknown>;\n\n // jose's jwtVerify checks `exp` (with clockTolerance) but not `iat`\n // future-time unless `maxTokenAge` is set. The spec requires both sides\n // of the skew window, so enforce the future-iat check explicitly.\n if (typeof claims.iat !== \"number\" || !Number.isFinite(claims.iat)) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'iat' claim must be a number\",\n );\n }\n const toleranceSeconds = toSeconds(cfg.clockTolerance);\n const nowSec = Math.floor(Date.now() / 1000);\n if (claims.iat - nowSec > toleranceSeconds) {\n throw new PartnerTokenError(\n \"not_yet_valid\",\n `'iat' is ${claims.iat - nowSec}s in the future, beyond ${toleranceSeconds}s tolerance`,\n );\n }\n\n if (typeof claims.sub !== \"string\" || claims.sub.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'sub' claim is required\");\n }\n if (typeof claims.jti !== \"string\" || claims.jti.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'jti' claim is required\");\n }\n if (typeof claims.scope !== \"string\") {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'scope' claim must be a string\",\n );\n }\n if (\n typeof claims.ext_provider !== \"string\" ||\n claims.ext_provider.length === 0\n ) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'ext_provider' claim is required\",\n );\n }\n if (claims.ext_provider !== cfg.expectedExtProvider) {\n throw new PartnerTokenError(\n \"ext_provider_mismatch\",\n `ext_provider '${claims.ext_provider}' does not match expected '${cfg.expectedExtProvider}'`,\n );\n }\n\n return claims;\n }\n\n /**\n * Force the JWKS cache to refetch immediately. Call this from your\n * `signing_key_rotation` webhook handler after verifying the webhook —\n * otherwise the cache picks up new keys on the next `kid` miss (which\n * works, but with one failed verify latency penalty).\n */\n async refreshJwks(): Promise<void> {\n const jwks = this.getJwks();\n // jose's RemoteJWKSet exposes `.reload()` for exactly this use case.\n const anyJwks = jwks as unknown as { reload?: () => Promise<void> };\n if (typeof anyJwks.reload === \"function\") {\n await anyJwks.reload();\n }\n }\n\n private requireConfig(): ResolvedPartnerMcpOptions {\n if (!this.partnerMcp) {\n throw new ConfigurationError(\n \"partnerMcp options are required for partner token operations\",\n );\n }\n return this.partnerMcp;\n }\n\n private getJwks(): RemoteJwks {\n const cfg = this.requireConfig();\n if (!this.jwks) {\n this.jwks = createRemoteJWKSet(new URL(cfg.jwksUrl), {\n cacheMaxAge: cfg.jwksCacheMaxAgeMs,\n cooldownDuration: 30_000,\n });\n this.jwksKeyFn = this.jwks as unknown as JWTVerifyGetKey;\n }\n return this.jwks;\n }\n}\n\nfunction toSeconds(tolerance: string | number): number {\n if (typeof tolerance === \"number\") return tolerance;\n const match = tolerance.trim().match(/^(\\d+)\\s*(s|m|h)$/i);\n if (!match) return 30;\n const n = Number.parseInt(match[1] as string, 10);\n const unit = (match[2] as string).toLowerCase();\n if (unit === \"s\") return n;\n if (unit === \"m\") return n * 60;\n if (unit === \"h\") return n * 3600;\n return 30;\n}\n\nfunction mapJoseError(err: unknown): PartnerTokenError {\n if (err instanceof PartnerTokenError) return err;\n\n if (err instanceof joseErrors.JWSSignatureVerificationFailed) {\n return new PartnerTokenError(\n \"signature_invalid\",\n \"JWT signature verification failed\",\n );\n }\n if (err instanceof joseErrors.JWKSNoMatchingKey) {\n return new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"No JWKS key matches the JWT 'kid' header\",\n );\n }\n if (err instanceof joseErrors.JOSEAlgNotAllowed) {\n return new PartnerTokenError(\n \"algorithm_not_allowed\",\n \"JWT 'alg' is not EdDSA\",\n );\n }\n if (err instanceof joseErrors.JWTExpired) {\n return new PartnerTokenError(\"expired\", \"JWT has expired\");\n }\n if (err instanceof joseErrors.JWTClaimValidationFailed) {\n const claim = (err as { claim?: string }).claim;\n if (claim === \"iss\") {\n return new PartnerTokenError(\n \"issuer_mismatch\",\n \"JWT 'iss' does not match expected issuer\",\n );\n }\n if (claim === \"aud\") {\n return new PartnerTokenError(\n \"audience_mismatch\",\n \"JWT 'aud' does not match expected audience\",\n );\n }\n if (claim === \"iat\") {\n return new PartnerTokenError(\n \"not_yet_valid\",\n \"JWT 'iat' is in the future beyond clock tolerance\",\n );\n }\n return new PartnerTokenError(\n \"missing_claim\",\n err.message || \"Claim validation failed\",\n );\n }\n if (\n err instanceof joseErrors.JWTInvalid ||\n err instanceof joseErrors.JWSInvalid\n ) {\n return new PartnerTokenError(\"malformed\", err.message || \"Malformed JWT\");\n }\n if (err instanceof Error) {\n return new PartnerTokenError(\"malformed\", err.message);\n }\n return new PartnerTokenError(\"malformed\", String(err));\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n CreateUserApprovalParams,\n DeleteUserApprovalParams,\n ListUserApprovalsParams,\n ListUserApprovalsResponse,\n ResolvedOptions,\n UpdateUserApprovalParams,\n UserToolApproval,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for managing per-user auto-approval rules — the SDK equivalent of the\n * console's `/account/auto-approvals` settings page. Uses HMAC-SHA256 signing\n * (Svix-compatible), identical to {@link ActionsClient.manage}.\n *\n * Each call is scoped to a single webhook (identified by `webhookIdentifier`),\n * which both selects the signing secret and scopes which approvals are visible.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Provision consent so future \"sendEmail\" triggers skip the approval prompt\n * await client.userApprovals.create({\n * webhookIdentifier: \"reviews\",\n * userId: \"user-uuid\",\n * actionWebhookId: \"webhook-uuid\",\n * toolName: \"sendEmail\",\n * mode: \"always_allow\",\n * });\n *\n * // List rules (optionally filtered by userId)\n * const { approvals } = await client.userApprovals.list({\n * webhookIdentifier: \"reviews\",\n * });\n *\n * // Revoke\n * await client.userApprovals.delete(approvalId, { webhookIdentifier: \"reviews\" });\n * ```\n */\nexport class UserApprovalsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * List auto-approval rules for a webhook. Optionally filter by `userId`.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async list(\n params: ListUserApprovalsParams,\n ): Promise<ListUserApprovalsResponse> {\n const body: Record<string, unknown> = {};\n if (params.userId !== undefined) body.userId = params.userId;\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n return this.send<ListUserApprovalsResponse>(\n params.webhookIdentifier,\n \"list\",\n body,\n );\n }\n\n /**\n * Create (or upsert) an auto-approval rule. If a rule with the same\n * `(userId, actionWebhookId, toolName)` triple already exists, it is\n * updated in place.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async create(params: CreateUserApprovalParams): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {\n userId: params.userId,\n actionWebhookId: params.actionWebhookId,\n toolName: params.toolName,\n mode: params.mode ?? \"always_allow\",\n };\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n \"create\",\n body,\n );\n }\n\n /**\n * Patch an existing auto-approval rule (change mode or expiry).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async update(\n id: string,\n params: UpdateUserApprovalParams,\n ): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {};\n if (params.mode !== undefined) body.mode = params.mode;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n `update/${id}`,\n body,\n );\n }\n\n /**\n * Revoke an auto-approval rule. Future triggers of the corresponding\n * `(user, webhook, tool)` combination will once again stage for approval.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async delete(\n id: string,\n params: DeleteUserApprovalParams,\n ): Promise<{ success: boolean }> {\n return this.send<{ success: boolean }>(\n params.webhookIdentifier,\n `delete/${id}`,\n {},\n );\n }\n\n /** Internal: HMAC-sign and POST the body to the scoped path. */\n private async send<T>(\n webhookIdentifier: string,\n operation: string,\n body: Record<string, unknown>,\n ): Promise<T> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for user approval management operations\",\n );\n }\n\n const path = `/webhooks/user-approvals/${this.options.org}/${webhookIdentifier}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<T>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nimport { ConfigurationError, KeyRotationVerifyError } from \"../errors\";\nimport type { KeyRotationEvent, KeyRotationVerifyParams } from \"../types\";\n\nconst MAX_PAYLOAD_BYTES = 8 * 1024; // 8 KB\nconst TIMESTAMP_SKEW_SECONDS = 300; // 5 minutes\nconst SIGNATURE_PREFIX = \"sha256=\";\n\n/**\n * Verify a `signing_key_rotation` webhook signed by AgentPress with\n * HMAC-SHA256 over the raw request body. Returns the typed\n * {@link KeyRotationEvent} payload.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping.\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\nexport function verifyKeyRotation(\n secret: string | undefined,\n params: KeyRotationVerifyParams,\n): KeyRotationEvent {\n if (!secret) {\n throw new ConfigurationError(\n \"webhookSecret is required for key rotation webhook verification\",\n );\n }\n\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n\n const byteLength =\n typeof params.payload === \"string\"\n ? Buffer.byteLength(params.payload, \"utf-8\")\n : params.payload.length;\n if (byteLength > MAX_PAYLOAD_BYTES) {\n throw new KeyRotationVerifyError(\n \"payload_too_large\",\n `Payload exceeds ${MAX_PAYLOAD_BYTES} bytes`,\n );\n }\n\n const signatureHeader = readHeader(params.headers, \"x-agentpress-signature\");\n const timestampHeader = readHeader(params.headers, \"x-agentpress-timestamp\");\n\n if (!signatureHeader?.startsWith(SIGNATURE_PREFIX)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n `Signature header missing or does not start with '${SIGNATURE_PREFIX}'`,\n );\n }\n const providedHex = signatureHeader\n .slice(SIGNATURE_PREFIX.length)\n .toLowerCase();\n if (!/^[0-9a-f]+$/.test(providedHex)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n \"Signature is not a hex string\",\n );\n }\n\n if (!timestampHeader) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp header is required\",\n );\n }\n const timestamp = Number.parseInt(timestampHeader, 10);\n if (\n !Number.isFinite(timestamp) ||\n String(timestamp) !== timestampHeader.trim()\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp is not a valid unix seconds integer\",\n );\n }\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > TIMESTAMP_SKEW_SECONDS) {\n throw new KeyRotationVerifyError(\n \"timestamp_out_of_window\",\n `Timestamp skew ${Math.abs(now - timestamp)}s exceeds ${TIMESTAMP_SKEW_SECONDS}s tolerance`,\n );\n }\n\n const expectedHex = createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n const providedBuf = Buffer.from(providedHex, \"hex\");\n const expectedBuf = Buffer.from(expectedHex, \"hex\");\n if (\n providedBuf.length !== expectedBuf.length ||\n !timingSafeEqual(providedBuf, expectedBuf)\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_signature\",\n \"HMAC signature mismatch\",\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload is not valid JSON\",\n );\n }\n\n return validatePayload(parsed);\n}\n\nfunction readHeader(\n headers: Record<string, string | undefined>,\n name: string,\n): string | undefined {\n // Headers are case-insensitive; normalize without mutating the caller's object.\n const lowered = name.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lowered && typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n\nfunction validatePayload(raw: unknown): KeyRotationEvent {\n if (!raw || typeof raw !== \"object\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload must be a JSON object\",\n );\n }\n const obj = raw as Record<string, unknown>;\n if (obj.event !== \"signing_key_rotation\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `Unexpected event '${String(obj.event)}'`,\n );\n }\n if (obj.type !== \"scheduled\" && obj.type !== \"emergency\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'type' must be 'scheduled' or 'emergency'\",\n );\n }\n for (const key of [\n \"retiredKid\",\n \"newCurrentKid\",\n \"retiredAt\",\n \"effectiveAt\",\n \"jwksUrl\",\n ]) {\n if (typeof obj[key] !== \"string\" || (obj[key] as string).length === 0) {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `'${key}' must be a non-empty string`,\n );\n }\n }\n if (obj.reason !== undefined && typeof obj.reason !== \"string\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'reason' must be a string when present\",\n );\n }\n\n const event: KeyRotationEvent = {\n event: \"signing_key_rotation\",\n type: obj.type as \"scheduled\" | \"emergency\",\n retiredKid: obj.retiredKid as string,\n newCurrentKid: obj.newCurrentKid as string,\n retiredAt: obj.retiredAt as string,\n effectiveAt: obj.effectiveAt as string,\n jwksUrl: obj.jwksUrl as string,\n };\n if (typeof obj.reason === \"string\") {\n event.reason = obj.reason;\n }\n return event;\n}\n","import {\n AgentPressError,\n ConfigurationError,\n WebhookSignatureError,\n} from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionCallbackPayload,\n KeyRotationEvent,\n KeyRotationVerifyParams,\n ResolvedOptions,\n WebhookResponse,\n WebhookSendParams,\n WebhookVerifyParams,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { verifyKeyRotation as verifyKeyRotationImpl } from \"./keyRotation\";\nimport { sign, verify as verifySig } from \"./signing\";\n\nexport class WebhooksClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Send an arbitrary webhook payload to AgentPress.\n * Signs the payload with HMAC-SHA256 (Svix-compatible).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async send(params: WebhookSendParams): Promise<WebhookResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${params.action}`;\n const body = JSON.stringify(params.payload);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(this.options.webhookSecret, msgId, timestamp, body);\n\n return this.http.request<WebhookResponse>(path, {\n method: \"POST\",\n body,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n\n /**\n * Verify an inbound Svix webhook signature.\n *\n * @returns true if valid, false if invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verify(params: WebhookVerifyParams): boolean {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook verification\",\n );\n }\n\n return verifySig(\n this.options.webhookSecret,\n params.payload,\n params.headers,\n );\n }\n\n /**\n * Verify an inbound Svix webhook signature, throwing on failure.\n * Useful for middleware patterns where invalid signatures should halt processing.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verifyOrThrow(params: WebhookVerifyParams): void {\n if (!this.verify(params)) {\n throw new WebhookSignatureError(\"Invalid webhook signature\");\n }\n }\n\n /**\n * Verify and parse an inbound webhook from AgentPress.\n * Combines signature verification with JSON parsing and type casting.\n * This is the recommended way to handle incoming webhooks.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws AgentPressError if payload is not valid JSON\n */\n constructEvent(params: WebhookVerifyParams): ActionCallbackPayload {\n this.verifyOrThrow(params);\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n try {\n return JSON.parse(body) as ActionCallbackPayload;\n } catch {\n throw new AgentPressError(\"Webhook payload is not valid JSON\");\n }\n }\n\n /**\n * Verify an inbound `signing_key_rotation` webhook (HMAC-SHA256 + timestamp\n * + typed payload) from AgentPress. See the Partner MCP Spec v1 for the\n * full contract.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping\n * (401 for signature errors, 400 for malformed payload, 413 for oversize).\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\n verifyKeyRotation(params: KeyRotationVerifyParams): KeyRotationEvent {\n return verifyKeyRotationImpl(this.options.webhookSecret, params);\n }\n}\n","import { ActionsClient } from \"./actions/client\";\nimport { ConfigurationError } from \"./errors\";\nimport { HttpClient } from \"./http\";\nimport { PartnersClient } from \"./partners/client\";\nimport type {\n AgentPressOptions,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"./types\";\nimport { UserApprovalsClient } from \"./userApprovals/client\";\nimport { WebhooksClient } from \"./webhooks/client\";\n\n/**\n * Main entry point for the AgentPress SDK. Provides namespaced access to API\n * resources (e.g., `client.webhooks.send()`, `client.actions.approve()`).\n * Validates all configuration options at construction time, so invalid config fails fast.\n *\n * @example\n * ```ts\n * const client = new AgentPress({\n * apiKey: \"ak_...\",\n * webhookSecret: \"whsec_...\",\n * });\n * await client.webhooks.send({ action: \"my_action\", payload: { ... } });\n * await client.actions.approve(\"act_123\", { action: \"my_action\" });\n * ```\n */\nexport class AgentPress {\n /** Webhook operations: send outbound webhooks and verify inbound signatures. */\n public readonly webhooks: WebhooksClient;\n /** Action management: approve or reject staged actions. */\n public readonly actions: ActionsClient;\n /** Per-user auto-approval rules (read / create / update / delete). */\n public readonly userApprovals: UserApprovalsClient;\n /** Partner MCP Spec v1 helpers (inbound JWT verification, JWKS refresh). */\n public readonly partners: PartnersClient;\n\n /**\n * @param options - SDK configuration. All fields are optional with sensible defaults.\n * @throws {ConfigurationError} If `timeout` is non-positive or `webhookSecret` has an invalid prefix.\n */\n constructor(options: AgentPressOptions = {}) {\n const resolved = resolveOptions(options);\n const http = new HttpClient(resolved);\n this.webhooks = new WebhooksClient(resolved, http);\n this.actions = new ActionsClient(resolved, http);\n this.userApprovals = new UserApprovalsClient(resolved, http);\n this.partners = new PartnersClient(resolved);\n }\n}\n\nfunction resolveOptions(options: AgentPressOptions): ResolvedOptions {\n const baseUrl = (options.baseUrl ?? \"https://api.agent.press\").replace(\n /\\/+$/,\n \"\",\n );\n const timeout = options.timeout ?? 30_000;\n const org = options.org ?? \"default-org\";\n\n if (timeout <= 0 || !Number.isFinite(timeout)) {\n throw new ConfigurationError(\"timeout must be a positive number\");\n }\n\n if (\n options.webhookSecret !== undefined &&\n !options.webhookSecret.startsWith(\"whsec_\")\n ) {\n throw new ConfigurationError('webhookSecret must start with \"whsec_\"');\n }\n\n return {\n baseUrl,\n timeout,\n org,\n webhookSecret: options.webhookSecret,\n apiKey: options.apiKey,\n partnerMcp: resolvePartnerMcp(options.partnerMcp),\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n };\n}\n\nfunction resolvePartnerMcp(\n options: AgentPressOptions[\"partnerMcp\"],\n): ResolvedPartnerMcpOptions | undefined {\n if (!options) return undefined;\n\n if (typeof options.jwksUrl !== \"string\" || options.jwksUrl.length === 0) {\n throw new ConfigurationError(\"partnerMcp.jwksUrl is required\");\n }\n try {\n // Validate early so a bad URL fails at construction, not on first verify.\n new URL(options.jwksUrl);\n } catch {\n throw new ConfigurationError(\"partnerMcp.jwksUrl must be a valid URL\");\n }\n if (typeof options.issuer !== \"string\" || options.issuer.length === 0) {\n throw new ConfigurationError(\"partnerMcp.issuer is required\");\n }\n if (typeof options.audience !== \"string\" || options.audience.length === 0) {\n throw new ConfigurationError(\"partnerMcp.audience is required\");\n }\n if (\n typeof options.expectedExtProvider !== \"string\" ||\n options.expectedExtProvider.length === 0\n ) {\n throw new ConfigurationError(\"partnerMcp.expectedExtProvider is required\");\n }\n\n const clockTolerance = options.clockTolerance ?? \"30s\";\n const jwksCacheMaxAgeMs = options.jwksCacheMaxAgeMs ?? 3_600_000;\n if (jwksCacheMaxAgeMs <= 0 || !Number.isFinite(jwksCacheMaxAgeMs)) {\n throw new ConfigurationError(\n \"partnerMcp.jwksCacheMaxAgeMs must be a positive number\",\n );\n }\n\n return {\n jwksUrl: options.jwksUrl,\n issuer: options.issuer,\n audience: options.audience,\n expectedExtProvider: options.expectedExtProvider,\n clockTolerance,\n jwksCacheMaxAgeMs,\n };\n}\n","/** Constructor options for the {@link AgentPress} client. All fields are optional. */\nexport interface AgentPressOptions {\n /** Svix webhook signing secret for verifying inbound webhooks. Must start with `\"whsec_\"`. */\n webhookSecret?: string;\n /** API key for authenticated requests. */\n apiKey?: string;\n /** @default \"https://api.agent.press\" */\n baseUrl?: string;\n /** Request timeout in milliseconds. Must be a positive finite number. @default 30000 */\n timeout?: number;\n /** Organization identifier sent with requests. @default \"default-org\" */\n org?: string;\n /**\n * Partner MCP Spec v1 configuration. Required only if you call\n * {@link PartnersClient.verifyToken} or {@link WebhooksClient.verifyKeyRotation}.\n *\n * Each environment (staging / production) needs its own {@link AgentPress}\n * instance with its own `partnerMcp` block — never share a client between\n * environments. JWKS cache state is per-instance, so side-by-side staging\n * and prod clients have no cross-talk.\n */\n partnerMcp?: PartnerMcpOptions;\n /** Hook called before every outbound HTTP request (useful for logging/tracing). */\n onRequest?: (url: string, init: RequestInit) => void;\n /** Hook called after every HTTP response is received. */\n onResponse?: (url: string, response: Response) => void;\n}\n\n/** Partner MCP Spec v1 configuration. See {@link AgentPressOptions.partnerMcp}. */\nexport interface PartnerMcpOptions {\n /**\n * Full URL to the issuing AgentPress org's JWKS.\n * Per-org as of Partner MCP Spec v1 (per-org signing keys), e.g.\n * `https://api.agent.press/orgs/<org-slug>/.well-known/jwks.json`.\n * The org admin who registered you as a partner will give you the\n * exact URL along with their `<org-slug>`.\n */\n jwksUrl: string;\n /**\n * Exact match for the JWT `iss` claim. Per-org scoped, e.g.\n * `https://api.agent.press/orgs/<org-slug>`. The JWKS URL above is\n * always `<issuer>/.well-known/jwks.json`.\n */\n issuer: string;\n /** Exact match for the JWT `aud` claim — your partner MCP's stable URL. */\n audience: string;\n /** Required value for the `ext_provider` claim, e.g. `\"localfalcon\"`. */\n expectedExtProvider: string;\n /**\n * Clock skew tolerance for `iat` / `exp` validation. Accepts a jose duration\n * string (`\"30s\"`, `\"1m\"`) or a number of seconds.\n * @default \"30s\"\n */\n clockTolerance?: string | number;\n /**\n * JWKS cache max age in milliseconds. Cache is per-instance, not module-global.\n * @default 3_600_000 (1 hour)\n */\n jwksCacheMaxAgeMs?: number;\n}\n\n/** A verified Partner MCP Spec v1 JWT claim set. */\nexport interface PartnerTokenClaims {\n /** The external user id (verified non-empty). */\n sub: string;\n /** Space-separated scope string, per RFC 8693. May be empty but always present. */\n scope: string;\n /** External auth provider name; verified against {@link PartnerMcpOptions.expectedExtProvider}. */\n ext_provider: string;\n /** Unique token id. Non-empty. Partners build replay caches keyed by this. */\n jti: string;\n /** Already validated against {@link PartnerMcpOptions.issuer}; returned for audit logs. */\n iss: string;\n /** Already validated against {@link PartnerMcpOptions.audience}; returned for audit logs. */\n aud: string;\n /** Unix seconds. */\n iat: number;\n /** Unix seconds. */\n exp: number;\n /** AgentPress org identifier, optional. */\n org_id?: string;\n /** AgentPress thread identifier, optional. */\n thread_id?: string;\n /** Reserved for multi-tenant partner flows. */\n settings_id?: string;\n /** Forward-compat: any additional claims pass through. */\n [key: string]: unknown;\n}\n\n/** Parameters for {@link WebhooksClient.verifyKeyRotation}. */\nexport interface KeyRotationVerifyParams {\n /** Raw request body (string or Buffer) — must not be parsed/modified. */\n payload: string | Buffer;\n /**\n * Incoming HTTP headers. Accepts plain `Record<string, string | undefined>`\n * so Hono / Fastify / Express / Fetch / Worker all work interchangeably.\n * Must include `x-agentpress-signature` and `x-agentpress-timestamp`.\n */\n headers: Record<string, string | undefined>;\n}\n\n/** A verified `signing_key_rotation` webhook payload. */\nexport interface KeyRotationEvent {\n event: \"signing_key_rotation\";\n type: \"scheduled\" | \"emergency\";\n retiredKid: string;\n newCurrentKid: string;\n /** ISO 8601 timestamp. */\n retiredAt: string;\n /** ISO 8601 timestamp. */\n effectiveAt: string;\n /** Matches the configured partner JWKS URL. */\n jwksUrl: string;\n /** Present only on `type: \"emergency\"` rotations. */\n reason?: string;\n}\n\n/** Parameters for {@link WebhooksClient.send}. */\nexport interface WebhookSendParams {\n /** Webhook action name (matches an action rule on the server). */\n action: string;\n /** Arbitrary payload data forwarded to the webhook handler. */\n payload: Record<string, unknown>;\n}\n\n/** Parameters for verifying an inbound webhook signature via {@link WebhooksClient.verify} or {@link WebhooksClient.verifyOrThrow}. */\nexport interface WebhookVerifyParams {\n /** Raw request body (string or Buffer) -- must not be parsed/modified. */\n payload: string | Buffer;\n /** Svix signature headers from the incoming request. */\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n };\n}\n\n/** Response from webhook send operations. */\nexport interface WebhookResponse {\n success: boolean;\n /** UUID of the created action (present on successful creation). */\n actionId?: string;\n /** `true` if an action with the same `externalId` already existed (idempotency). */\n alreadyExists?: boolean;\n skipped?: boolean;\n data?: Record<string, unknown>;\n}\n\n// ── Action Lifecycle Event Types ────────────────────────────────────\n\n/** Action lifecycle event types emitted by AgentPress. */\nexport type ActionEventType =\n | \"action.pending_approval\"\n | \"action.approved\"\n | \"action.completed\"\n | \"action.failed\"\n | \"action.rejected\"\n | \"action.expired\";\n\n/** All public action callback event types emitted by AgentPress. */\nexport const ACTION_EVENT_TYPES: readonly ActionEventType[] = [\n \"action.pending_approval\",\n \"action.approved\",\n \"action.completed\",\n \"action.failed\",\n \"action.rejected\",\n \"action.expired\",\n] as const;\n\n/** Structured approval summary for a staged tool call. */\nexport interface StagedToolCallSummary {\n /** Short action phrase, suitable for headings. */\n title: string;\n /** Full approval request sentence with the key action details. */\n detail: string;\n}\n\n/** A tool call staged for approval lifecycle callbacks. */\nexport interface StagedToolCall {\n toolName: string;\n toolCallId: string;\n arguments: Record<string, unknown>;\n /**\n * Generated approval summary. New callbacks use the structured shape; legacy\n * callbacks may contain a plain string.\n */\n summary?: string | StagedToolCallSummary;\n}\n\n/** Parameters for {@link ActionsClient.approve}. */\nexport interface ApproveActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Optionally modify the tool call arguments before execution. */\n editedToolCall?: {\n toolName: string;\n arguments: Record<string, unknown>;\n };\n /**\n * If `\"webhook\"`, also auto-approves future triggers of the same\n * `(user, webhook, tool)` combination — same effect as the UI's\n * \"Always allow for this webhook\" option.\n *\n * - `\"once\"` — approve only this action (default behavior).\n * - `\"webhook\"` — approve and remember for future triggers.\n */\n remember?: \"once\" | \"webhook\";\n}\n\n/** Parameters for {@link ActionsClient.reject}. */\nexport interface RejectActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Reason for rejection. */\n reason?: string;\n}\n\n/** Response from action approve/reject operations. */\nexport interface ActionManageResponse {\n success: boolean;\n actionId: string;\n status: ActionStatus;\n}\n\n// ── Outbound Webhook (Action Callback) Types ──────────────────────────\n\n/** Status of an action in the AgentPress system. */\nexport type ActionStatus =\n | \"pending\"\n | \"staged\"\n | \"approved\"\n | \"executing\"\n | \"rejected\"\n | \"completed\"\n | \"failed\"\n | \"expired\";\n\n/** A tool call made by the agent during action processing. */\nexport interface ToolCallResult {\n toolName: string;\n arguments: Record<string, unknown>;\n result: unknown;\n}\n\n/** The agent's response after processing an action. */\nexport interface AgentResponse {\n /** The agent's text response, if any. */\n text: string | null;\n /** Tool calls made by the agent during processing. */\n toolCalls: ToolCallResult[];\n}\n\n/**\n * Payload received from AgentPress outbound webhooks (post-event callbacks).\n * This is what your server receives for approval, terminal, and failure events.\n */\nexport interface ActionCallbackPayload {\n actionId: string;\n status: ActionStatus;\n actionType: string;\n /** Lifecycle event type (e.g., \"action.pending_approval\", \"action.completed\"). */\n eventType: ActionEventType;\n /** Webhook action identifier used to create this action. Needed for approve/reject. */\n webhookAction: string | null;\n /** Tool staged for approval lifecycle events when available. */\n stagedToolCall: StagedToolCall | null;\n /** ISO 8601 timestamp of when this callback event occurred. */\n occurredAt: string;\n /** ISO 8601 timestamp retained for backwards compatibility. */\n completedAt: string;\n /** Human-readable execution summary when populated on the action. */\n resultSummary: string | null;\n /** Original data from the inbound webhook that triggered this action. */\n sourceData: Record<string, unknown>;\n /** External system identifier. */\n externalId: string | null;\n /** AgentPress user ID associated with this action. */\n userId: string | null;\n /** Thread ID if the action created a conversation. */\n threadId: string | null;\n /** The agent's response including text and tool call results. */\n agentResponse: AgentResponse;\n /** Error message if the action failed. */\n errorMessage: string | null;\n /** Reason provided if the action was rejected by a human reviewer. */\n rejectionReason: string | null;\n /** Additional custom fields from post-event configuration. */\n [key: string]: unknown;\n}\n\n// ── User Tool Approvals ─────────────────────────────────────────────\n\n/** Mode of a user tool approval rule. */\nexport type ApprovalMode = \"always_allow\" | \"always_deny\";\n\n/**\n * A persisted rule that auto-approves (or auto-denies) a specific\n * `(user, webhook, tool)` triple, bypassing the per-action approval prompt.\n * Dates are ISO 8601 strings on the wire.\n */\nexport interface UserToolApproval {\n id: string;\n orgId: string;\n userId: string;\n actionWebhookId: string;\n toolName: string;\n mode: ApprovalMode;\n /** ISO 8601 timestamp. `null` means never expires. */\n expiresAt: string | null;\n /** ISO 8601 timestamp. */\n createdAt: string;\n /** ISO 8601 timestamp. */\n updatedAt: string;\n}\n\n/** Parameters for {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsParams {\n /** Webhook identifier (slug) — required to scope the signing secret and the result. */\n webhookIdentifier: string;\n /**\n * Filter to a single user's approvals. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId?: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`.\n */\n authProvider?: string;\n}\n\n/** Response from {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsResponse {\n approvals: UserToolApproval[];\n}\n\n/** Parameters for {@link UserApprovalsClient.create}. */\nexport interface CreateUserApprovalParams {\n /** Webhook identifier (slug) — required to scope the signing secret. */\n webhookIdentifier: string;\n /**\n * User identifier this rule applies to. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`. The user must have authenticated through the\n * provider at least once for resolution to succeed.\n */\n authProvider?: string;\n /** UUID of the `action_webhooks` row. Must match the webhook identified by `webhookIdentifier`. */\n actionWebhookId: string;\n /** Name of the tool this rule covers. */\n toolName: string;\n /** @default \"always_allow\" */\n mode?: ApprovalMode;\n /** `null` or omitted = never expires. */\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.update}. */\nexport interface UpdateUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n mode?: ApprovalMode;\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.delete}. */\nexport interface DeleteUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n}\n\n/** @internal Resolved (validated, defaulted) options. Not exported from the public API. */\nexport interface ResolvedOptions {\n baseUrl: string;\n timeout: number;\n org: string;\n webhookSecret?: string;\n apiKey?: string;\n partnerMcp?: ResolvedPartnerMcpOptions;\n onRequest?: AgentPressOptions[\"onRequest\"];\n onResponse?: AgentPressOptions[\"onResponse\"];\n}\n\n/** @internal Resolved (validated, defaulted) partner MCP options. */\nexport interface ResolvedPartnerMcpOptions {\n jwksUrl: string;\n issuer: string;\n audience: string;\n expectedExtProvider: string;\n clockTolerance: string | number;\n jwksCacheMaxAgeMs: number;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["SIGNATURE_PREFIX","joseErrors","verifySig","verifyKeyRotationImpl"],"sources":["../src/errors.ts","../src/utils.ts","../src/webhooks/signing.ts","../src/actions/client.ts","../src/http.ts","../src/partners/client.ts","../src/userApprovals/client.ts","../src/webhooks/keyRotation.ts","../src/webhooks/client.ts","../src/client.ts","../src/types.ts"],"sourcesContent":["/**\n * Base error class for all SDK errors. Catch this to handle any error\n * thrown by the AgentPress SDK regardless of specific type.\n */\nexport class AgentPressError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentPressError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown at construction time when `AgentPressOptions` contains invalid values\n * (e.g., non-positive timeout, malformed `webhookSecret`).\n */\nexport class ConfigurationError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when the API returns a non-2xx HTTP response.\n *\n * Properties:\n * - `statusCode` - HTTP status code (e.g., 401, 404, 500)\n * - `responseBody` - Raw response body text for debugging\n * - `url` - The full request URL that failed\n */\nexport class HttpError extends AgentPressError {\n public readonly statusCode: number;\n public readonly responseBody: string;\n public readonly url: string;\n\n constructor(statusCode: number, responseBody: string, url: string) {\n super(`HTTP ${statusCode} from ${url}`);\n this.name = \"HttpError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n this.url = url;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a request exceeds the configured `timeout` (default 30s). */\nexport class TimeoutError extends AgentPressError {\n constructor(url: string, timeout: number) {\n super(`Request to ${url} timed out after ${timeout}ms`);\n this.name = \"TimeoutError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown by {@link WebhooksClient.verifyOrThrow} when an inbound webhook signature is invalid or expired. */\nexport class WebhookSignatureError extends AgentPressError {\n constructor(message: string) {\n super(message);\n this.name = \"WebhookSignatureError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link PartnerTokenError}. Maps 1:1 to RFC 6750 `error_description` values. */\nexport type PartnerTokenErrorReason =\n | \"signature_invalid\"\n | \"issuer_mismatch\"\n | \"audience_mismatch\"\n | \"expired\"\n | \"not_yet_valid\"\n | \"missing_claim\"\n | \"ext_provider_mismatch\"\n | \"algorithm_not_allowed\"\n | \"kid_missing_or_unknown\"\n | \"malformed\";\n\n/**\n * Thrown by {@link PartnersClient.verifyToken} when a Partner MCP Spec v1 JWT\n * fails verification. Partners map `reason` to their RFC 6750 `WWW-Authenticate`\n * response (`401 invalid_token` for all reasons in this class).\n */\nexport class PartnerTokenError extends AgentPressError {\n public readonly reason: PartnerTokenErrorReason;\n\n constructor(reason: PartnerTokenErrorReason, message: string) {\n super(message);\n this.name = \"PartnerTokenError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Reason codes for {@link KeyRotationVerifyError}. */\nexport type KeyRotationVerifyErrorReason =\n | \"invalid_signature\"\n | \"invalid_signature_format\"\n | \"timestamp_out_of_window\"\n | \"invalid_timestamp\"\n | \"payload_too_large\"\n | \"malformed_payload\";\n\n/**\n * Thrown by {@link WebhooksClient.verifyKeyRotation} when a `signing_key_rotation`\n * webhook fails HMAC / timestamp / payload validation.\n */\nexport class KeyRotationVerifyError extends AgentPressError {\n public readonly reason: KeyRotationVerifyErrorReason;\n\n constructor(reason: KeyRotationVerifyErrorReason, message: string) {\n super(message);\n this.name = \"KeyRotationVerifyError\";\n this.reason = reason;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nexport function randomMessageId(): string {\n return `msg_${randomUUID()}`;\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nconst SIGNATURE_PREFIX = \"v1,\";\nconst DEFAULT_TOLERANCE_SECONDS = 5 * 60; // 5 minutes\n\n/**\n * Sign a webhook payload using Svix-compatible HMAC-SHA256.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param msgId - Unique message ID (e.g., \"msg_<uuid>\")\n * @param timestamp - Unix timestamp in seconds\n * @param body - JSON stringified payload\n * @returns Signature string in format \"v1,<base64>\"\n */\nexport function sign(\n secret: string,\n msgId: string,\n timestamp: number,\n body: string,\n): string {\n const secretBytes = Buffer.from(secret.replace(/^whsec_/, \"\"), \"base64\");\n const message = `${msgId}.${timestamp}.${body}`;\n const signature = createHmac(\"sha256\", secretBytes)\n .update(message)\n .digest(\"base64\");\n return `${SIGNATURE_PREFIX}${signature}`;\n}\n\n/**\n * Verify a Svix webhook signature.\n *\n * @param secret - The webhook secret (with \"whsec_\" prefix)\n * @param payload - Raw request body (string or Buffer)\n * @param headers - Svix headers object\n * @param toleranceSeconds - Max age of signature in seconds (default: 5 min)\n * @returns true if valid, false if invalid or expired\n */\nexport function verify(\n secret: string,\n payload: string | Buffer,\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n },\n toleranceSeconds: number = DEFAULT_TOLERANCE_SECONDS,\n): boolean {\n const msgId = headers[\"svix-id\"];\n const timestampStr = headers[\"svix-timestamp\"];\n const signatureHeader = headers[\"svix-signature\"];\n\n const timestamp = parseInt(timestampStr, 10);\n if (Number.isNaN(timestamp)) return false;\n\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > toleranceSeconds) return false;\n\n const body =\n typeof payload === \"string\" ? payload : payload.toString(\"utf-8\");\n const expected = sign(secret, msgId, timestamp, body);\n\n const signatures = signatureHeader.split(\" \");\n const expectedBuf = Buffer.from(expected);\n\n for (const sig of signatures) {\n const sigBuf = Buffer.from(sig);\n if (\n sigBuf.length === expectedBuf.length &&\n timingSafeEqual(sigBuf, expectedBuf)\n ) {\n return true;\n }\n }\n\n return false;\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionManageResponse,\n ApproveActionParams,\n RejectActionParams,\n ResolvedOptions,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for programmatically approving or rejecting staged actions.\n * Uses HMAC-SHA256 signing (Svix-compatible), identical to {@link WebhooksClient}.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Approve a staged action\n * await client.actions.approve(\"act_123\", {\n * action: \"my_webhook_action\",\n * });\n *\n * // Reject with a reason\n * await client.actions.reject(\"act_456\", {\n * action: \"my_webhook_action\",\n * reason: \"Insufficient data\",\n * });\n * ```\n */\nexport class ActionsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Approve a staged action, optionally modifying the tool call.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async approve(\n actionId: string,\n params: ApproveActionParams,\n ): Promise<ActionManageResponse> {\n const body: Record<string, unknown> = {};\n if (params.editedToolCall !== undefined) {\n body.editedToolCall = params.editedToolCall;\n }\n if (params.remember !== undefined) {\n body.remember = params.remember;\n }\n return this.manage(actionId, params.action, \"approve\", body);\n }\n\n /**\n * Reject a staged action.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async reject(\n actionId: string,\n params: RejectActionParams,\n ): Promise<ActionManageResponse> {\n return this.manage(actionId, params.action, \"reject\", {\n reason: params.reason,\n });\n }\n\n private async manage(\n actionId: string,\n webhookAction: string,\n operation: \"approve\" | \"reject\",\n body: Record<string, unknown>,\n ): Promise<ActionManageResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for action management operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${webhookAction}/manage/${actionId}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<ActionManageResponse>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { AgentPressError, HttpError, TimeoutError } from \"./errors\";\nimport type { ResolvedOptions } from \"./types\";\n\n/**\n * Internal shared HTTP client. Not part of the public API -- used by\n * namespace clients (e.g., `WebhooksClient`) to make authenticated requests.\n * @internal\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly onRequest?: ResolvedOptions[\"onRequest\"];\n private readonly onResponse?: ResolvedOptions[\"onResponse\"];\n\n constructor(options: ResolvedOptions) {\n this.baseUrl = options.baseUrl;\n this.timeout = options.timeout;\n this.onRequest = options.onRequest;\n this.onResponse = options.onResponse;\n }\n\n /**\n * Send an HTTP request to the API. Constructs the full URL from `baseUrl` + `path`,\n * applies the configured timeout via `AbortSignal`, fires `onRequest`/`onResponse`\n * hooks, and parses the JSON response.\n *\n * @throws {TimeoutError} If the request exceeds the configured timeout.\n * @throws {HttpError} If the API returns a non-2xx status code.\n * @throws {AgentPressError} On network failures or non-JSON responses.\n */\n async request<T>(path: string, init: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers = new Headers(init.headers);\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n const requestInit: RequestInit = {\n ...init,\n headers,\n signal: AbortSignal.timeout(this.timeout),\n };\n\n this.onRequest?.(url, requestInit);\n\n let response: Response;\n try {\n response = await fetch(url, requestInit);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n (error.name === \"TimeoutError\" || error.name === \"AbortError\")\n ) {\n throw new TimeoutError(url, this.timeout);\n }\n const message =\n error instanceof Error ? error.message : \"Unknown fetch error\";\n throw new AgentPressError(`Request to ${url} failed: ${message}`);\n }\n\n this.onResponse?.(url, response.clone());\n\n const text = await response.text();\n\n if (!response.ok) {\n throw new HttpError(response.status, text, url);\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new AgentPressError(\n `Expected JSON response from ${url} but received: ${text.slice(0, 200)}`,\n );\n }\n }\n}\n","import {\n createRemoteJWKSet,\n type JWTVerifyGetKey,\n errors as joseErrors,\n jwtVerify,\n} from \"jose\";\n\nimport { ConfigurationError, PartnerTokenError } from \"../errors\";\nimport type {\n PartnerTokenClaims,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"../types\";\n\nconst ALGORITHMS = [\"EdDSA\"] as const;\n\ntype RemoteJwks = ReturnType<typeof createRemoteJWKSet>;\n\n/**\n * Client for Partner MCP Spec v1 helpers. Created automatically when\n * {@link AgentPressOptions.partnerMcp} is provided.\n *\n * State (JWKS cache) is per-instance, NOT module-global, so staging and\n * production clients can run side-by-side without cross-talk.\n */\nexport class PartnersClient {\n private readonly options: ResolvedOptions;\n private readonly partnerMcp: ResolvedPartnerMcpOptions | undefined;\n private jwks: RemoteJwks | null = null;\n private jwksKeyFn: JWTVerifyGetKey | null = null;\n\n constructor(options: ResolvedOptions) {\n this.options = options;\n this.partnerMcp = options.partnerMcp;\n }\n\n /**\n * Verify an inbound Partner MCP Spec v1 JWT against AgentPress's JWKS.\n *\n * Enforces the full spec: `algorithms: [\"EdDSA\"]` pinned; `iss`, `aud`,\n * `ext_provider` validated; `sub`, `jti`, `scope` required and non-empty;\n * `kid` header required; `exp` / `iat` validated with ±30s skew (configurable).\n *\n * @param token - Bare JWT string (no `Bearer ` prefix).\n * @returns Typed {@link PartnerTokenClaims}.\n * @throws {PartnerTokenError} with a typed `reason` for RFC 6750 mapping.\n * @throws {ConfigurationError} if `partnerMcp` is not configured.\n */\n async verifyToken(token: string): Promise<PartnerTokenClaims> {\n const cfg = this.requireConfig();\n const jwks = this.getJwks();\n\n let payload: Record<string, unknown>;\n let protectedHeader: { alg?: string; kid?: string; typ?: string };\n\n try {\n const result = await jwtVerify(token, jwks, {\n algorithms: [...ALGORITHMS],\n issuer: cfg.issuer,\n audience: cfg.audience,\n clockTolerance: cfg.clockTolerance,\n });\n payload = result.payload as Record<string, unknown>;\n protectedHeader = result.protectedHeader as {\n alg?: string;\n kid?: string;\n typ?: string;\n };\n } catch (err) {\n throw mapJoseError(err);\n }\n\n // kid header required by spec. jose does not enforce this on its own\n // when the key is resolvable — we enforce it explicitly so forged\n // tokens that elide the kid header can't slip through on a single-key\n // JWKS.\n if (!protectedHeader.kid || typeof protectedHeader.kid !== \"string\") {\n throw new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"JWT header missing required 'kid'\",\n );\n }\n\n const claims = payload as PartnerTokenClaims & Record<string, unknown>;\n\n // jose's jwtVerify checks `exp` (with clockTolerance) but not `iat`\n // future-time unless `maxTokenAge` is set. The spec requires both sides\n // of the skew window, so enforce the future-iat check explicitly.\n if (typeof claims.iat !== \"number\" || !Number.isFinite(claims.iat)) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'iat' claim must be a number\",\n );\n }\n const toleranceSeconds = toSeconds(cfg.clockTolerance);\n const nowSec = Math.floor(Date.now() / 1000);\n if (claims.iat - nowSec > toleranceSeconds) {\n throw new PartnerTokenError(\n \"not_yet_valid\",\n `'iat' is ${claims.iat - nowSec}s in the future, beyond ${toleranceSeconds}s tolerance`,\n );\n }\n\n if (typeof claims.sub !== \"string\" || claims.sub.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'sub' claim is required\");\n }\n if (typeof claims.jti !== \"string\" || claims.jti.length === 0) {\n throw new PartnerTokenError(\"missing_claim\", \"'jti' claim is required\");\n }\n if (typeof claims.scope !== \"string\") {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'scope' claim must be a string\",\n );\n }\n if (\n typeof claims.ext_provider !== \"string\" ||\n claims.ext_provider.length === 0\n ) {\n throw new PartnerTokenError(\n \"missing_claim\",\n \"'ext_provider' claim is required\",\n );\n }\n if (claims.ext_provider !== cfg.expectedExtProvider) {\n throw new PartnerTokenError(\n \"ext_provider_mismatch\",\n `ext_provider '${claims.ext_provider}' does not match expected '${cfg.expectedExtProvider}'`,\n );\n }\n\n return claims;\n }\n\n /**\n * Force the JWKS cache to refetch immediately. Call this from your\n * `signing_key_rotation` webhook handler after verifying the webhook —\n * otherwise the cache picks up new keys on the next `kid` miss (which\n * works, but with one failed verify latency penalty).\n */\n async refreshJwks(): Promise<void> {\n const jwks = this.getJwks();\n // jose's RemoteJWKSet exposes `.reload()` for exactly this use case.\n const anyJwks = jwks as unknown as { reload?: () => Promise<void> };\n if (typeof anyJwks.reload === \"function\") {\n await anyJwks.reload();\n }\n }\n\n private requireConfig(): ResolvedPartnerMcpOptions {\n if (!this.partnerMcp) {\n throw new ConfigurationError(\n \"partnerMcp options are required for partner token operations\",\n );\n }\n return this.partnerMcp;\n }\n\n private getJwks(): RemoteJwks {\n const cfg = this.requireConfig();\n if (!this.jwks) {\n this.jwks = createRemoteJWKSet(new URL(cfg.jwksUrl), {\n cacheMaxAge: cfg.jwksCacheMaxAgeMs,\n cooldownDuration: 30_000,\n });\n this.jwksKeyFn = this.jwks as unknown as JWTVerifyGetKey;\n }\n return this.jwks;\n }\n}\n\nfunction toSeconds(tolerance: string | number): number {\n if (typeof tolerance === \"number\") return tolerance;\n const match = tolerance.trim().match(/^(\\d+)\\s*(s|m|h)$/i);\n if (!match) return 30;\n const n = Number.parseInt(match[1] as string, 10);\n const unit = (match[2] as string).toLowerCase();\n if (unit === \"s\") return n;\n if (unit === \"m\") return n * 60;\n if (unit === \"h\") return n * 3600;\n return 30;\n}\n\nfunction mapJoseError(err: unknown): PartnerTokenError {\n if (err instanceof PartnerTokenError) return err;\n\n if (err instanceof joseErrors.JWSSignatureVerificationFailed) {\n return new PartnerTokenError(\n \"signature_invalid\",\n \"JWT signature verification failed\",\n );\n }\n if (err instanceof joseErrors.JWKSNoMatchingKey) {\n return new PartnerTokenError(\n \"kid_missing_or_unknown\",\n \"No JWKS key matches the JWT 'kid' header\",\n );\n }\n if (err instanceof joseErrors.JOSEAlgNotAllowed) {\n return new PartnerTokenError(\n \"algorithm_not_allowed\",\n \"JWT 'alg' is not EdDSA\",\n );\n }\n if (err instanceof joseErrors.JWTExpired) {\n return new PartnerTokenError(\"expired\", \"JWT has expired\");\n }\n if (err instanceof joseErrors.JWTClaimValidationFailed) {\n const claim = (err as { claim?: string }).claim;\n if (claim === \"iss\") {\n return new PartnerTokenError(\n \"issuer_mismatch\",\n \"JWT 'iss' does not match expected issuer\",\n );\n }\n if (claim === \"aud\") {\n return new PartnerTokenError(\n \"audience_mismatch\",\n \"JWT 'aud' does not match expected audience\",\n );\n }\n if (claim === \"iat\") {\n return new PartnerTokenError(\n \"not_yet_valid\",\n \"JWT 'iat' is in the future beyond clock tolerance\",\n );\n }\n return new PartnerTokenError(\n \"missing_claim\",\n err.message || \"Claim validation failed\",\n );\n }\n if (\n err instanceof joseErrors.JWTInvalid ||\n err instanceof joseErrors.JWSInvalid\n ) {\n return new PartnerTokenError(\"malformed\", err.message || \"Malformed JWT\");\n }\n if (err instanceof Error) {\n return new PartnerTokenError(\"malformed\", err.message);\n }\n return new PartnerTokenError(\"malformed\", String(err));\n}\n","import { ConfigurationError } from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n CreateUserApprovalParams,\n DeleteUserApprovalParams,\n ListUserApprovalsParams,\n ListUserApprovalsResponse,\n ResolvedOptions,\n UpdateUserApprovalParams,\n UserToolApproval,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { sign } from \"../webhooks/signing\";\n\n/**\n * Client for managing per-user auto-approval rules — the SDK equivalent of the\n * console's `/account/auto-approvals` settings page. Uses HMAC-SHA256 signing\n * (Svix-compatible), identical to {@link ActionsClient.manage}.\n *\n * Each call is scoped to a single webhook (identified by `webhookIdentifier`),\n * which both selects the signing secret and scopes which approvals are visible.\n *\n * @example\n * ```ts\n * const client = new AgentPress({ webhookSecret: \"whsec_...\", org: \"my-org\" });\n *\n * // Provision consent so future \"sendEmail\" triggers skip the approval prompt\n * await client.userApprovals.create({\n * webhookIdentifier: \"reviews\",\n * userId: \"user-uuid\",\n * actionWebhookId: \"webhook-uuid\",\n * toolName: \"sendEmail\",\n * mode: \"always_allow\",\n * });\n *\n * // List rules (optionally filtered by userId)\n * const { approvals } = await client.userApprovals.list({\n * webhookIdentifier: \"reviews\",\n * });\n *\n * // Revoke\n * await client.userApprovals.delete(approvalId, { webhookIdentifier: \"reviews\" });\n * ```\n */\nexport class UserApprovalsClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * List auto-approval rules for a webhook. Optionally filter by `userId`.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async list(\n params: ListUserApprovalsParams,\n ): Promise<ListUserApprovalsResponse> {\n const body: Record<string, unknown> = {};\n if (params.userId !== undefined) body.userId = params.userId;\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n return this.send<ListUserApprovalsResponse>(\n params.webhookIdentifier,\n \"list\",\n body,\n );\n }\n\n /**\n * Create (or upsert) an auto-approval rule. If a rule with the same\n * `(userId, actionWebhookId, toolName)` triple already exists, it is\n * updated in place.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async create(params: CreateUserApprovalParams): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {\n userId: params.userId,\n actionWebhookId: params.actionWebhookId,\n toolName: params.toolName,\n mode: params.mode ?? \"always_allow\",\n };\n if (params.authProvider !== undefined)\n body.authProvider = params.authProvider;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n \"create\",\n body,\n );\n }\n\n /**\n * Patch an existing auto-approval rule (change mode or expiry).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async update(\n id: string,\n params: UpdateUserApprovalParams,\n ): Promise<UserToolApproval> {\n const body: Record<string, unknown> = {};\n if (params.mode !== undefined) body.mode = params.mode;\n if (params.expiresAt !== undefined) {\n body.expiresAt =\n params.expiresAt === null ? null : params.expiresAt.toISOString();\n }\n return this.send<UserToolApproval>(\n params.webhookIdentifier,\n `update/${id}`,\n body,\n );\n }\n\n /**\n * Revoke an auto-approval rule. Future triggers of the corresponding\n * `(user, webhook, tool)` combination will once again stage for approval.\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response (404 if the rule does not belong to this webhook)\n * @throws TimeoutError if request exceeds timeout\n */\n async delete(\n id: string,\n params: DeleteUserApprovalParams,\n ): Promise<{ success: boolean }> {\n return this.send<{ success: boolean }>(\n params.webhookIdentifier,\n `delete/${id}`,\n {},\n );\n }\n\n /** Internal: HMAC-sign and POST the body to the scoped path. */\n private async send<T>(\n webhookIdentifier: string,\n operation: string,\n body: Record<string, unknown>,\n ): Promise<T> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for user approval management operations\",\n );\n }\n\n const path = `/webhooks/user-approvals/${this.options.org}/${webhookIdentifier}/${operation}`;\n const bodyStr = JSON.stringify(body);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(\n this.options.webhookSecret,\n msgId,\n timestamp,\n bodyStr,\n );\n\n return this.http.request<T>(path, {\n method: \"POST\",\n body: bodyStr,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nimport { ConfigurationError, KeyRotationVerifyError } from \"../errors\";\nimport type { KeyRotationEvent, KeyRotationVerifyParams } from \"../types\";\n\nconst MAX_PAYLOAD_BYTES = 8 * 1024; // 8 KB\nconst TIMESTAMP_SKEW_SECONDS = 300; // 5 minutes\nconst SIGNATURE_PREFIX = \"sha256=\";\n\n/**\n * Verify a `signing_key_rotation` webhook signed by AgentPress with\n * HMAC-SHA256 over the raw request body. Returns the typed\n * {@link KeyRotationEvent} payload.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping.\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\nexport function verifyKeyRotation(\n secret: string | undefined,\n params: KeyRotationVerifyParams,\n): KeyRotationEvent {\n if (!secret) {\n throw new ConfigurationError(\n \"webhookSecret is required for key rotation webhook verification\",\n );\n }\n\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n\n const byteLength =\n typeof params.payload === \"string\"\n ? Buffer.byteLength(params.payload, \"utf-8\")\n : params.payload.length;\n if (byteLength > MAX_PAYLOAD_BYTES) {\n throw new KeyRotationVerifyError(\n \"payload_too_large\",\n `Payload exceeds ${MAX_PAYLOAD_BYTES} bytes`,\n );\n }\n\n const signatureHeader = readHeader(params.headers, \"x-agentpress-signature\");\n const timestampHeader = readHeader(params.headers, \"x-agentpress-timestamp\");\n\n if (!signatureHeader?.startsWith(SIGNATURE_PREFIX)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n `Signature header missing or does not start with '${SIGNATURE_PREFIX}'`,\n );\n }\n const providedHex = signatureHeader\n .slice(SIGNATURE_PREFIX.length)\n .toLowerCase();\n if (!/^[0-9a-f]+$/.test(providedHex)) {\n throw new KeyRotationVerifyError(\n \"invalid_signature_format\",\n \"Signature is not a hex string\",\n );\n }\n\n if (!timestampHeader) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp header is required\",\n );\n }\n const timestamp = Number.parseInt(timestampHeader, 10);\n if (\n !Number.isFinite(timestamp) ||\n String(timestamp) !== timestampHeader.trim()\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_timestamp\",\n \"x-agentpress-timestamp is not a valid unix seconds integer\",\n );\n }\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestamp) > TIMESTAMP_SKEW_SECONDS) {\n throw new KeyRotationVerifyError(\n \"timestamp_out_of_window\",\n `Timestamp skew ${Math.abs(now - timestamp)}s exceeds ${TIMESTAMP_SKEW_SECONDS}s tolerance`,\n );\n }\n\n const expectedHex = createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n const providedBuf = Buffer.from(providedHex, \"hex\");\n const expectedBuf = Buffer.from(expectedHex, \"hex\");\n if (\n providedBuf.length !== expectedBuf.length ||\n !timingSafeEqual(providedBuf, expectedBuf)\n ) {\n throw new KeyRotationVerifyError(\n \"invalid_signature\",\n \"HMAC signature mismatch\",\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload is not valid JSON\",\n );\n }\n\n return validatePayload(parsed);\n}\n\nfunction readHeader(\n headers: Record<string, string | undefined>,\n name: string,\n): string | undefined {\n // Headers are case-insensitive; normalize without mutating the caller's object.\n const lowered = name.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lowered && typeof v === \"string\" && v.length > 0) {\n return v;\n }\n }\n return undefined;\n}\n\nfunction validatePayload(raw: unknown): KeyRotationEvent {\n if (!raw || typeof raw !== \"object\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"Payload must be a JSON object\",\n );\n }\n const obj = raw as Record<string, unknown>;\n if (obj.event !== \"signing_key_rotation\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `Unexpected event '${String(obj.event)}'`,\n );\n }\n if (obj.type !== \"scheduled\" && obj.type !== \"emergency\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'type' must be 'scheduled' or 'emergency'\",\n );\n }\n for (const key of [\n \"retiredKid\",\n \"newCurrentKid\",\n \"retiredAt\",\n \"effectiveAt\",\n \"jwksUrl\",\n ]) {\n if (typeof obj[key] !== \"string\" || (obj[key] as string).length === 0) {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n `'${key}' must be a non-empty string`,\n );\n }\n }\n if (obj.reason !== undefined && typeof obj.reason !== \"string\") {\n throw new KeyRotationVerifyError(\n \"malformed_payload\",\n \"'reason' must be a string when present\",\n );\n }\n\n const event: KeyRotationEvent = {\n event: \"signing_key_rotation\",\n type: obj.type as \"scheduled\" | \"emergency\",\n retiredKid: obj.retiredKid as string,\n newCurrentKid: obj.newCurrentKid as string,\n retiredAt: obj.retiredAt as string,\n effectiveAt: obj.effectiveAt as string,\n jwksUrl: obj.jwksUrl as string,\n };\n if (typeof obj.reason === \"string\") {\n event.reason = obj.reason;\n }\n return event;\n}\n","import {\n AgentPressError,\n ConfigurationError,\n WebhookSignatureError,\n} from \"../errors\";\nimport type { HttpClient } from \"../http\";\nimport type {\n ActionCallbackPayload,\n KeyRotationEvent,\n KeyRotationVerifyParams,\n ResolvedOptions,\n WebhookResponse,\n WebhookSendParams,\n WebhookVerifyParams,\n} from \"../types\";\nimport { randomMessageId } from \"../utils\";\nimport { verifyKeyRotation as verifyKeyRotationImpl } from \"./keyRotation\";\nimport { sign, verify as verifySig } from \"./signing\";\n\nexport class WebhooksClient {\n private readonly options: ResolvedOptions;\n private readonly http: HttpClient;\n\n constructor(options: ResolvedOptions, http: HttpClient) {\n this.options = options;\n this.http = http;\n }\n\n /**\n * Send an arbitrary webhook payload to AgentPress.\n * Signs the payload with HMAC-SHA256 (Svix-compatible).\n *\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws HttpError on non-2xx response\n * @throws TimeoutError if request exceeds timeout\n */\n async send(params: WebhookSendParams): Promise<WebhookResponse> {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook operations\",\n );\n }\n\n const path = `/webhooks/actions/${this.options.org}/${params.action}`;\n const body = JSON.stringify(params.payload);\n const msgId = randomMessageId();\n const timestamp = Math.floor(Date.now() / 1000);\n const signature = sign(this.options.webhookSecret, msgId, timestamp, body);\n\n return this.http.request<WebhookResponse>(path, {\n method: \"POST\",\n body,\n headers: {\n \"svix-id\": msgId,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": signature,\n },\n });\n }\n\n /**\n * Verify an inbound Svix webhook signature.\n *\n * @returns true if valid, false if invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verify(params: WebhookVerifyParams): boolean {\n if (!this.options.webhookSecret) {\n throw new ConfigurationError(\n \"webhookSecret is required for webhook verification\",\n );\n }\n\n return verifySig(\n this.options.webhookSecret,\n params.payload,\n params.headers,\n );\n }\n\n /**\n * Verify an inbound Svix webhook signature, throwing on failure.\n * Useful for middleware patterns where invalid signatures should halt processing.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n */\n verifyOrThrow(params: WebhookVerifyParams): void {\n if (!this.verify(params)) {\n throw new WebhookSignatureError(\"Invalid webhook signature\");\n }\n }\n\n /**\n * Verify and parse an inbound webhook from AgentPress.\n * Combines signature verification with JSON parsing and type casting.\n * This is the recommended way to handle incoming webhooks.\n *\n * @throws WebhookSignatureError if signature is invalid or expired\n * @throws ConfigurationError if webhookSecret is not configured\n * @throws AgentPressError if payload is not valid JSON\n */\n constructEvent(params: WebhookVerifyParams): ActionCallbackPayload {\n this.verifyOrThrow(params);\n const body =\n typeof params.payload === \"string\"\n ? params.payload\n : params.payload.toString(\"utf-8\");\n try {\n return JSON.parse(body) as ActionCallbackPayload;\n } catch {\n throw new AgentPressError(\"Webhook payload is not valid JSON\");\n }\n }\n\n /**\n * Verify an inbound `signing_key_rotation` webhook (HMAC-SHA256 + timestamp\n * + typed payload) from AgentPress. See the Partner MCP Spec v1 for the\n * full contract.\n *\n * @throws {KeyRotationVerifyError} with a typed `reason` for HTTP mapping\n * (401 for signature errors, 400 for malformed payload, 413 for oversize).\n * @throws {ConfigurationError} if `webhookSecret` is not configured.\n */\n verifyKeyRotation(params: KeyRotationVerifyParams): KeyRotationEvent {\n return verifyKeyRotationImpl(this.options.webhookSecret, params);\n }\n}\n","import { ActionsClient } from \"./actions/client\";\nimport { ConfigurationError } from \"./errors\";\nimport { HttpClient } from \"./http\";\nimport { PartnersClient } from \"./partners/client\";\nimport type {\n AgentPressOptions,\n ResolvedOptions,\n ResolvedPartnerMcpOptions,\n} from \"./types\";\nimport { UserApprovalsClient } from \"./userApprovals/client\";\nimport { WebhooksClient } from \"./webhooks/client\";\n\n/**\n * Main entry point for the AgentPress SDK. Provides namespaced access to API\n * resources (e.g., `client.webhooks.send()`, `client.actions.approve()`).\n * Validates all configuration options at construction time, so invalid config fails fast.\n *\n * @example\n * ```ts\n * const client = new AgentPress({\n * apiKey: \"ak_...\",\n * webhookSecret: \"whsec_...\",\n * });\n * await client.webhooks.send({ action: \"my_action\", payload: { ... } });\n * await client.actions.approve(\"act_123\", { action: \"my_action\" });\n * ```\n */\nexport class AgentPress {\n /** Webhook operations: send outbound webhooks and verify inbound signatures. */\n public readonly webhooks: WebhooksClient;\n /** Action management: approve or reject staged actions. */\n public readonly actions: ActionsClient;\n /** Per-user auto-approval rules (read / create / update / delete). */\n public readonly userApprovals: UserApprovalsClient;\n /** Partner MCP Spec v1 helpers (inbound JWT verification, JWKS refresh). */\n public readonly partners: PartnersClient;\n\n /**\n * @param options - SDK configuration. All fields are optional with sensible defaults.\n * @throws {ConfigurationError} If `timeout` is non-positive or `webhookSecret` has an invalid prefix.\n */\n constructor(options: AgentPressOptions = {}) {\n const resolved = resolveOptions(options);\n const http = new HttpClient(resolved);\n this.webhooks = new WebhooksClient(resolved, http);\n this.actions = new ActionsClient(resolved, http);\n this.userApprovals = new UserApprovalsClient(resolved, http);\n this.partners = new PartnersClient(resolved);\n }\n}\n\nfunction resolveOptions(options: AgentPressOptions): ResolvedOptions {\n const baseUrl = (options.baseUrl ?? \"https://api.agent.press\").replace(\n /\\/+$/,\n \"\",\n );\n const timeout = options.timeout ?? 30_000;\n const org = options.org ?? \"default-org\";\n\n if (timeout <= 0 || !Number.isFinite(timeout)) {\n throw new ConfigurationError(\"timeout must be a positive number\");\n }\n\n if (\n options.webhookSecret !== undefined &&\n !options.webhookSecret.startsWith(\"whsec_\")\n ) {\n throw new ConfigurationError('webhookSecret must start with \"whsec_\"');\n }\n\n return {\n baseUrl,\n timeout,\n org,\n webhookSecret: options.webhookSecret,\n apiKey: options.apiKey,\n partnerMcp: resolvePartnerMcp(options.partnerMcp),\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n };\n}\n\nfunction resolvePartnerMcp(\n options: AgentPressOptions[\"partnerMcp\"],\n): ResolvedPartnerMcpOptions | undefined {\n if (!options) return undefined;\n\n if (typeof options.jwksUrl !== \"string\" || options.jwksUrl.length === 0) {\n throw new ConfigurationError(\"partnerMcp.jwksUrl is required\");\n }\n try {\n // Validate early so a bad URL fails at construction, not on first verify.\n new URL(options.jwksUrl);\n } catch {\n throw new ConfigurationError(\"partnerMcp.jwksUrl must be a valid URL\");\n }\n if (typeof options.issuer !== \"string\" || options.issuer.length === 0) {\n throw new ConfigurationError(\"partnerMcp.issuer is required\");\n }\n if (typeof options.audience !== \"string\" || options.audience.length === 0) {\n throw new ConfigurationError(\"partnerMcp.audience is required\");\n }\n if (\n typeof options.expectedExtProvider !== \"string\" ||\n options.expectedExtProvider.length === 0\n ) {\n throw new ConfigurationError(\"partnerMcp.expectedExtProvider is required\");\n }\n\n const clockTolerance = options.clockTolerance ?? \"30s\";\n const jwksCacheMaxAgeMs = options.jwksCacheMaxAgeMs ?? 3_600_000;\n if (jwksCacheMaxAgeMs <= 0 || !Number.isFinite(jwksCacheMaxAgeMs)) {\n throw new ConfigurationError(\n \"partnerMcp.jwksCacheMaxAgeMs must be a positive number\",\n );\n }\n\n return {\n jwksUrl: options.jwksUrl,\n issuer: options.issuer,\n audience: options.audience,\n expectedExtProvider: options.expectedExtProvider,\n clockTolerance,\n jwksCacheMaxAgeMs,\n };\n}\n","/** Constructor options for the {@link AgentPress} client. All fields are optional. */\nexport interface AgentPressOptions {\n /** Svix webhook signing secret for verifying inbound webhooks. Must start with `\"whsec_\"`. */\n webhookSecret?: string;\n /** API key for authenticated requests. */\n apiKey?: string;\n /** @default \"https://api.agent.press\" */\n baseUrl?: string;\n /** Request timeout in milliseconds. Must be a positive finite number. @default 30000 */\n timeout?: number;\n /** Organization identifier sent with requests. @default \"default-org\" */\n org?: string;\n /**\n * Partner MCP Spec v1 configuration. Required only if you call\n * {@link PartnersClient.verifyToken} or {@link WebhooksClient.verifyKeyRotation}.\n *\n * Each environment (staging / production) needs its own {@link AgentPress}\n * instance with its own `partnerMcp` block — never share a client between\n * environments. JWKS cache state is per-instance, so side-by-side staging\n * and prod clients have no cross-talk.\n */\n partnerMcp?: PartnerMcpOptions;\n /** Hook called before every outbound HTTP request (useful for logging/tracing). */\n onRequest?: (url: string, init: RequestInit) => void;\n /** Hook called after every HTTP response is received. */\n onResponse?: (url: string, response: Response) => void;\n}\n\n/** Partner MCP Spec v1 configuration. See {@link AgentPressOptions.partnerMcp}. */\nexport interface PartnerMcpOptions {\n /**\n * Full URL to the issuing AgentPress org's JWKS.\n * Per-org as of Partner MCP Spec v1 (per-org signing keys), e.g.\n * `https://api.agent.press/orgs/<org-slug>/.well-known/jwks.json`.\n * The org admin who registered you as a partner will give you the\n * exact URL along with their `<org-slug>`.\n */\n jwksUrl: string;\n /**\n * Exact match for the JWT `iss` claim. Per-org scoped, e.g.\n * `https://api.agent.press/orgs/<org-slug>`. The JWKS URL above is\n * always `<issuer>/.well-known/jwks.json`.\n */\n issuer: string;\n /** Exact match for the JWT `aud` claim — your partner MCP's stable URL. */\n audience: string;\n /** Required value for the `ext_provider` claim, e.g. `\"localfalcon\"`. */\n expectedExtProvider: string;\n /**\n * Clock skew tolerance for `iat` / `exp` validation. Accepts a jose duration\n * string (`\"30s\"`, `\"1m\"`) or a number of seconds.\n * @default \"30s\"\n */\n clockTolerance?: string | number;\n /**\n * JWKS cache max age in milliseconds. Cache is per-instance, not module-global.\n * @default 3_600_000 (1 hour)\n */\n jwksCacheMaxAgeMs?: number;\n}\n\n/** A verified Partner MCP Spec v1 JWT claim set. */\nexport interface PartnerTokenClaims {\n /** The external user id (verified non-empty). */\n sub: string;\n /** Space-separated scope string, per RFC 8693. May be empty but always present. */\n scope: string;\n /** External auth provider name; verified against {@link PartnerMcpOptions.expectedExtProvider}. */\n ext_provider: string;\n /** Unique token id. Non-empty. Partners build replay caches keyed by this. */\n jti: string;\n /** Already validated against {@link PartnerMcpOptions.issuer}; returned for audit logs. */\n iss: string;\n /** Already validated against {@link PartnerMcpOptions.audience}; returned for audit logs. */\n aud: string;\n /** Unix seconds. */\n iat: number;\n /** Unix seconds. */\n exp: number;\n /** AgentPress org identifier, optional. */\n org_id?: string;\n /** AgentPress thread identifier, optional. */\n thread_id?: string;\n /** Reserved for multi-tenant partner flows. */\n settings_id?: string;\n /** Forward-compat: any additional claims pass through. */\n [key: string]: unknown;\n}\n\n/** Parameters for {@link WebhooksClient.verifyKeyRotation}. */\nexport interface KeyRotationVerifyParams {\n /** Raw request body (string or Buffer) — must not be parsed/modified. */\n payload: string | Buffer;\n /**\n * Incoming HTTP headers. Accepts plain `Record<string, string | undefined>`\n * so Hono / Fastify / Express / Fetch / Worker all work interchangeably.\n * Must include `x-agentpress-signature` and `x-agentpress-timestamp`.\n */\n headers: Record<string, string | undefined>;\n}\n\n/** A verified `signing_key_rotation` webhook payload. */\nexport interface KeyRotationEvent {\n event: \"signing_key_rotation\";\n type: \"scheduled\" | \"emergency\";\n retiredKid: string;\n newCurrentKid: string;\n /** ISO 8601 timestamp. */\n retiredAt: string;\n /** ISO 8601 timestamp. */\n effectiveAt: string;\n /** Matches the configured partner JWKS URL. */\n jwksUrl: string;\n /** Present only on `type: \"emergency\"` rotations. */\n reason?: string;\n}\n\n/** Parameters for {@link WebhooksClient.send}. */\nexport interface WebhookSendParams {\n /** Webhook action name (matches an action rule on the server). */\n action: string;\n /** Arbitrary payload data forwarded to the webhook handler. */\n payload: Record<string, unknown>;\n}\n\n/** Parameters for verifying an inbound webhook signature via {@link WebhooksClient.verify} or {@link WebhooksClient.verifyOrThrow}. */\nexport interface WebhookVerifyParams {\n /** Raw request body (string or Buffer) -- must not be parsed/modified. */\n payload: string | Buffer;\n /** Svix signature headers from the incoming request. */\n headers: {\n \"svix-id\": string;\n \"svix-timestamp\": string;\n \"svix-signature\": string;\n };\n}\n\n/** Response from webhook send operations. */\nexport interface WebhookResponse {\n success: boolean;\n /** UUID of the created action (present on successful creation). */\n actionId?: string;\n /** `true` if an action with the same `externalId` already existed (idempotency). */\n alreadyExists?: boolean;\n skipped?: boolean;\n data?: Record<string, unknown>;\n}\n\n// ── Action Lifecycle Event Types ────────────────────────────────────\n\n/** Action lifecycle event types emitted by AgentPress. */\nexport type ActionEventType =\n | \"action.pending_approval\"\n | \"action.approved\"\n | \"action.completed\"\n | \"action.failed\"\n | \"action.rejected\"\n | \"action.expired\";\n\n/** All public action callback event types emitted by AgentPress. */\nexport const ACTION_EVENT_TYPES: readonly ActionEventType[] = [\n \"action.pending_approval\",\n \"action.approved\",\n \"action.completed\",\n \"action.failed\",\n \"action.rejected\",\n \"action.expired\",\n] as const;\n\n/** Structured approval summary for a staged tool call. */\nexport interface StagedToolCallSummary {\n /** Short action phrase, suitable for headings. */\n title: string;\n /** Full approval request sentence with the key action details. */\n detail: string;\n}\n\n/** A tool call staged for approval lifecycle callbacks. */\nexport interface StagedToolCall {\n toolName: string;\n toolCallId: string;\n arguments: Record<string, unknown>;\n /**\n * Generated approval summary. New callbacks use the structured shape; legacy\n * callbacks may contain a plain string.\n */\n summary?: string | StagedToolCallSummary;\n}\n\n/** Parameters for {@link ActionsClient.approve}. */\nexport interface ApproveActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Optionally modify the tool call arguments before execution. */\n editedToolCall?: {\n toolName: string;\n arguments: Record<string, unknown>;\n };\n /**\n * If `\"webhook\"`, also auto-approves future triggers of the same\n * `(user, webhook, tool)` combination — same effect as the UI's\n * \"Always allow for this webhook\" option.\n *\n * - `\"once\"` — approve only this action (default behavior).\n * - `\"webhook\"` — approve and remember for future triggers.\n */\n remember?: \"once\" | \"webhook\";\n}\n\n/** Parameters for {@link ActionsClient.reject}. */\nexport interface RejectActionParams {\n /** Webhook action identifier (from callback's webhookAction field). */\n action: string;\n /** Reason for rejection. */\n reason?: string;\n}\n\n/** Response from action approve/reject operations. */\nexport interface ActionManageResponse {\n success: boolean;\n actionId: string;\n status: ActionStatus;\n}\n\n// ── Outbound Webhook (Action Callback) Types ──────────────────────────\n\n/** Status of an action in the AgentPress system. */\nexport type ActionStatus =\n | \"pending\"\n | \"staged\"\n | \"approved\"\n | \"executing\"\n | \"rejected\"\n | \"completed\"\n | \"failed\"\n | \"expired\";\n\n/** A tool call made by the agent during action processing. */\nexport interface ToolCallResult {\n toolName: string;\n arguments: Record<string, unknown>;\n result: unknown;\n}\n\n/** The agent's response after processing an action. */\nexport interface AgentResponse {\n /** The agent's text response, if any. */\n text: string | null;\n /** Tool calls made by the agent during processing. */\n toolCalls: ToolCallResult[];\n}\n\n/**\n * Payload received from AgentPress outbound webhooks (post-event callbacks).\n * This is what your server receives for approval, terminal, and failure events.\n */\nexport interface ActionCallbackPayload {\n actionId: string;\n status: ActionStatus;\n actionType: string;\n /** Lifecycle event type (e.g., \"action.pending_approval\", \"action.completed\"). */\n eventType: ActionEventType;\n /** Webhook action identifier used to create this action. Needed for approve/reject. */\n webhookAction: string | null;\n /** Tool staged for approval lifecycle events when available. */\n stagedToolCall: StagedToolCall | null;\n /** ISO 8601 timestamp of when this callback event occurred. */\n occurredAt: string;\n /** ISO 8601 timestamp retained for backwards compatibility. */\n completedAt: string;\n /** Human-readable execution summary when populated on the action. */\n resultSummary: string | null;\n /** Original data from the inbound webhook that triggered this action. */\n sourceData: Record<string, unknown>;\n /** External system identifier. */\n externalId: string | null;\n /** AgentPress user ID associated with this action. */\n userId: string | null;\n /** Thread ID if the action created a conversation. */\n threadId: string | null;\n /** The agent's response including text and tool call results. */\n agentResponse: AgentResponse;\n /** Error message if the action failed. */\n errorMessage: string | null;\n /** Reason provided if the action was rejected by a human reviewer. */\n rejectionReason: string | null;\n /** Additional custom fields from post-event configuration. */\n [key: string]: unknown;\n}\n\n// ── User Tool Approvals ─────────────────────────────────────────────\n\n/** Mode of a user tool approval rule. */\nexport type ApprovalMode = \"always_allow\" | \"always_deny\";\n\n/**\n * A persisted rule that auto-approves (or auto-denies) a specific\n * `(user, webhook, tool)` triple, bypassing the per-action approval prompt.\n * Dates are ISO 8601 strings on the wire.\n */\nexport interface UserToolApproval {\n id: string;\n orgId: string;\n userId: string;\n actionWebhookId: string;\n toolName: string;\n mode: ApprovalMode;\n /** ISO 8601 timestamp. `null` means never expires. */\n expiresAt: string | null;\n /** ISO 8601 timestamp. */\n createdAt: string;\n /** ISO 8601 timestamp. */\n updatedAt: string;\n}\n\n/** Parameters for {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsParams {\n /** Webhook identifier (slug) — required to scope the signing secret and the result. */\n webhookIdentifier: string;\n /**\n * Filter to a single user's approvals. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId?: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`.\n */\n authProvider?: string;\n}\n\n/** Response from {@link UserApprovalsClient.list}. */\nexport interface ListUserApprovalsResponse {\n approvals: UserToolApproval[];\n}\n\n/** Parameters for {@link UserApprovalsClient.create}. */\nexport interface CreateUserApprovalParams {\n /** Webhook identifier (slug) — required to scope the signing secret. */\n webhookIdentifier: string;\n /**\n * User identifier this rule applies to. Accepts either an internal AgentPress\n * user UUID, or — when paired with {@link authProvider} — an external user ID\n * from a custom auth provider (e.g. LocalFalcon).\n */\n userId: string;\n /**\n * Name of the registered external auth provider. When provided, `userId` is\n * treated as the external user ID and resolved to the internal user via\n * `users.external_auth_id`. The user must have authenticated through the\n * provider at least once for resolution to succeed.\n */\n authProvider?: string;\n /** UUID of the `action_webhooks` row. Must match the webhook identified by `webhookIdentifier`. */\n actionWebhookId: string;\n /** Name of the tool this rule covers. */\n toolName: string;\n /** @default \"always_allow\" */\n mode?: ApprovalMode;\n /** `null` or omitted = never expires. */\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.update}. */\nexport interface UpdateUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n mode?: ApprovalMode;\n expiresAt?: Date | null;\n}\n\n/** Parameters for {@link UserApprovalsClient.delete}. */\nexport interface DeleteUserApprovalParams {\n /** Webhook identifier (slug) the approval belongs to — required for signing. */\n webhookIdentifier: string;\n}\n\n/** @internal Resolved (validated, defaulted) options. Not exported from the public API. */\nexport interface ResolvedOptions {\n baseUrl: string;\n timeout: number;\n org: string;\n webhookSecret?: string;\n apiKey?: string;\n partnerMcp?: ResolvedPartnerMcpOptions;\n onRequest?: AgentPressOptions[\"onRequest\"];\n onResponse?: AgentPressOptions[\"onResponse\"];\n}\n\n/** @internal Resolved (validated, defaulted) partner MCP options. */\nexport interface ResolvedPartnerMcpOptions {\n jwksUrl: string;\n issuer: string;\n audience: string;\n expectedExtProvider: string;\n clockTolerance: string | number;\n jwksCacheMaxAgeMs: number;\n}\n"],"mappings":"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"}
|