@keeperhub/wallet 0.1.11 → 0.1.13

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.
@@ -0,0 +1,236 @@
1
+ import { PublicClient } from 'viem';
2
+
3
+ type WalletConfig = {
4
+ /** Turnkey sub-org ID returned by POST /api/agentic-wallet/provision */
5
+ subOrgId: string;
6
+ /** EVM-shared wallet address (same for Base chainId 8453 and Tempo chainId 4217) */
7
+ walletAddress: `0x${string}`;
8
+ /** 64-char lowercase hex HMAC secret, minted server-side at provision; never logged */
9
+ hmacSecret: string;
10
+ };
11
+ type HmacHeaders = {
12
+ "X-KH-Sub-Org": string;
13
+ "X-KH-Timestamp": string;
14
+ "X-KH-Signature": string;
15
+ };
16
+ type HookDecision = {
17
+ decision: "allow" | "deny" | "ask";
18
+ reason?: string;
19
+ };
20
+ declare class KeeperHubError extends Error {
21
+ readonly code: string;
22
+ constructor(code: string, message: string);
23
+ }
24
+ /** Protocol preference for a single pay() or fetch() call. "auto" preserves
25
+ * the x402-first default when both challenges are offered. */
26
+ type PaymentHint = "x402" | "mpp" | "auto";
27
+ declare class WalletConfigMissingError extends Error {
28
+ constructor();
29
+ }
30
+
31
+ type BalanceSnapshot = {
32
+ base: {
33
+ chain: "base";
34
+ token: "USDC";
35
+ amount: string;
36
+ address: `0x${string}`;
37
+ };
38
+ tempo: {
39
+ chain: "tempo";
40
+ token: "USDC.e";
41
+ amount: string;
42
+ address: `0x${string}`;
43
+ };
44
+ };
45
+ type CheckBalanceOptions = {
46
+ /** Injectable viem client for Base (tests mock readContract). */
47
+ baseClient?: PublicClient;
48
+ /** Injectable viem client for Tempo (tests mock readContract). */
49
+ tempoClient?: PublicClient;
50
+ };
51
+ /**
52
+ * Read the wallet's on-chain balance across Base + Tempo in parallel. Both
53
+ * legs must resolve; any single failure rejects the Promise.
54
+ *
55
+ * Amounts are formatted as decimal strings (6-decimal USDC precision) so the
56
+ * caller can render them without BigInt math.
57
+ */
58
+ declare function checkBalance(wallet: WalletConfig, opts?: CheckBalanceOptions): Promise<BalanceSnapshot>;
59
+
60
+ type ClientOptions = {
61
+ /** Defaults to process.env.KEEPERHUB_API_URL ?? "https://app.keeperhub.com" */
62
+ baseUrl?: string;
63
+ /** Injected for tests; defaults to global fetch */
64
+ fetch?: typeof fetch;
65
+ };
66
+ /**
67
+ * 202 ask-tier envelope returned by /sign and /approval-request when the
68
+ * risk classifier routes a request to the ask queue. Callers poll
69
+ * `/api/agentic-wallet/approval-request/:id` until status !== "pending".
70
+ */
71
+ type AskTierResponse = {
72
+ _status: 202;
73
+ approvalRequestId: string;
74
+ };
75
+ /**
76
+ * HMAC-signed HTTP client for the KeeperHub agentic-wallet API surface.
77
+ * Every request to /api/agentic-wallet/* (except /provision, which uses
78
+ * the session cookie) flows through this class.
79
+ *
80
+ * @security No logging of headers, body, or response bodies. Any stdout
81
+ * emitter (the global console object or util.inspect) added to this
82
+ * file is a T-34-08 violation (grep-enforced in CI).
83
+ */
84
+ declare class KeeperHubClient {
85
+ private readonly baseUrl;
86
+ private readonly fetchImpl;
87
+ private readonly wallet;
88
+ constructor(wallet: WalletConfig, opts?: ClientOptions);
89
+ /**
90
+ * HMAC-signed POST/GET to any /api/agentic-wallet/* route except
91
+ * /provision. Path MUST start with a leading slash. Body is
92
+ * JSON.stringify'd (or the empty string for GET).
93
+ *
94
+ * Error mapping: non-2xx/non-202 surface as `KeeperHubError(code,
95
+ * message)` where `code` is the server-supplied field or the default
96
+ * taxonomy (`HMAC_INVALID`, `POLICY_BLOCKED`, `NOT_FOUND`,
97
+ * `TURNKEY_UPSTREAM`, `HTTP_<status>`). 202 ask-tier surfaces as an
98
+ * AskTierResponse envelope.
99
+ */
100
+ request<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<T | AskTierResponse>;
101
+ }
102
+
103
+ /**
104
+ * User-owned safety config at ~/.keeperhub/safety.json. File mode 0o644 so the
105
+ * user can freely edit thresholds and the allowlist; server-side Turnkey policy
106
+ * remains the authoritative hard cap (GUARD-06).
107
+ */
108
+ type SafetyConfig = {
109
+ auto_approve_max_usd: number;
110
+ ask_threshold_usd: number;
111
+ block_threshold_usd: number;
112
+ allowlisted_contracts: string[];
113
+ };
114
+ /**
115
+ * Defaults per 34-CONTEXT lines 61-68. Thresholds bracket the Turnkey policy
116
+ * hard cap (100 USDC). Allowlisted contracts mirror the server Turnkey policy
117
+ * allowlist (lib/agentic-wallet/policy.ts FACILITATOR_ALLOWLIST) -- lowercased
118
+ * for case-insensitive match against tool_input.to / paymentChallenge.payTo.
119
+ */
120
+ declare const DEFAULT_SAFETY_CONFIG: SafetyConfig;
121
+ declare function loadSafetyConfig(): Promise<SafetyConfig>;
122
+ declare function validateAndMerge(partial: Partial<SafetyConfig>): SafetyConfig;
123
+ declare function getSafetyConfigPath(): string;
124
+
125
+ type MppChallenge = {
126
+ serialized: string;
127
+ };
128
+ declare function parseMppChallenge(response: Response): MppChallenge | null;
129
+
130
+ type X402Challenge = {
131
+ x402Version: 2;
132
+ accepts: Array<{
133
+ scheme: "exact";
134
+ network: string;
135
+ asset: string;
136
+ amount: string;
137
+ payTo: string;
138
+ maxTimeoutSeconds: number;
139
+ extra: Record<string, unknown>;
140
+ }>;
141
+ resource: {
142
+ url: string;
143
+ description: string;
144
+ mimeType: string;
145
+ };
146
+ };
147
+ declare function parseX402Challenge(response: Response): Promise<X402Challenge | null>;
148
+
149
+ type PaySignerOptions = {
150
+ /** Override wallet loader (primarily for tests). */
151
+ walletLoader?: () => Promise<WalletConfig>;
152
+ /** Override KeeperHubClient factory (tests inject a mocked fetch). */
153
+ clientFactory?: (wallet: WalletConfig) => KeeperHubClient;
154
+ /** Replayed fetch (tests intercept the retry). */
155
+ fetchImpl?: typeof fetch;
156
+ /** Approval polling override: interval + max attempts. */
157
+ approval?: {
158
+ intervalMs: number;
159
+ maxAttempts: number;
160
+ };
161
+ };
162
+ /**
163
+ * Retry options threaded through `pay()` and `fetch()` into the post-sign
164
+ * retry. Lets callers forward the original request body and headers so the
165
+ * paid workflow receives the same payload on the retry as on the 402 attempt
166
+ * -- otherwise a workflow whose input schema requires a body (e.g.
167
+ * `{address}` on `/api/mcp/workflows/<slug>/call`) rejects the retry with
168
+ * 400 "Invalid JSON body".
169
+ */
170
+ type PayRetryOptions = {
171
+ /**
172
+ * Body to re-send on the retry. Must be a type that can be sent twice --
173
+ * string, ArrayBuffer, Uint8Array, FormData, URLSearchParams, or Blob.
174
+ * ReadableStream bodies are NOT supported because the first fetch() already
175
+ * consumed the stream; pass a string/Buffer instead.
176
+ */
177
+ body?: RequestInit["body"];
178
+ /**
179
+ * Additional request headers to merge onto the retry (e.g. Content-Type).
180
+ * The payment auth header (PAYMENT-SIGNATURE or Authorization) is set by
181
+ * the signer and overrides any same-named header in this map.
182
+ */
183
+ headers?: RequestInit["headers"];
184
+ /** HTTP method for the retry. Defaults to "POST". */
185
+ method?: string;
186
+ /**
187
+ * Per-call protocol preference. "x402" forces Base USDC; "mpp" forces Tempo
188
+ * USDC.e; "auto" (default, also the behaviour when omitted) uses x402 when
189
+ * offered, MPP otherwise. Throws KeeperHubError("X402_NOT_OFFERED") or
190
+ * KeeperHubError("MPP_NOT_OFFERED") when the requested protocol is absent
191
+ * from the challenge (KEEP-361).
192
+ */
193
+ paymentHint?: PaymentHint;
194
+ };
195
+ /** RequestInit extended with paymentHint for per-call protocol selection. */
196
+ type FetchInit = RequestInit & {
197
+ paymentHint?: PaymentHint;
198
+ };
199
+ type PaymentSigner = {
200
+ /**
201
+ * Pays a 402 response and returns the post-payment retry Response.
202
+ * Non-402 responses are returned unchanged.
203
+ *
204
+ * Pass `options.body` (and usually `options.headers`) if the paid
205
+ * workflow's input schema requires a body -- `pay()` does not have access
206
+ * to the original request otherwise.
207
+ *
208
+ * For most agent code, prefer `signer.fetch(url, init)` which threads the
209
+ * body/headers automatically.
210
+ */
211
+ pay: (response: Response, options?: PayRetryOptions) => Promise<Response>;
212
+ /**
213
+ * `fetch(url, init)` wrapper: does the initial fetch, and on 402 calls
214
+ * `pay()` with `init.body` + `init.headers` so the retry carries the
215
+ * original payload. Returns whatever the retry (or first response, if not
216
+ * 402) returns. No-op for non-402 responses.
217
+ *
218
+ * Pass `init.paymentHint` to force a specific payment protocol for this
219
+ * call. Omitting it is equivalent to `paymentHint: "auto"` (x402-first).
220
+ */
221
+ fetch: (input: string | URL, init?: FetchInit) => Promise<Response>;
222
+ };
223
+ /**
224
+ * Pure function that decides which payment protocol to use given challenge
225
+ * availability and caller's hint. Exported for unit testing.
226
+ *
227
+ * Returns "x402" or "mpp" to direct the caller to the appropriate path,
228
+ * or null when hint is "auto" and no challenge is present (pay() then
229
+ * returns the original 402 response unchanged). Throws KeeperHubError with
230
+ * a specific code when the requested protocol is unavailable (KEEP-361).
231
+ */
232
+ declare function selectProtocol(x402: X402Challenge | null, mpp: MppChallenge | null, hint: PaymentHint | undefined): "x402" | "mpp" | null;
233
+ declare function createPaymentSigner(opts?: PaySignerOptions): PaymentSigner;
234
+ declare const paymentSigner: PaymentSigner;
235
+
236
+ export { type AskTierResponse as A, type BalanceSnapshot as B, type CheckBalanceOptions as C, DEFAULT_SAFETY_CONFIG as D, type FetchInit as F, type HmacHeaders as H, KeeperHubClient as K, type MppChallenge as M, type PayRetryOptions as P, type SafetyConfig as S, type WalletConfig as W, type X402Challenge as X, type HookDecision as a, type ClientOptions as b, KeeperHubError as c, type PaymentHint as d, type PaymentSigner as e, WalletConfigMissingError as f, checkBalance as g, createPaymentSigner as h, getSafetyConfigPath as i, parseX402Challenge as j, paymentSigner as k, loadSafetyConfig as l, parseMppChallenge as p, selectProtocol as s, validateAndMerge as v };
package/package.json CHANGED
@@ -1,56 +1,59 @@
1
1
  {
2
- "name": "@keeperhub/wallet",
3
- "version": "0.1.11",
4
- "description": "KeeperHub agentic wallet: auto-pay x402 and MPP 402 responses with a server-side Turnkey proxy.",
5
- "license": "Apache-2.0",
6
- "type": "module",
7
- "engines": {
8
- "node": ">=20"
9
- },
10
- "bin": {
11
- "keeperhub-wallet": "./bin/keeperhub-wallet.js",
12
- "keeperhub-wallet-hook": "./bin/keeperhub-wallet-hook.js"
13
- },
14
- "main": "./dist/index.cjs",
15
- "module": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
17
- "exports": {
18
- ".": {
19
- "types": "./dist/index.d.ts",
20
- "import": "./dist/index.js",
21
- "require": "./dist/index.cjs"
22
- }
23
- },
24
- "files": [
25
- "dist",
26
- "bin",
27
- "skill",
28
- "README.md",
29
- "LICENSE"
30
- ],
31
- "repository": {
32
- "type": "git",
33
- "url": "https://github.com/KeeperHub/agentic-wallet.git"
34
- },
35
- "homepage": "https://docs.keeperhub.com/ai-tools/agentic-wallet",
36
- "bugs": {
37
- "url": "https://github.com/KeeperHub/agentic-wallet/issues"
38
- },
39
- "scripts": {
40
- "build": "tsup",
41
- "test": "vitest run",
42
- "test:watch": "vitest",
43
- "type-check": "tsc --noEmit"
44
- },
45
- "dependencies": {
46
- "viem": "2.48.1",
47
- "commander": "14.0.3"
48
- },
49
- "devDependencies": {
50
- "tsup": "8.5.1",
51
- "typescript": "5.9.2",
52
- "@types/node": "24.1.0",
53
- "vitest": "4.1.2",
54
- "msw": "2.13.4"
55
- }
2
+ "name": "@keeperhub/wallet",
3
+ "version": "0.1.13",
4
+ "description": "KeeperHub agentic wallet: auto-pay x402 and MPP 402 responses with a server-side Turnkey proxy.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "bin": {
11
+ "keeperhub-wallet": "./bin/keeperhub-wallet.js",
12
+ "keeperhub-wallet-hook": "./bin/keeperhub-wallet-hook.js",
13
+ "keeperhub-wallet-mcp": "./bin/keeperhub-wallet-mcp.js"
14
+ },
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "bin",
28
+ "skill",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/KeeperHub/agentic-wallet.git"
35
+ },
36
+ "homepage": "https://docs.keeperhub.com/ai-tools/agentic-wallet",
37
+ "bugs": {
38
+ "url": "https://github.com/KeeperHub/agentic-wallet/issues"
39
+ },
40
+ "scripts": {
41
+ "build": "tsup",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
44
+ "type-check": "tsc --noEmit"
45
+ },
46
+ "dependencies": {
47
+ "@modelcontextprotocol/sdk": "1.29.0",
48
+ "commander": "14.0.3",
49
+ "viem": "2.48.1",
50
+ "zod": "4.4.2"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "24.1.0",
54
+ "msw": "2.13.4",
55
+ "tsup": "8.5.1",
56
+ "typescript": "5.9.2",
57
+ "vitest": "4.1.2"
58
+ }
56
59
  }
