@buildersgarden/siwa 0.0.10 → 0.0.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/README.md CHANGED
@@ -13,7 +13,7 @@ A Claude Code skill for registering AI agents on the [ERC-8004 (Trustless Agents
13
13
  ```
14
14
  src/ Core SDK modules
15
15
  keystore.ts Proxy-only keystore (signing delegated over HMAC-authenticated HTTP)
16
- identity.ts IDENTITY.md read/write helpers
16
+ identity.ts SIWA_IDENTITY.md read/write helpers
17
17
  siwa.ts SIWA message building, signing, verification
18
18
  proxy-auth.ts HMAC-SHA256 authentication utilities
19
19
  registry.ts Onchain agent profile & reputation lookups
@@ -26,7 +26,7 @@ references/ Protocol documentation
26
26
  security-model.md Threat model and keystore architecture
27
27
 
28
28
  assets/ Templates
29
- IDENTITY.template.md
29
+ SIWA_IDENTITY.template.md
30
30
 
31
31
  ```
32
32
 
package/dist/erc8128.d.ts CHANGED
@@ -9,14 +9,16 @@
9
9
  *
10
10
  * These are the two main entry points. Everything else is internal.
11
11
  */
12
- import type { PublicClient } from 'viem';
13
- import { type EthHttpSigner } from '@slicekit/erc8128';
14
- import { type KeystoreConfig } from './keystore.js';
12
+ import type { Address, PublicClient } from 'viem';
13
+ import { type EthHttpSigner, type NonceStore } from '@slicekit/erc8128';
14
+ import type { Signer, SignerType } from './signer.js';
15
15
  export interface VerifyOptions {
16
16
  receiptSecret: string;
17
17
  rpcUrl?: string;
18
18
  verifyOnchain?: boolean;
19
19
  publicClient?: PublicClient;
20
+ nonceStore?: NonceStore;
21
+ allowedSignerTypes?: SignerType[];
20
22
  }
21
23
  /** Verified agent identity returned from a successful auth check. */
22
24
  export interface SiwaAgent {
@@ -24,6 +26,7 @@ export interface SiwaAgent {
24
26
  agentId: number;
25
27
  agentRegistry: string;
26
28
  chainId: number;
29
+ signerType?: SignerType;
27
30
  }
28
31
  export type AuthResult = {
29
32
  valid: true;
@@ -41,13 +44,19 @@ export declare function resolveReceiptSecret(explicit?: string): string;
41
44
  /** Header name for the verification receipt */
42
45
  export declare const RECEIPT_HEADER = "X-SIWA-Receipt";
43
46
  /**
44
- * Create an ERC-8128 signer backed by the keyring proxy.
47
+ * Create an ERC-8128 HTTP signer from a SIWA Signer.
45
48
  *
46
49
  * The `signMessage` callback converts the RFC 9421 signature base
47
- * (Uint8Array) to a hex string and delegates to the proxy via
48
- * `signRawMessage`, which signs with `{ raw: true }`.
50
+ * (Uint8Array) to a hex string and delegates to the signer.
51
+ *
52
+ * @param signer - A SIWA Signer (createKeyringProxySigner, createLocalAccountSigner, etc.)
53
+ * @param chainId - Chain ID for the ERC-8128 keyid
54
+ * @param options - Optional overrides (e.g. signerAddress for TBA identity)
55
+ * @returns An EthHttpSigner for use with @slicekit/erc8128
49
56
  */
50
- export declare function createProxySigner(config: KeystoreConfig, chainId: number): Promise<EthHttpSigner>;
57
+ export declare function createErc8128Signer(signer: Signer, chainId: number, options?: {
58
+ signerAddress?: Address;
59
+ }): Promise<EthHttpSigner>;
51
60
  /**
52
61
  * Attach a verification receipt to a request.
53
62
  *
@@ -60,16 +69,35 @@ export declare function attachReceipt(request: Request, receipt: string): Reques
60
69
  * This is the main function platform developers use on the agent side.
61
70
  * One call does everything:
62
71
  * 1. Attaches the receipt header
63
- * 2. Creates a proxy-backed ERC-8128 signer
72
+ * 2. Creates an ERC-8128 signer from the SIWA signer
64
73
  * 3. Signs the request with HTTP Message Signatures (RFC 9421)
65
74
  *
66
75
  * @param request The outgoing Request object
67
76
  * @param receipt Verification receipt from SIWA sign-in
68
- * @param config Keystore config (proxy URL + secret)
77
+ * @param signer A SIWA Signer (createKeyringProxySigner, createLocalAccountSigner, etc.)
69
78
  * @param chainId Chain ID for the ERC-8128 keyid
79
+ * @param options Optional overrides (e.g. signerAddress for TBA identity)
70
80
  * @returns A new Request with Signature, Signature-Input, Content-Digest, and X-SIWA-Receipt headers
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * import { signAuthenticatedRequest, createLocalAccountSigner } from '@buildersgarden/siwa';
85
+ * import { privateKeyToAccount } from 'viem/accounts';
86
+ *
87
+ * const account = privateKeyToAccount('0x...');
88
+ * const signer = createLocalAccountSigner(account);
89
+ *
90
+ * const signedRequest = await signAuthenticatedRequest(
91
+ * new Request('https://api.example.com/data'),
92
+ * receipt,
93
+ * signer,
94
+ * 84532
95
+ * );
96
+ * ```
71
97
  */
72
- export declare function signAuthenticatedRequest(request: Request, receipt: string, config: KeystoreConfig, chainId: number): Promise<Request>;
98
+ export declare function signAuthenticatedRequest(request: Request, receipt: string, signer: Signer, chainId: number, options?: {
99
+ signerAddress?: Address;
100
+ }): Promise<Request>;
73
101
  /**
74
102
  * Verify an authenticated request: ERC-8128 signature + receipt + optional onchain check.
75
103
  *
package/dist/erc8128.js CHANGED
@@ -10,7 +10,6 @@
10
10
  * These are the two main entry points. Everything else is internal.
11
11
  */
12
12
  import { signRequest, verifyRequest, } from '@slicekit/erc8128';
13
- import { signRawMessage, getAddress } from './keystore.js';
14
13
  import { verifyReceipt } from './receipt.js';
15
14
  /**
16
15
  * Resolve the receipt secret from an explicit value or environment variables.
@@ -30,23 +29,29 @@ export const RECEIPT_HEADER = 'X-SIWA-Receipt';
30
29
  // Agent-side: signer creation
31
30
  // ---------------------------------------------------------------------------
32
31
  /**
33
- * Create an ERC-8128 signer backed by the keyring proxy.
32
+ * Create an ERC-8128 HTTP signer from a SIWA Signer.
34
33
  *
35
34
  * The `signMessage` callback converts the RFC 9421 signature base
36
- * (Uint8Array) to a hex string and delegates to the proxy via
37
- * `signRawMessage`, which signs with `{ raw: true }`.
35
+ * (Uint8Array) to a hex string and delegates to the signer.
36
+ *
37
+ * @param signer - A SIWA Signer (createKeyringProxySigner, createLocalAccountSigner, etc.)
38
+ * @param chainId - Chain ID for the ERC-8128 keyid
39
+ * @param options - Optional overrides (e.g. signerAddress for TBA identity)
40
+ * @returns An EthHttpSigner for use with @slicekit/erc8128
38
41
  */
39
- export async function createProxySigner(config, chainId) {
40
- const address = await getAddress(config);
41
- if (!address)
42
- throw new Error('No wallet found in keystore');
42
+ export async function createErc8128Signer(signer, chainId, options) {
43
+ const address = options?.signerAddress ?? await signer.getAddress();
43
44
  return {
44
- address: address,
45
+ address,
45
46
  chainId,
46
47
  signMessage: async (message) => {
47
48
  const hex = ('0x' + Array.from(message).map(b => b.toString(16).padStart(2, '0')).join(''));
48
- const result = await signRawMessage(hex, config);
49
- return result.signature;
49
+ // Use signRawMessage if available (preferred for raw bytes)
50
+ if (signer.signRawMessage) {
51
+ return signer.signRawMessage(hex);
52
+ }
53
+ // Fallback to signMessage for signers without signRawMessage
54
+ return signer.signMessage(hex);
50
55
  },
51
56
  };
52
57
  }
@@ -69,22 +74,41 @@ export function attachReceipt(request, receipt) {
69
74
  * This is the main function platform developers use on the agent side.
70
75
  * One call does everything:
71
76
  * 1. Attaches the receipt header
72
- * 2. Creates a proxy-backed ERC-8128 signer
77
+ * 2. Creates an ERC-8128 signer from the SIWA signer
73
78
  * 3. Signs the request with HTTP Message Signatures (RFC 9421)
74
79
  *
75
80
  * @param request The outgoing Request object
76
81
  * @param receipt Verification receipt from SIWA sign-in
77
- * @param config Keystore config (proxy URL + secret)
82
+ * @param signer A SIWA Signer (createKeyringProxySigner, createLocalAccountSigner, etc.)
78
83
  * @param chainId Chain ID for the ERC-8128 keyid
84
+ * @param options Optional overrides (e.g. signerAddress for TBA identity)
79
85
  * @returns A new Request with Signature, Signature-Input, Content-Digest, and X-SIWA-Receipt headers
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * import { signAuthenticatedRequest, createLocalAccountSigner } from '@buildersgarden/siwa';
90
+ * import { privateKeyToAccount } from 'viem/accounts';
91
+ *
92
+ * const account = privateKeyToAccount('0x...');
93
+ * const signer = createLocalAccountSigner(account);
94
+ *
95
+ * const signedRequest = await signAuthenticatedRequest(
96
+ * new Request('https://api.example.com/data'),
97
+ * receipt,
98
+ * signer,
99
+ * 84532
100
+ * );
101
+ * ```
80
102
  */
81
- export async function signAuthenticatedRequest(request, receipt, config, chainId) {
103
+ export async function signAuthenticatedRequest(request, receipt, signer, chainId, options) {
82
104
  // 1. Attach receipt header
83
105
  const withReceipt = attachReceipt(request, receipt);
84
- // 2. Create proxy-backed signer
85
- const signer = await createProxySigner(config, chainId);
86
- // 3. Sign with ERC-8128 (includes Content-Digest for bodies)
87
- return signRequest(withReceipt, signer);
106
+ // 2. Create ERC-8128 signer from SIWA signer
107
+ const erc8128Signer = await createErc8128Signer(signer, chainId, options);
108
+ // 3. Sign with ERC-8128 (includes Content-Digest for bodies and receipt header)
109
+ return signRequest(withReceipt, erc8128Signer, {
110
+ components: [RECEIPT_HEADER],
111
+ });
88
112
  }
89
113
  // ---------------------------------------------------------------------------
90
114
  // Server-side: high-level request verification
@@ -138,6 +162,10 @@ export async function verifyAuthenticatedRequest(request, options) {
138
162
  if (!receipt) {
139
163
  return { valid: false, error: 'Invalid or expired receipt' };
140
164
  }
165
+ // 1b. Enforce signer type policy
166
+ if (options.allowedSignerTypes?.length && !options.allowedSignerTypes.includes(receipt.signerType)) {
167
+ return { valid: false, error: `Signer type '${receipt.signerType || 'unknown'}' is not in allowed types [${options.allowedSignerTypes.join(', ')}]` };
168
+ }
141
169
  // 2. Verify ERC-8128 signature
142
170
  const { verifyMessage } = await import('viem');
143
171
  const verifyResult = await verifyRequest(request, async (args) => {
@@ -155,7 +183,10 @@ export async function verifyAuthenticatedRequest(request, options) {
155
183
  message: args.message,
156
184
  signature: args.signature,
157
185
  });
158
- }, nonceStore);
186
+ }, options.nonceStore ?? nonceStore, {
187
+ additionalRequestBoundComponents: [RECEIPT_HEADER],
188
+ classBoundPolicies: [RECEIPT_HEADER]
189
+ });
159
190
  if (!verifyResult.ok) {
160
191
  return { valid: false, error: `ERC-8128 verification failed: ${verifyResult.reason}${verifyResult.detail ? ` (${verifyResult.detail})` : ''}` };
161
192
  }
@@ -202,6 +233,7 @@ export async function verifyAuthenticatedRequest(request, options) {
202
233
  agentId: receipt.agentId,
203
234
  agentRegistry: receipt.agentRegistry,
204
235
  chainId: receipt.chainId,
236
+ ...(receipt.signerType ? { signerType: receipt.signerType } : {}),
205
237
  },
206
238
  };
207
239
  }
package/dist/express.d.ts CHANGED
@@ -16,6 +16,7 @@
16
16
  */
17
17
  import type { RequestHandler } from 'express';
18
18
  import { type SiwaAgent, type VerifyOptions } from './erc8128.js';
19
+ import type { SignerType } from './signer.js';
19
20
  export type { SiwaAgent };
20
21
  declare global {
21
22
  namespace Express {
@@ -34,6 +35,8 @@ export interface SiwaMiddlewareOptions {
34
35
  verifyOnchain?: boolean;
35
36
  /** Public client for ERC-1271 or onchain checks. */
36
37
  publicClient?: VerifyOptions['publicClient'];
38
+ /** Allowed signer types. Omit to accept all. */
39
+ allowedSignerTypes?: SignerType[];
37
40
  }
38
41
  export interface SiwaCorsOptions {
39
42
  /** Allowed origin(s). Defaults to "*". */
package/dist/express.js CHANGED
@@ -78,6 +78,7 @@ export function siwaMiddleware(options) {
78
78
  rpcUrl: options?.rpcUrl,
79
79
  verifyOnchain: options?.verifyOnchain,
80
80
  publicClient: options?.publicClient,
81
+ allowedSignerTypes: options?.allowedSignerTypes,
81
82
  });
82
83
  if (!result.valid) {
83
84
  res.status(401).json({ error: result.error });
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * identity.ts
3
3
  *
4
- * Read/write helpers for the agent's IDENTITY.md file.
4
+ * Read/write helpers for the agent's SIWA_IDENTITY.md file.
5
5
  * Minimal 4-field identity: Address, Agent ID, Agent Registry, Chain ID.
6
6
  *
7
- * IDENTITY.md uses the pattern: - **Key**: `value`
7
+ * SIWA_IDENTITY.md uses the pattern: - **Key**: `value`
8
8
  *
9
9
  * Registration checks are done onchain via ownerOf() when a PublicClient
10
10
  * is provided, otherwise the local file is used as a cache.
@@ -19,26 +19,26 @@ export interface AgentIdentity {
19
19
  chainId?: number;
20
20
  }
21
21
  /**
22
- * Ensure IDENTITY.md exists. If not, copy from template or create minimal.
22
+ * Ensure SIWA_IDENTITY.md exists. If not, copy from template or create minimal.
23
23
  */
24
24
  export declare function ensureIdentityExists(identityPath?: string, templatePath?: string): void;
25
25
  /**
26
- * Read the agent identity from IDENTITY.md.
26
+ * Read the agent identity from SIWA_IDENTITY.md.
27
27
  * Returns typed AgentIdentity with parsed values.
28
28
  */
29
29
  export declare function readIdentity(identityPath?: string): AgentIdentity;
30
30
  /**
31
- * Write a single field value in IDENTITY.md.
31
+ * Write a single field value in SIWA_IDENTITY.md.
32
32
  */
33
33
  export declare function writeIdentityField(key: string, value: string, identityPath?: string): void;
34
34
  /**
35
- * Check if the agent has a wallet address recorded in IDENTITY.md.
35
+ * Check if the agent has a wallet address recorded in SIWA_IDENTITY.md.
36
36
  */
37
37
  export declare function hasWalletRecord(identityPath?: string): boolean;
38
38
  /**
39
39
  * Check if the agent is registered.
40
40
  *
41
- * Without a client: returns true if IDENTITY.md has an Agent ID and Agent Registry (local cache).
41
+ * Without a client: returns true if SIWA_IDENTITY.md has an Agent ID and Agent Registry (local cache).
42
42
  * With a client: performs an onchain ownerOf(agentId) check on the registry contract.
43
43
  */
44
44
  export declare function isRegistered(options?: {
package/dist/identity.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * identity.ts
3
3
  *
4
- * Read/write helpers for the agent's IDENTITY.md file.
4
+ * Read/write helpers for the agent's SIWA_IDENTITY.md file.
5
5
  * Minimal 4-field identity: Address, Agent ID, Agent Registry, Chain ID.
6
6
  *
7
- * IDENTITY.md uses the pattern: - **Key**: `value`
7
+ * SIWA_IDENTITY.md uses the pattern: - **Key**: `value`
8
8
  *
9
9
  * Registration checks are done onchain via ownerOf() when a PublicClient
10
10
  * is provided, otherwise the local file is used as a cache.
@@ -12,12 +12,12 @@
12
12
  * Dependencies: fs (Node built-in), viem (optional for onchain checks)
13
13
  */
14
14
  import * as fs from 'fs';
15
- const DEFAULT_IDENTITY_PATH = './IDENTITY.md';
15
+ const DEFAULT_IDENTITY_PATH = './SIWA_IDENTITY.md';
16
16
  // ---------------------------------------------------------------------------
17
17
  // File Operations
18
18
  // ---------------------------------------------------------------------------
19
19
  /**
20
- * Ensure IDENTITY.md exists. If not, copy from template or create minimal.
20
+ * Ensure SIWA_IDENTITY.md exists. If not, copy from template or create minimal.
21
21
  */
22
22
  export function ensureIdentityExists(identityPath = DEFAULT_IDENTITY_PATH, templatePath) {
23
23
  if (fs.existsSync(identityPath))
@@ -36,7 +36,7 @@ export function ensureIdentityExists(identityPath = DEFAULT_IDENTITY_PATH, templ
36
36
  }
37
37
  }
38
38
  /**
39
- * Read the agent identity from IDENTITY.md.
39
+ * Read the agent identity from SIWA_IDENTITY.md.
40
40
  * Returns typed AgentIdentity with parsed values.
41
41
  */
42
42
  export function readIdentity(identityPath = DEFAULT_IDENTITY_PATH) {
@@ -62,7 +62,7 @@ export function readIdentity(identityPath = DEFAULT_IDENTITY_PATH) {
62
62
  return identity;
63
63
  }
64
64
  /**
65
- * Write a single field value in IDENTITY.md.
65
+ * Write a single field value in SIWA_IDENTITY.md.
66
66
  */
67
67
  export function writeIdentityField(key, value, identityPath = DEFAULT_IDENTITY_PATH) {
68
68
  let content = fs.readFileSync(identityPath, 'utf-8');
@@ -77,7 +77,7 @@ export function writeIdentityField(key, value, identityPath = DEFAULT_IDENTITY_P
77
77
  fs.writeFileSync(identityPath, content);
78
78
  }
79
79
  /**
80
- * Check if the agent has a wallet address recorded in IDENTITY.md.
80
+ * Check if the agent has a wallet address recorded in SIWA_IDENTITY.md.
81
81
  */
82
82
  export function hasWalletRecord(identityPath = DEFAULT_IDENTITY_PATH) {
83
83
  const identity = readIdentity(identityPath);
@@ -86,7 +86,7 @@ export function hasWalletRecord(identityPath = DEFAULT_IDENTITY_PATH) {
86
86
  /**
87
87
  * Check if the agent is registered.
88
88
  *
89
- * Without a client: returns true if IDENTITY.md has an Agent ID and Agent Registry (local cache).
89
+ * Without a client: returns true if SIWA_IDENTITY.md has an Agent ID and Agent Registry (local cache).
90
90
  * With a client: performs an onchain ownerOf(agentId) check on the registry contract.
91
91
  */
92
92
  export async function isRegistered(options) {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './signer.js';
1
2
  export * from './keystore.js';
2
3
  export * from './siwa.js';
3
4
  export * from './identity.js';
@@ -6,3 +7,4 @@ export * from './registry.js';
6
7
  export * from './addresses.js';
7
8
  export * from './receipt.js';
8
9
  export * from './erc8128.js';
10
+ export * from './tba.js';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './signer.js';
1
2
  export * from './keystore.js';
2
3
  export * from './siwa.js';
3
4
  export * from './identity.js';
@@ -6,3 +7,4 @@ export * from './registry.js';
6
7
  export * from './addresses.js';
7
8
  export * from './receipt.js';
8
9
  export * from './erc8128.js';
10
+ export * from './tba.js';
@@ -1,23 +1,23 @@
1
1
  /**
2
2
  * keystore.ts
3
3
  *
4
- * Secure signing abstraction for ERC-8004 agents.
4
+ * Keyring proxy administrative operations.
5
5
  *
6
- * All signing is delegated to a **keyring proxy server** — a separate process
7
- * that holds the encrypted private key and exposes only HMAC-authenticated
8
- * signing endpoints. The private key NEVER enters the agent process.
6
+ * This module provides admin functions for the keyring proxy server:
7
+ * - createWallet() - Create a new wallet
8
+ * - hasWallet() - Check if a wallet exists
9
+ * - signAuthorization() - Sign EIP-7702 authorizations
9
10
  *
10
- * External code interacts only through:
11
- * - createWallet() → returns { address } (no private key)
12
- * - signMessage(msg) → returns { signature, address }
13
- * - signTransaction(tx) → returns { signedTx, address }
14
- * - signAuthorization(auth) → returns signed EIP-7702 authorization
15
- * - getAddress() → returns the public address
16
- * - hasWallet() → returns boolean
11
+ * For signing operations, use the Signer API instead:
17
12
  *
18
- * Configuration (via env vars or passed options):
19
- * KEYRING_PROXY_URL — URL of the keyring proxy server
20
- * KEYRING_PROXY_SECRET — HMAC shared secret
13
+ * ```typescript
14
+ * import { createKeyringProxySigner } from '@buildersgarden/siwa/signer';
15
+ *
16
+ * const signer = createKeyringProxySigner({ proxyUrl, proxySecret });
17
+ * const address = await signer.getAddress();
18
+ * const signature = await signer.signMessage(message);
19
+ * const signedTx = await signer.signTransaction(tx);
20
+ * ```
21
21
  */
22
22
  export interface KeystoreConfig {
23
23
  proxyUrl?: string;
@@ -26,10 +26,6 @@ export interface KeystoreConfig {
26
26
  export interface WalletInfo {
27
27
  address: string;
28
28
  }
29
- export interface SignResult {
30
- signature: string;
31
- address: string;
32
- }
33
29
  export interface AuthorizationRequest {
34
30
  address: string;
35
31
  chainId?: number;
@@ -43,23 +39,9 @@ export interface SignedAuthorization {
43
39
  r: string;
44
40
  s: string;
45
41
  }
46
- export interface TransactionLike {
47
- to?: string;
48
- data?: string;
49
- value?: bigint;
50
- nonce?: number;
51
- chainId?: number;
52
- type?: number;
53
- maxFeePerGas?: bigint | null;
54
- maxPriorityFeePerGas?: bigint | null;
55
- gasLimit?: bigint;
56
- gas?: bigint;
57
- gasPrice?: bigint | null;
58
- accessList?: any[];
59
- }
60
42
  /**
61
43
  * Create a new random wallet via the keyring proxy.
62
- * Returns only the public address — NEVER the private key.
44
+ * Returns only the public address.
63
45
  */
64
46
  export declare function createWallet(config?: KeystoreConfig): Promise<WalletInfo>;
65
47
  /**
@@ -67,35 +49,13 @@ export declare function createWallet(config?: KeystoreConfig): Promise<WalletInf
67
49
  */
68
50
  export declare function hasWallet(config?: KeystoreConfig): Promise<boolean>;
69
51
  /**
70
- * Get the wallet's public address (no private key exposed).
52
+ * Get the wallet's public address from the keyring proxy.
71
53
  */
72
54
  export declare function getAddress(config?: KeystoreConfig): Promise<string | null>;
73
- /**
74
- * Sign a message (EIP-191 personal_sign) via the keyring proxy.
75
- * Only the signature is returned.
76
- */
77
- export declare function signMessage(message: string, config?: KeystoreConfig): Promise<SignResult>;
78
- /**
79
- * Sign a raw hex message via the keyring proxy.
80
- *
81
- * Used internally by the ERC-8128 signer — the signature base bytes are
82
- * passed as a hex string and signed with `{ raw: true }` so the proxy
83
- * interprets them as raw bytes (not UTF-8). Note: the proxy still applies
84
- * EIP-191 personal_sign wrapping (viem `signMessage({ message: { raw } })`).
85
- */
86
- export declare function signRawMessage(rawHex: string, config?: KeystoreConfig): Promise<SignResult>;
87
- /**
88
- * Sign a transaction via the keyring proxy.
89
- * Only the signed transaction is returned.
90
- */
91
- export declare function signTransaction(tx: TransactionLike, config?: KeystoreConfig): Promise<{
92
- signedTx: string;
93
- address: string;
94
- }>;
95
55
  /**
96
56
  * Sign an EIP-7702 authorization for delegating the EOA to a contract.
97
57
  *
98
58
  * This allows the agent's EOA to temporarily act as a smart contract
99
- * during a type 4 transaction. Only the signed authorization tuple is returned.
59
+ * during a type 4 transaction.
100
60
  */
101
61
  export declare function signAuthorization(auth: AuthorizationRequest, config?: KeystoreConfig): Promise<SignedAuthorization>;
package/dist/keystore.js CHANGED
@@ -1,35 +1,35 @@
1
1
  /**
2
2
  * keystore.ts
3
3
  *
4
- * Secure signing abstraction for ERC-8004 agents.
4
+ * Keyring proxy administrative operations.
5
5
  *
6
- * All signing is delegated to a **keyring proxy server** — a separate process
7
- * that holds the encrypted private key and exposes only HMAC-authenticated
8
- * signing endpoints. The private key NEVER enters the agent process.
6
+ * This module provides admin functions for the keyring proxy server:
7
+ * - createWallet() - Create a new wallet
8
+ * - hasWallet() - Check if a wallet exists
9
+ * - signAuthorization() - Sign EIP-7702 authorizations
9
10
  *
10
- * External code interacts only through:
11
- * - createWallet() → returns { address } (no private key)
12
- * - signMessage(msg) → returns { signature, address }
13
- * - signTransaction(tx) → returns { signedTx, address }
14
- * - signAuthorization(auth) → returns signed EIP-7702 authorization
15
- * - getAddress() → returns the public address
16
- * - hasWallet() → returns boolean
11
+ * For signing operations, use the Signer API instead:
17
12
  *
18
- * Configuration (via env vars or passed options):
19
- * KEYRING_PROXY_URL — URL of the keyring proxy server
20
- * KEYRING_PROXY_SECRET — HMAC shared secret
13
+ * ```typescript
14
+ * import { createKeyringProxySigner } from '@buildersgarden/siwa/signer';
15
+ *
16
+ * const signer = createKeyringProxySigner({ proxyUrl, proxySecret });
17
+ * const address = await signer.getAddress();
18
+ * const signature = await signer.signMessage(message);
19
+ * const signedTx = await signer.signTransaction(tx);
20
+ * ```
21
21
  */
22
22
  import { computeHmac } from "./proxy-auth.js";
23
23
  // ---------------------------------------------------------------------------
24
- // Proxy backend — HMAC-authenticated HTTP to a keyring proxy server
24
+ // Proxy backend
25
25
  // ---------------------------------------------------------------------------
26
26
  async function proxyRequest(config, endpoint, body = {}) {
27
27
  const url = config.proxyUrl || process.env.KEYRING_PROXY_URL;
28
28
  const secret = config.proxySecret || process.env.KEYRING_PROXY_SECRET;
29
29
  if (!url)
30
- throw new Error("Keystore requires KEYRING_PROXY_URL or config.proxyUrl");
30
+ throw new Error("Keyring proxy requires KEYRING_PROXY_URL or config.proxyUrl");
31
31
  if (!secret)
32
- throw new Error("Keystore requires KEYRING_PROXY_SECRET or config.proxySecret");
32
+ throw new Error("Keyring proxy requires KEYRING_PROXY_SECRET or config.proxySecret");
33
33
  const bodyStr = JSON.stringify(body, (_key, value) => typeof value === "bigint" ? "0x" + value.toString(16) : value);
34
34
  const hmacHeaders = computeHmac(secret, "POST", endpoint, bodyStr);
35
35
  const res = await fetch(`${url}${endpoint}`, {
@@ -51,7 +51,7 @@ async function proxyRequest(config, endpoint, body = {}) {
51
51
  // ---------------------------------------------------------------------------
52
52
  /**
53
53
  * Create a new random wallet via the keyring proxy.
54
- * Returns only the public address — NEVER the private key.
54
+ * Returns only the public address.
55
55
  */
56
56
  export async function createWallet(config = {}) {
57
57
  const data = await proxyRequest(config, "/create-wallet");
@@ -65,51 +65,17 @@ export async function hasWallet(config = {}) {
65
65
  return data.hasWallet;
66
66
  }
67
67
  /**
68
- * Get the wallet's public address (no private key exposed).
68
+ * Get the wallet's public address from the keyring proxy.
69
69
  */
70
70
  export async function getAddress(config = {}) {
71
71
  const data = await proxyRequest(config, "/get-address");
72
72
  return data.address;
73
73
  }
74
- /**
75
- * Sign a message (EIP-191 personal_sign) via the keyring proxy.
76
- * Only the signature is returned.
77
- */
78
- export async function signMessage(message, config = {}) {
79
- const msg = typeof message === "string" ? message : String(message ?? "");
80
- const data = await proxyRequest(config, "/sign-message", { message: msg });
81
- return { signature: data.signature, address: data.address };
82
- }
83
- /**
84
- * Sign a raw hex message via the keyring proxy.
85
- *
86
- * Used internally by the ERC-8128 signer — the signature base bytes are
87
- * passed as a hex string and signed with `{ raw: true }` so the proxy
88
- * interprets them as raw bytes (not UTF-8). Note: the proxy still applies
89
- * EIP-191 personal_sign wrapping (viem `signMessage({ message: { raw } })`).
90
- */
91
- export async function signRawMessage(rawHex, config = {}) {
92
- const data = await proxyRequest(config, "/sign-message", {
93
- message: rawHex,
94
- raw: true,
95
- });
96
- return { signature: data.signature, address: data.address };
97
- }
98
- /**
99
- * Sign a transaction via the keyring proxy.
100
- * Only the signed transaction is returned.
101
- */
102
- export async function signTransaction(tx, config = {}) {
103
- const data = await proxyRequest(config, "/sign-transaction", {
104
- tx: tx,
105
- });
106
- return { signedTx: data.signedTx, address: data.address };
107
- }
108
74
  /**
109
75
  * Sign an EIP-7702 authorization for delegating the EOA to a contract.
110
76
  *
111
77
  * This allows the agent's EOA to temporarily act as a smart contract
112
- * during a type 4 transaction. Only the signed authorization tuple is returned.
78
+ * during a type 4 transaction.
113
79
  */
114
80
  export async function signAuthorization(auth, config = {}) {
115
81
  const data = await proxyRequest(config, "/sign-authorization", { auth });
package/dist/next.d.ts CHANGED
@@ -17,6 +17,7 @@
17
17
  * ```
18
18
  */
19
19
  import { type SiwaAgent } from './erc8128.js';
20
+ import type { SignerType } from './signer.js';
20
21
  export type { SiwaAgent };
21
22
  export interface WithSiwaOptions {
22
23
  /** HMAC secret for receipt verification. Defaults to RECEIPT_SECRET or SIWA_SECRET env. */
@@ -25,6 +26,8 @@ export interface WithSiwaOptions {
25
26
  rpcUrl?: string;
26
27
  /** Enable onchain ownerOf check. */
27
28
  verifyOnchain?: boolean;
29
+ /** Allowed signer types. Omit to accept all. */
30
+ allowedSignerTypes?: SignerType[];
28
31
  }
29
32
  /** CORS headers required by SIWA-authenticated requests. */
30
33
  export declare function corsHeaders(): Record<string, string>;
package/dist/next.js CHANGED
@@ -60,6 +60,7 @@ export function withSiwa(handler, options) {
60
60
  receiptSecret: secret,
61
61
  rpcUrl: options?.rpcUrl,
62
62
  verifyOnchain: options?.verifyOnchain,
63
+ allowedSignerTypes: options?.allowedSignerTypes,
63
64
  };
64
65
  const result = await verifyAuthenticatedRequest(nextjsToFetchRequest(verifyReq), verifyOptions);
65
66
  if (!result.valid) {
package/dist/receipt.d.ts CHANGED
@@ -14,12 +14,14 @@
14
14
  * Format: base64url(json).base64url(hmac-sha256)
15
15
  * Same token format as nonce tokens in siwa.ts.
16
16
  */
17
+ import type { SignerType } from './signer.js';
17
18
  export interface ReceiptPayload {
18
19
  address: string;
19
20
  agentId: number;
20
21
  agentRegistry: string;
21
22
  chainId: number;
22
23
  verified: 'offline' | 'onchain';
24
+ signerType?: SignerType;
23
25
  iat: number;
24
26
  exp: number;
25
27
  }