@lucid-agents/opencode-x402-plugin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daydreams AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # opencode-x402-auth
2
+
3
+ OpenCode auth plugin for the x402 payment protocol. Sign ERC-2612 permits with your wallet to pay for LLM inference.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # npm
9
+ npm install opencode-x402-auth
10
+
11
+ # bun
12
+ bun add opencode-x402-auth
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### 1. Configure OpenCode
18
+
19
+ Add the plugin to your `~/.config/opencode/opencode.json`:
20
+
21
+ ```json
22
+ {
23
+ "$schema": "https://opencode.ai/config.json",
24
+ "plugins": ["opencode-x402-auth"],
25
+ "provider": {
26
+ "x402": {
27
+ "npm": "@ai-sdk/openai-compatible",
28
+ "name": "x402 Router",
29
+ "options": {
30
+ "baseURL": "http://localhost:8080/v1"
31
+ },
32
+ "models": {
33
+ "openai:gpt-4": { "name": "GPT-4" },
34
+ "anthropic:claude-sonnet-4-20250514": { "name": "Claude Sonnet 4" }
35
+ }
36
+ }
37
+ },
38
+ "model": "x402/anthropic:claude-sonnet-4-20250514"
39
+ }
40
+ ```
41
+
42
+ ### 2. Connect Your Wallet
43
+
44
+ In OpenCode, run `/connect` and select "x402":
45
+
46
+ 1. Choose **"Connect Wallet (Private Key)"**
47
+ 2. Enter your wallet's private key (0x-prefixed)
48
+ 3. The plugin will sign permits automatically
49
+
50
+ ### 3. Start Coding
51
+
52
+ That's it! The plugin automatically:
53
+ - Fetches router configuration
54
+ - Signs ERC-2612 permits for each request
55
+ - Injects the `PAYMENT-SIGNATURE` header
56
+
57
+ ## How It Works
58
+
59
+ ```
60
+ OpenCode → Plugin (signs permit) → x402 Router → LLM Provider
61
+
62
+ Your Wallet (ERC-2612 permit)
63
+ ```
64
+
65
+ 1. **You make a request** - OpenCode sends a chat message
66
+ 2. **Plugin intercepts** - Before the request reaches the router
67
+ 3. **Permit is signed** - Using your wallet's private key (EIP-712)
68
+ 4. **Header is injected** - `PAYMENT-SIGNATURE: <base64-encoded-permit>`
69
+ 5. **Router processes** - Validates permit, forwards to provider
70
+ 6. **Response streams** - Back through OpenCode to you
71
+ 7. **Payment tracked** - Router tracks cost asynchronously
72
+
73
+ ## Configuration Options
74
+
75
+ ### Via `/connect` in OpenCode
76
+
77
+ | Option | Description |
78
+ |--------|-------------|
79
+ | **Connect Wallet** | Enter your private key (stored locally) |
80
+ | **Configure Router URL** | Set custom router endpoint |
81
+ | **Set Permit Cap** | Maximum USDC per permit session |
82
+
83
+ ### Environment Variables
84
+
85
+ ```bash
86
+ # Optional: Override router URL
87
+ export X402_ROUTER_URL="https://router.example.com"
88
+
89
+ # Optional: Override permit cap (in USDC)
90
+ export X402_PERMIT_CAP="50"
91
+ ```
92
+
93
+ ## Supported Networks
94
+
95
+ | Network | CAIP-2 ID | USDC Contract |
96
+ |---------|-----------|---------------|
97
+ | Base Mainnet | `eip155:8453` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
98
+ | Base Sepolia | `eip155:84532` | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |
99
+ | Ethereum Mainnet | `eip155:1` | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` |
100
+
101
+ ## Security
102
+
103
+ **Important security considerations:**
104
+
105
+ 1. **Use a dedicated wallet** - Create a wallet specifically for AI spending
106
+ 2. **Fund minimally** - Only keep what you're willing to spend
107
+ 3. **Set low caps** - Start with $1-10 permit caps
108
+ 4. **Private key storage** - Stored locally in OpenCode's auth store (`~/.local/share/opencode/auth.json`)
109
+
110
+ **Never use your main wallet's private key.** Create a burner wallet and fund it with small amounts.
111
+
112
+ ## API Reference
113
+
114
+ ### Plugin Export
115
+
116
+ ```typescript
117
+ import { X402AuthPlugin } from "opencode-x402-auth";
118
+
119
+ // The plugin is auto-loaded by OpenCode
120
+ // Manual usage:
121
+ const plugin = await X402AuthPlugin({ client });
122
+ ```
123
+
124
+ ### Types
125
+
126
+ ```typescript
127
+ interface X402Auth {
128
+ type: "wallet" | "manual";
129
+ privateKey?: string;
130
+ routerUrl?: string;
131
+ permitCap?: string; // In token units (6 decimals for USDC)
132
+ network?: string; // CAIP-2 format
133
+ }
134
+ ```
135
+
136
+ ## Troubleshooting
137
+
138
+ ### "402 Payment Required"
139
+
140
+ The permit wasn't accepted. Check:
141
+ 1. Wallet has sufficient USDC balance
142
+ 2. Router is running and accessible
143
+ 3. Permit cap is high enough for the request
144
+
145
+ ### "Failed to fetch router config"
146
+
147
+ Router endpoint unreachable. Verify:
148
+ 1. Router URL is correct
149
+ 2. Router is running: `curl http://localhost:8080/health`
150
+
151
+ ### "Invalid private key format"
152
+
153
+ Private key must be:
154
+ - 66 characters (including `0x` prefix)
155
+ - Valid hex string
156
+ - Example: `0x1234567890abcdef...` (64 hex chars after 0x)
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ # Clone the repo
162
+ git clone https://github.com/daydreamsai/router.git
163
+ cd router/packages/opencode-x402-auth
164
+
165
+ # Install dependencies
166
+ bun install
167
+
168
+ # Build
169
+ bun run build
170
+
171
+ # Type check
172
+ bun tsc --noEmit
173
+ ```
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Permit caching utilities for x402 auth plugin
3
+ */
4
+ export interface CachedPermit {
5
+ paymentSig: string;
6
+ deadline: number;
7
+ maxValue: string;
8
+ nonce: string;
9
+ network: string;
10
+ asset: string;
11
+ payTo: string;
12
+ }
13
+ export interface ErrorResponse {
14
+ code?: string;
15
+ error?: string;
16
+ message?: string;
17
+ }
18
+ export declare class PermitCache {
19
+ private cache;
20
+ get(network: string, asset: string, payTo: string): CachedPermit | null;
21
+ set(permit: CachedPermit): void;
22
+ invalidate(network: string, asset: string, payTo: string): void;
23
+ clear(): void;
24
+ private buildKey;
25
+ private isNearDeadline;
26
+ }
27
+ export declare function isCapExhausted(error: ErrorResponse): boolean;
28
+ export declare function isSessionClosed(error: ErrorResponse): boolean;
29
+ export declare function shouldInvalidatePermit(error: ErrorResponse): boolean;
30
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAmC;IAEhD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAevE,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAK/B,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK/D,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,cAAc;CAIvB;AAUD,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAK5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAK7D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAEpE"}
package/dist/cache.js ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Permit caching utilities for x402 auth plugin
3
+ */
4
+ // ============================================================================
5
+ // Permit Cache
6
+ // ============================================================================
7
+ const PRE_INVALIDATE_WINDOW_SECONDS = 60;
8
+ export class PermitCache {
9
+ cache = new Map();
10
+ get(network, asset, payTo) {
11
+ const key = this.buildKey(network, asset, payTo);
12
+ const permit = this.cache.get(key);
13
+ if (!permit) {
14
+ return null;
15
+ }
16
+ if (this.isNearDeadline(permit.deadline)) {
17
+ this.cache.delete(key);
18
+ return null;
19
+ }
20
+ return permit;
21
+ }
22
+ set(permit) {
23
+ const key = this.buildKey(permit.network, permit.asset, permit.payTo);
24
+ this.cache.set(key, permit);
25
+ }
26
+ invalidate(network, asset, payTo) {
27
+ const key = this.buildKey(network, asset, payTo);
28
+ this.cache.delete(key);
29
+ }
30
+ clear() {
31
+ this.cache.clear();
32
+ }
33
+ buildKey(network, asset, payTo) {
34
+ return `${network.toLowerCase()}:${asset.toLowerCase()}:${payTo.toLowerCase()}`;
35
+ }
36
+ isNearDeadline(deadline) {
37
+ const now = Math.floor(Date.now() / 1000);
38
+ return deadline - now <= PRE_INVALIDATE_WINDOW_SECONDS;
39
+ }
40
+ }
41
+ // ============================================================================
42
+ // Error helpers
43
+ // ============================================================================
44
+ function normalizeErrorText(error, message) {
45
+ return `${error ?? ""} ${message ?? ""}`.toLowerCase();
46
+ }
47
+ export function isCapExhausted(error) {
48
+ if (!error)
49
+ return false;
50
+ if (error.code === "cap_exhausted")
51
+ return true;
52
+ const text = normalizeErrorText(error.error, error.message);
53
+ return text.includes("cap exhausted");
54
+ }
55
+ export function isSessionClosed(error) {
56
+ if (!error)
57
+ return false;
58
+ if (error.code === "session_closed")
59
+ return true;
60
+ const text = normalizeErrorText(error.error, error.message);
61
+ return text.includes("session closed");
62
+ }
63
+ export function shouldInvalidatePermit(error) {
64
+ return isCapExhausted(error) || isSessionClosed(error);
65
+ }
66
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * OpenCode x402 Auth Plugin
3
+ *
4
+ * Enables OpenCode to authenticate with the x402 Inference Router using
5
+ * wallet-signed ERC-2612 permits for crypto-native payment.
6
+ *
7
+ * @example
8
+ * ```json
9
+ * // opencode.json
10
+ * {
11
+ * "plugins": ["opencode-x402-auth"],
12
+ * "provider": {
13
+ * "x402": {
14
+ * "npm": "@ai-sdk/openai-compatible",
15
+ * "options": { "baseURL": "http://localhost:8080/v1" }
16
+ * }
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+ /** Authentication state stored by OpenCode */
22
+ export interface X402Auth {
23
+ type: "wallet" | "manual";
24
+ privateKey?: string;
25
+ routerUrl?: string;
26
+ permitCap?: string;
27
+ network?: string;
28
+ }
29
+ /** OpenCode plugin client interface */
30
+ export interface PluginClient {
31
+ auth: {
32
+ get(params: {
33
+ path: {
34
+ id: string;
35
+ };
36
+ }): Promise<X402Auth | null>;
37
+ set(params: {
38
+ path: {
39
+ id: string;
40
+ };
41
+ body: X402Auth;
42
+ }): Promise<void>;
43
+ };
44
+ }
45
+ /** OpenCode auth method result */
46
+ export type AuthResult = {
47
+ type: "success";
48
+ key?: string;
49
+ refresh?: string;
50
+ access?: string;
51
+ expires?: number;
52
+ } | {
53
+ type: "failed";
54
+ };
55
+ /**
56
+ * Clear the router config cache (for testing)
57
+ */
58
+ export declare function clearRouterConfigCache(): void;
59
+ /**
60
+ * OpenCode x402 Auth Plugin
61
+ *
62
+ * Provides wallet-based authentication for x402 payment protocol.
63
+ * Signs ERC-2612 permits to authorize spending on each request.
64
+ */
65
+ export declare function X402AuthPlugin({ client }: {
66
+ client: PluginClient;
67
+ }): Promise<{
68
+ auth: {
69
+ provider: string;
70
+ /**
71
+ * Loader function - called to configure authentication for requests
72
+ */
73
+ loader: (getAuth: () => Promise<X402Auth | null>, provider: {
74
+ options?: {
75
+ baseURL?: string;
76
+ };
77
+ models?: Record<string, unknown>;
78
+ }) => Promise<{
79
+ fetch?: undefined;
80
+ } | {
81
+ fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
82
+ }>;
83
+ /**
84
+ * Authentication methods available in /connect
85
+ */
86
+ methods: {
87
+ label: string;
88
+ type: "manual";
89
+ authorize: () => Promise<{
90
+ instructions: string;
91
+ method: "code" | "key";
92
+ callback: (input: string) => Promise<AuthResult>;
93
+ }>;
94
+ }[];
95
+ };
96
+ }>;
97
+ export default X402AuthPlugin;
98
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAiBH,8CAA8C;AAC9C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqCD,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE;QACJ,GAAG,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QAChE,GAAG,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,IAAI,EAAE,QAAQ,CAAA;SAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACtE,CAAC;CACH;AAED,kCAAkC;AAClC,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAwUvB;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAoBD;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE;;;QAKnE;;WAEG;0BAEQ,MAAM,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,YAC7B;YAAE,OAAO,CAAC,EAAE;gBAAE,OAAO,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE;;;2BAyDvD,MAAM,GAAG,GAAG,GAAG,OAAO,SAAS,WAAW;;QAyCnE;;WAEG;;;;6BAqDsB,OAAO,CAAC;gBAC3B,YAAY,EAAE,MAAM,CAAC;gBACrB,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;gBACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;aAClD,CAAC;;;GAuFX;AAGD,eAAe,cAAc,CAAC"}