openpay-x402-sdk 0.8.1 → 0.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.0 — 2026-09-21
4
+
5
+ - Add explicit `keystore` signer mode and `wallet_not_initialized` guard reason. `createSigner` requires the caller to supply keystore keys via `createSignerFromOptions`; no env-key fallback.
6
+ - Redact any `0x` + 64-hex value in error text as `[redacted_32byte_hex]` (a key configured through the SDK is still replaced as `[redacted_private_key]`). The generic label is deliberate: the same shape is also a transaction hash or a nonce, and it must not read as "your key leaked". Signature redaction is unchanged. Update public types; existing env-key / Steward behavior is unchanged.
7
+
3
8
  ## 0.8.1
4
9
 
5
10
  - Fix `openpay-x402-sdk/delivery` on Cloudflare Workers: the JWKS fetch called a
package/README.md CHANGED
@@ -577,6 +577,20 @@ returned or the facilitator signer could not be resolved. Treat `unverified` and
577
577
 
578
578
  ## Signers
579
579
 
580
+ The environment adapter accepts `SIGNER_MODE=env-key` (default), `steward`, or
581
+ `keystore`. Keystore is an explicit caller-managed mode: `createSigner(env)`
582
+ throws instead of loading a file or falling back to `BUYER_PRIVATE_KEY`. A caller
583
+ such as `openpay-x402-mcp` loads its wallet and uses
584
+ `createSignerFromOptions({ privateKey })`, passing the signer to the executor.
585
+ The keystore guard returns `wallet_not_initialized` when `signerAvailable` is
586
+ false; env-key and Steward retain their existing guard behavior. File storage
587
+ and the default daily limit for keystore are MCP responsibilities.
588
+
589
+ `safeErrorMessage` / `redactSensitiveText` redact 32-byte key hex and 65-byte
590
+ signature hex in error text. Do not apply these functions to payment payloads:
591
+ authorization nonces are also 32-byte hex. OpenPay does not receive, store, or
592
+ recover local wallet keys (OpenPay は鍵を受け取らない・保管しない・復元できない).
593
+
580
594
  Choose exactly one of `privateKey`, `steward`, or `signer`. Supplying more than
581
595
  one is a startup error. A custom signer has an EVM `address` and an async
582
596
  `signTypedData(typedData)` method.
package/index.d.ts CHANGED
@@ -166,7 +166,7 @@ export type OpenPayClientOptions = ClientCommonOptions &
166
166
  );
167
167
 