@@ -17,7 +17,14 @@ description: |
17
17
  binds payment to the workflow slug server-side and supports per-call
18
18
  safety thresholds in ~/.keeperhub/safety.json.
19
19
 
20
- Install with `npx @keeperhub/wallet skill install`.
20
+ WHEN A KEEPERHUB-WALLET MCP SERVER IS LOADED, PREFER THE MCP TOOLS over
21
+ shelling out: `mcp__keeperhub-wallet__call_workflow` for paid invocation
22
+ by slug, `mcp__keeperhub-wallet__balance` and
23
+ `mcp__keeperhub-wallet__info` for status checks. The first tool call
24
+ auto-provisions a wallet if `~/.keeperhub/wallet.json` is missing — no
25
+ manual `add` ceremony required.
26
+
27
+ Install with `npx -p @keeperhub/wallet keeperhub-wallet skill install`.
21
28
  license: Apache-2.0
22
29
  ---
23
30
 
@@ -30,7 +37,7 @@ Enables automatic payment of HTTP 402 responses (x402 on Base USDC + MPP on Temp
30
37
  **Recommended — one command, fully wired up:**
31
38
 
32
39
  ```
33
- npx @keeperhub/wallet skill install
40
+ npx -p @keeperhub/wallet keeperhub-wallet skill install
34
41
  ```
35
42
 
36
43
  This writes the skill file into every detected agent directory under `$HOME` (Claude Code, Cursor, Cline, Windsurf, OpenCode) **and** registers the `keeperhub-wallet-hook` PreToolUse safety hook in `~/.claude/settings.json`. Re-running is safe — the installer is idempotent and preserves any foreign keys already in `settings.json`.
@@ -44,7 +51,7 @@ npx skills add keeperhub/agentic-wallet-skills
44
51
  This installs the skill file via the vercel-labs/skills convention but **does not register the PreToolUse safety hook**. Without the hook, signing operations are not gated by your auto/ask/block thresholds. After running `skills add` you MUST also run:
45
52
 
46
53
  ```
47
- npx @keeperhub/wallet skill install
54
+ npx -p @keeperhub/wallet keeperhub-wallet skill install
48
55
  ```
49
56
 
50
57
  to activate the safety hook. The combination is safe — `skill install` is idempotent and will not duplicate the skill file written by `skills add`.
@@ -52,17 +59,17 @@ to activate the safety hook. The combination is safe — `skill install` is idem
52
59
  After install, provision a wallet with:
53
60
 
54
61
  ```
55
- npx @keeperhub/wallet add
62
+ npx -p @keeperhub/wallet keeperhub-wallet add
56
63
  ```
57
64
 
58
65
  ## Commands
59
66
 
60
67
  Direct npm package invocation:
61
68
 
62
- - `npx @keeperhub/wallet add` — provision a new agentic wallet (no KeeperHub account required).
63
- - `npx @keeperhub/wallet info` — print `subOrgId` and `walletAddress` for the current wallet.
64
- - `npx @keeperhub/wallet fund` — print a Coinbase Onramp URL (Base USDC) and a Tempo deposit address.
65
- - `npx @keeperhub/wallet balance` — print on-chain balance across Base USDC and Tempo USDC.e.
69
+ - `npx -p @keeperhub/wallet keeperhub-wallet add` — provision a new agentic wallet (no KeeperHub account required).
70
+ - `npx -p @keeperhub/wallet keeperhub-wallet info` — print `subOrgId` and `walletAddress` for the current wallet.
71
+ - `npx -p @keeperhub/wallet keeperhub-wallet fund` — print a Coinbase Onramp URL (Base USDC) and a Tempo deposit address.
72
+ - `npx -p @keeperhub/wallet keeperhub-wallet balance` — print on-chain balance across Base USDC and Tempo USDC.e.
66
73
 
67
74
  Equivalent Go CLI wrappers (thin pass-through; delegate to the npm package):
68
75
 
@@ -78,7 +85,7 @@ Three-tier PreToolUse hook enforced on every signing call:
78
85
  - **ask** — amount above `auto_approve_max_usd` and at or below `block_threshold_usd` returns `{decision: "ask"}` so Claude Code surfaces an inline prompt in the agent chat.
79
86
  - **block** — amount above `block_threshold_usd`, or a contract not in `allowlisted_contracts`, is denied without calling `/sign`.
80
87
 
81
- Thresholds live in `~/.keeperhub/safety.json` (chmod 0o644). The `npx @keeperhub/wallet skill install` path registers the `keeperhub-wallet-hook` PreToolUse entry in `~/.claude/settings.json` automatically. For agents without auto-registration support (Cursor, Cline, Windsurf, OpenCode), the installer prints a copy-paste notice with the hook invocation.
88
+ Thresholds live in `~/.keeperhub/safety.json` (chmod 0o644). The `npx -p @keeperhub/wallet keeperhub-wallet skill install` path registers the `keeperhub-wallet-hook` PreToolUse entry in `~/.claude/settings.json` automatically. For agents without auto-registration support (Cursor, Cline, Windsurf, OpenCode), the installer prints a copy-paste notice with the hook invocation.
82
89
 
83
90
  The hook reads only the payment-challenge fields `amount`, `unit`, and the asset contract address from the tool payload. Forged fields like `trust-level hint`, `is-safe boolean`, or `admin-override bit` are ignored by design (GUARD-05).
84
91