168
168
  export interface RuntimeConfig {
169
- signerMode: 'env-key' | 'steward';
169
+ signerMode: 'env-key' | 'steward' | 'keystore';
170
170
  buyerPrivateKey: string | null;
171
171
  stewardApiKey: string | null;
172
172
  stewardSignerSecret: string | null;
@@ -193,6 +193,10 @@ export interface OpenPaySession {
193
193
  }
194
194
 
195
195
  export interface DiscoveryItem {
196
+ /** Short display name (first-party, or seller-provided). */
197
+ title?: string;
198
+ /** One line describing when an agent should buy this resource (optional). */
199
+ trigger?: string;
196
200
  resource: string;
197
201
  description?: string;
198
202
  category?: string;
@@ -698,6 +702,7 @@ export const REASONS: {
698
702
  dailyAuthorizationCrossesUtcDay: 'daily_authorization_crosses_utc_day';
699
703
  buyerPrivateKeyMissing: 'buyer_private_key_missing';
700
704
  stewardSignerUnconfigured: 'steward_signer_unconfigured';
705
+ walletNotInitialized: 'wallet_not_initialized';
701
706
  catalogAcceptMismatch: 'catalog_accept_mismatch';
702
707
  };
703
708
  export const SUPPORTED_JPYC_ASSETS: Readonly<
@@ -822,10 +827,11 @@ export function safeErrorMessage(
822
827
  export const SIGNER_MODES: {
823
828
  envKey: 'env-key';
824
829
  steward: 'steward';
830
+ keystore: 'keystore';
825
831
  };
826
832
  export function readSignerMode(
827
833
  env?: Record<string, string | undefined>,
828
- ): 'env-key' | 'steward';
834
+ ): 'env-key' | 'steward' | 'keystore';
829
835
  export function createSigner(
830
836
  env?: Record<string, string | undefined>,
831
837
  options?: { fetchImpl?: typeof globalThis.fetch },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openpay-x402-sdk",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Guarded Node.js buyer SDK for OpenPay x402 JPYC resources",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
package/src/guards.mjs CHANGED
@@ -47,6 +47,7 @@ export const REASONS = {
47
47
  dailyAuthorizationCrossesUtcDay: 'daily_authorization_crosses_utc_day',
48
48
  buyerPrivateKeyMissing: 'buyer_private_key_missing',
49
49
  stewardSignerUnconfigured: 'steward_signer_unconfigured',
50
+ walletNotInitialized: 'wallet_not_initialized',
50
51
  // catalog trust 経由 (第三者ドメイン) の URL で、支払い時にライブ fetch した accept が
51
52
  // discovery 掲載 accept (OpenPay サーバー生成の権威値) と食い違う = bait-and-switch。
52
53
  catalogAcceptMismatch: 'catalog_accept_mismatch',
@@ -554,6 +555,8 @@ export function evaluatePaymentGuards({
554
555
  if (requirePrivateKey || requireSigner) {
555
556
  if (config.signerMode === SIGNER_MODES.steward) {
556
557
  if (!signerAvailable) reasons.push(REASONS.stewardSignerUnconfigured);
558
+ } else if (config.signerMode === SIGNER_MODES.keystore) {
559
+ if (!signerAvailable) reasons.push(REASONS.walletNotInitialized);
557
560
  } else if (config.buyerPrivateKey === null) {
558
561
  reasons.push(REASONS.buyerPrivateKeyMissing);
559
562
  }
@@ -574,7 +577,11 @@ export function redactSensitiveText(text, secrets = []) {
574
577
  out = out.split(secret).join('[redacted_private_key]');
575
578
  }
576
579
  }
577
- return out.replace(/\b0x[0-9a-fA-F]{130}\b/g, '[redacted_signature]');
580
+ return out
581
+ .replace(/\b0x[0-9a-fA-F]{130}\b/g, '[redacted_signature]')
582
+ // 32 バイトの hex は秘密鍵と同じ形だが、取引ハッシュや nonce でもあり得る。「鍵が漏れた」と
583
+ // 誤解させないラベルにする (既知の秘密の置換は上の [redacted_private_key] のまま)。
584
+ .replace(/\b0x[0-9a-fA-F]{64}\b/g, '[redacted_32byte_hex]');
578
585
  }
579
586
 
580
587
  export function safeErrorMessage(error, config = {}) {
package/src/signer.mjs CHANGED
@@ -4,6 +4,7 @@ import { privateKeyToAccount } from 'viem/accounts';
4
4
  export const SIGNER_MODES = {
5
5
  envKey: 'env-key',
6
6
  steward: 'steward',
7
+ keystore: 'keystore',
7
8
  };
8
9
 
9
10
  function nonEmpty(raw) {
@@ -12,8 +13,8 @@ function nonEmpty(raw) {
12
13
 
13
14
  export function readSignerMode(env = process.env) {
14
15
  const mode = nonEmpty(env.SIGNER_MODE) ?? SIGNER_MODES.envKey;
15
- if (mode !== SIGNER_MODES.envKey && mode !== SIGNER_MODES.steward) {
16
- throw new Error('SIGNER_MODE must be "env-key" or "steward"');
16
+ if (mode !== SIGNER_MODES.envKey && mode !== SIGNER_MODES.steward && mode !== SIGNER_MODES.keystore) {
17
+ throw new Error('SIGNER_MODE must be "env-key", "steward", or "keystore"');
17
18
  }
18
19
  return mode;
19
20
  }
@@ -182,6 +183,9 @@ function createStewardSigner(env, fetchImpl) {
182
183
 
183
184
  export function createSigner(env = process.env, { fetchImpl = fetch } = {}) {
184
185
  const mode = readSignerMode(env);
186
+ if (mode === SIGNER_MODES.keystore) {
187
+ throw new Error('keystore keys must be supplied by the caller via createSignerFromOptions');
188
+ }
185
189
  if (mode === SIGNER_MODES.envKey) return createEnvKeySigner(env);
186
190
  return createStewardSigner(env, fetchImpl);
187
191
  }