uvd-x402-sdk 2.100.0 → 2.102.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.
Files changed (59) hide show
  1. package/README.md +95 -6
  2. package/dist/adapters/index.d.mts +3 -2
  3. package/dist/adapters/index.d.ts +3 -2
  4. package/dist/adapters/index.js +522 -126
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/adapters/index.mjs +522 -126
  7. package/dist/adapters/index.mjs.map +1 -1
  8. package/dist/backend/index.d.mts +2 -2
  9. package/dist/backend/index.d.ts +2 -2
  10. package/dist/backend/index.js +490 -64
  11. package/dist/backend/index.js.map +1 -1
  12. package/dist/backend/index.mjs +484 -65
  13. package/dist/backend/index.mjs.map +1 -1
  14. package/dist/erc8128/index.d.mts +1 -1
  15. package/dist/erc8128/index.d.ts +1 -1
  16. package/dist/{index-prkNXpLX.d.mts → index-DKUUBqZO.d.mts} +220 -16
  17. package/dist/{index-CYMXb5eC.d.ts → index-Di8sCYHx.d.ts} +220 -16
  18. package/dist/index.d.mts +11 -5
  19. package/dist/index.d.ts +11 -5
  20. package/dist/index.js +738 -165
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +735 -166
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/ows-BB6Sgj0W.d.ts +342 -0
  25. package/dist/ows-DazT4KQH.d.mts +342 -0
  26. package/dist/providers/evm/index.js +31 -1
  27. package/dist/providers/evm/index.js.map +1 -1
  28. package/dist/providers/evm/index.mjs +31 -1
  29. package/dist/providers/evm/index.mjs.map +1 -1
  30. package/dist/providers/stellar/index.js +28 -0
  31. package/dist/providers/stellar/index.js.map +1 -1
  32. package/dist/providers/stellar/index.mjs +28 -0
  33. package/dist/providers/stellar/index.mjs.map +1 -1
  34. package/dist/providers/sui/index.js +27 -0
  35. package/dist/providers/sui/index.js.map +1 -1
  36. package/dist/providers/sui/index.mjs +27 -0
  37. package/dist/providers/sui/index.mjs.map +1 -1
  38. package/dist/react/index.js +49 -4
  39. package/dist/react/index.js.map +1 -1
  40. package/dist/react/index.mjs +49 -4
  41. package/dist/react/index.mjs.map +1 -1
  42. package/dist/{wallet-w7BnImDG.d.mts → wallet-T0NFUUkT.d.mts} +3 -2
  43. package/dist/{wallet-w7BnImDG.d.ts → wallet-T0NFUUkT.d.ts} +3 -2
  44. package/package.json +3 -2
  45. package/src/adapters/env-key.ts +5 -1
  46. package/src/adapters/index.ts +8 -1
  47. package/src/adapters/ows.ts +664 -154
  48. package/src/backend/index.ts +635 -22
  49. package/src/client/X402Client.ts +23 -3
  50. package/src/escrow-preauth.ts +32 -4
  51. package/src/index.ts +21 -1
  52. package/src/lifecycle-auth.ts +37 -31
  53. package/src/providers/evm/index.ts +9 -1
  54. package/src/providers/stellar/index.ts +5 -0
  55. package/src/providers/sui/index.ts +4 -0
  56. package/src/utils/uint.ts +252 -0
  57. package/src/wallet.ts +3 -2
  58. package/dist/ows-C-KmORG9.d.ts +0 -221
  59. package/dist/ows-Z9v4GxOZ.d.mts +0 -221
package/README.md CHANGED
@@ -17,7 +17,7 @@ Users sign a message or transaction, and the Ultravioleta facilitator handles on
17
17
  - **Buyer Policy**: Per-payment and cumulative budgets, payee allowlist and offer expiry, evaluated against the offer in hand **before signing** — six closed refusal codes in a fixed order
18
18
  - **Type-Safe**: Full TypeScript support
19
19
  - **React & Wagmi**: First-class integrations
20
- - **Signing Wallet Adapters**: EnvKeyAdapter (server/CLI), OWSWalletAdapter (Open Wallet Standard), or bring your own
20
+ - **Signing Wallet Adapters**: EnvKeyAdapter (server/CLI), OWSWalletAdapter (Open Wallet Standard vault, Node), or bring your own
21
21
  - **ERC-8128 Signed Requests**: Authenticate HTTP requests with a wallet (RFC 9421 + EIP-191) — no API keys
22
22
  - **ERC-8004 Trustless Agents**: On-chain reputation and identity across 23 networks (21 EVM + 2 Solana)
23
23
  - **Escrow & Refunds**: Hold payments with dispute resolution
@@ -560,16 +560,22 @@ const result = await wallet.signTypedData(JSON.stringify({
560
560
 
561
561
  ### OWSWalletAdapter (Open Wallet Standard)
562
562
 
563
- Delegates signing to any wallet that implements the [Open Wallet Standard](https://github.com/open-wallet-standard/open-wallet-standard). Works with browser wallets, agent vaults, and hardware-backed signers.
563
+ Signs with a wallet kept in an [Open Wallet Standard](https://github.com/open-wallet-standard/core) vault. OWS stores the keys encrypted on disk and signs inside the library, so the key never reaches your process. Node only: `@open-wallet-standard/core` is a native module with prebuilt binaries for Linux (glibc) and macOS, x64 and arm64.
564
564
 
565
565
  ```bash
566
- npm install @open-wallet-standard/core # optional peer dependency
566
+ npm install @open-wallet-standard/core # optional peer dependency, 1.4.2 or later 1.x
567
567
  ```
568
568
 
569
569
  ```typescript
570
+ import * as ows from '@open-wallet-standard/core';
570
571
  import { OWSWalletAdapter } from 'uvd-x402-sdk';
571
572
 
572
- const wallet = new OWSWalletAdapter(owsWalletInstance);
573
+ const wallet = new OWSWalletAdapter(ows, {
574
+ wallet: 'agent-treasury', // name or id of the wallet in the vault
575
+ passphrase: process.env.OWS_PASSPHRASE, // or an OWS API key; this is also the default
576
+ network: 'base', // chain used when the payload names none
577
+ // vaultPath: '/path/to/vault', // default: the OWS default (~/.ows)
578
+ });
573
579
 
574
580
  const auth = await wallet.signEIP3009({
575
581
  to: '0xRecipient...',
@@ -578,6 +584,29 @@ const auth = await wallet.signEIP3009({
578
584
  });
579
585
  ```
580
586
 
587
+ What it guarantees, tested against `@open-wallet-standard/core` 1.4.2 with an ephemeral key imported into a temporary vault:
588
+
589
+ - For inputs `EnvKeyAdapter` signs, it signs the same bytes: messages, EIP-3009 on every EVM network of the registry, typed data with uint256 up to `2**256 - 1` given as numbers, decimal strings or hex (the lifecycle order's `salt` included), and EIP-1559, EIP-2930 and legacy transactions (EIP-155 or not).
590
+ - Integers are checked against their EIP-712 type before anything is signed. OWS itself signs `2**256` as a uint256 as if it were `0`; the adapter throws `INVALID_AMOUNT` instead.
591
+ - Every signature is recovered with ethers over the digest `EnvKeyAdapter` signs. One that does not recover to `getAddress()` is not returned.
592
+ - `signTransaction` takes the hex ethers serializes, an `ethers.Transaction`, or a transaction object with `from`. A `from` that is not this wallet is refused before signing. A transaction without a `chainId` is signed pre-EIP-155, as `EnvKeyAdapter` signs it.
593
+ - The passphrase is never in the adapter's `JSON.stringify` / `util.inspect` output nor in its errors.
594
+
595
+ It refuses (`INVALID_CONFIG`, nothing signed) some inputs that ethers signs:
596
+
597
+ - Typed data: an integer string with spaces; a bool that is not a boolean (`1`, `0`, `"true"`, `"false"`; ethers signs `"false"` as true); `uint` / `int` without a width; a `primaryType` that is not the root struct (ethers ignores `primaryType` and signs the root).
598
+ - Transaction objects (`ethers.Wallet` signs these): a `type` given as `'0x2'`, `'2'` or a bigint; `to: ''`; `data: ''`; and any key ethers' `Transaction.from` does not read, other than `from` and `hash`. The error names the key, and for `input` / `gas` it names the ethers field (`data` / `gasLimit`).
599
+
600
+ A `vaultPath` that does not exist is created by OWS, so a typo gives "wallet not found".
601
+
602
+ **Migrating from the old form.** Up to 2.100.0 the adapter took a wallet object with `accounts` (the `OWSWallet` type). That shape never worked with `@open-wallet-standard/core` 1.x. It still compiles but is deprecated, and `new OWSWalletAdapter(wallet)` now throws `INVALID_CONFIG`. If you wrapped the library in such an object, drop the wrapper and pass the module and the wallet:
603
+
604
+ ```typescript
605
+ // before: new OWSWalletAdapter(createOWSWalletBridge(walletName, passphrase))
606
+ import * as ows from '@open-wallet-standard/core';
607
+ const wallet = new OWSWalletAdapter(ows, { wallet: walletName, passphrase });
608
+ ```
609
+
581
610
  ### Custom Adapter
582
611
 
583
612
  Implement the `SigningWalletAdapter` interface for your own signer:
@@ -1538,10 +1567,11 @@ const state = await client.queryEscrowState(paymentInfo);
1538
1567
  ### With SigningWalletAdapter (OWS)
1539
1568
 
1540
1569
  ```typescript
1570
+ import * as ows from '@open-wallet-standard/core';
1541
1571
  import { AdvancedEscrowClient } from 'uvd-x402-sdk/backend';
1542
1572
  import { OWSWalletAdapter } from 'uvd-x402-sdk';
1543
1573
 
1544
- const wallet = new OWSWalletAdapter(owsWalletInstance);
1574
+ const wallet = new OWSWalletAdapter(ows, { wallet: 'agent-treasury', network: 'base' });
1545
1575
  const client = new AdvancedEscrowClient(null, {
1546
1576
  wallet,
1547
1577
  rpcUrl: 'https://mainnet.base.org',
@@ -1635,7 +1665,7 @@ Register and discover paid x402 resources across the network.
1635
1665
  The Bazaar is served by the facilitator itself under `/discovery/*`. No API key, no separate host.
1636
1666
 
1637
1667
  ```typescript
1638
- import { BazaarClient, isAlive } from 'uvd-x402-sdk/backend';
1668
+ import { BazaarClient, bazaarExtension, isAlive } from 'uvd-x402-sdk/backend';
1639
1669
 
1640
1670
  const bazaar = new BazaarClient();
1641
1671
 
@@ -1657,6 +1687,16 @@ console.log(`${page.items.length} of ${page.pagination.total}`);
1657
1687
  // Free-text search. The parameter is `q`; anything else is rejected with a 400.
1658
1688
  const hits = await bazaar.listResources({ q: 'logs' });
1659
1689
 
1690
+ // Routing filters. Each one is sent only when you pass it.
1691
+ const posts = await bazaar.listResources({
1692
+ q: 'look up who owns a phone number, callable by an agent with a POST',
1693
+ method: 'POST', // GET | POST | PUT | PATCH, sent uppercased
1694
+ maxPriceUsd: 0.05, // price at most 5 cents
1695
+ hasInputSchema: true, // only resources that declare their input
1696
+ kind: 'api', // 'api' | 'content'
1697
+ excludeHost: 'tenjin.blog' // host names, comma-separated; not a URL, no port
1698
+ });
1699
+
1660
1700
  // Walk the whole filtered catalog, one page at a time
1661
1701
  for await (const r of bazaar.iterateResources({ health: 'alive' })) {
1662
1702
  if (isAlive(r)) console.log(r.url);
@@ -1675,6 +1715,9 @@ await bazaar.registerResource({
1675
1715
  maxTimeoutSeconds: 60,
1676
1716
  }],
1677
1717
  metadata: { category: 'ai', tags: ['image'] },
1718
+ // How to call it (see bazaarExtension below). Without it the listing
1719
+ // says hasInputSchema: false.
1720
+ extensions: bazaarExtension({ method: 'POST', body: { prompt: 'a red fox' } }),
1678
1721
  });
1679
1722
 
1680
1723
  // Aggregate catalog metrics
@@ -1684,6 +1727,52 @@ console.log(stats.total, stats.visible, stats.byHealth.alive);
1684
1727
 
1685
1728
  Timestamps (`firstSeen`, `lastSeen`, `lastUpdated`, `health.lastChecked`) are Unix epoch **seconds**. Use `epochToDate()` to get a `Date`.
1686
1729
 
1730
+ **Search length.** `q` can be up to 400 characters (`DEFAULT_MAX_SEARCH_LEN`), long enough for a request in natural language. Characters are counted as the facilitator counts them (code points: an emoji is one, not two). A longer `q` is refused before the request. Change the cap with `new BazaarClient({ maxSearchLen })`; against an older facilitator whose substring search takes at most 128 (up to 2.46.1, and some 2.47.0 builds), pass `maxSearchLen: MAX_SEARCH_LEN` to fail before the request instead of getting its 400. `getResourceByUrl()` searches with the URL's first 128 characters, which every facilitator accepts.
1731
+
1732
+ **Routing filters** (`maxPriceUsd`, `method`, `hasInputSchema`, `kind`, `excludeHost`) need facilitator 2.48.0 or later (some 2.47.0 builds have them and some do not). A facilitator without them (every one up to 2.46.1) answers each, as any query parameter it does not know, with a 400 that names it, so the client sends each of these only when you pass it: a call that sets none of them sends exactly what it sent before. A value you pass is sent or refused before the request, never dropped, by the rules the facilitator reads it with: `maxPriceUsd` is a number `>= 0`, sent in decimal (`1e-7` goes out as `0.0000001`) and refused if that takes more than 32 characters; `method` is `GET`, `POST`, `PUT` or `PATCH` in any case; `kind` is `api` or `content`; `excludeHost` is a host name, or up to 20 separated by commas, each matched with its subdomains, with no scheme, path or port. `null` counts as not passed.
1733
+
1734
+ **Registering with `extensions`.** `registerResource({ ..., extensions })` sends the object as the body's `extensions`, which the facilitator keeps as it comes: from `extensions.bazaar.info.input` the listing gets `hasInputSchema: true`, and it is found by `method: 'POST'` when that is what it declares. Pass the same `bazaarExtension(...)` you put in your 402. It must be a plain object of at most 16 KiB as JSON and 64 levels deep (the facilitator drops a bigger one without an error, so the client refuses it before the request). Without `extensions` the request body is exactly what it was. `extensions` only counts on a URL's first registration: registering a URL that is already in the catalog is answered with a 409 (`registerResource` throws) and leaves its record as it was, and the facilitator serves no public route that updates one. A URL listed without `extensions` does not gain them by registering again, so pass them the first time.
1735
+
1736
+ ### Declaring your endpoint to the Bazaar (`bazaarExtension`)
1737
+
1738
+ A seller can tell the facilitator how its endpoint is called inside the 402 itself, with the `bazaar` extension of x402 v2 ([spec](https://github.com/coinbase/x402/blob/main/specs/extensions/bazaar.md)). The facilitator catalogs the endpoint from it. The method travels in `info.input.method` and the example body in `info.input.body`: that is what a facilitator needs to probe a POST endpoint with a POST instead of a GET. Pass the same object as `extensions` to `BazaarClient.registerResource()` (above) when you register the endpoint yourself.
1739
+
1740
+ ```typescript
1741
+ import { bazaarExtension, create402Response } from 'uvd-x402-sdk';
1742
+
1743
+ // POST (or PUT / PATCH) with a JSON body
1744
+ const { status, headers, body } = create402Response(
1745
+ {
1746
+ amount: '0.05',
1747
+ recipient: '0xYourWallet...',
1748
+ resource: 'https://api.example.com/phone-lookup',
1749
+ chainName: 'base',
1750
+ x402Version: 2,
1751
+ },
1752
+ {
1753
+ extensions: bazaarExtension({
1754
+ method: 'POST',
1755
+ body: { phone: '+573001234567' }, // example body, required for POST/PUT/PATCH
1756
+ bodySchema: { // optional JSON Schema of the body
1757
+ type: 'object',
1758
+ properties: { phone: { type: 'string' } },
1759
+ required: ['phone'],
1760
+ },
1761
+ output: { example: { owner: 'ACME S.A.S.', carrier: 'Claro' } },
1762
+ }),
1763
+ }
1764
+ );
1765
+
1766
+ // GET (or HEAD / DELETE) with query parameters
1767
+ bazaarExtension({
1768
+ method: 'GET',
1769
+ queryParams: { city: 'Bogota' },
1770
+ output: { example: { city: 'Bogota', temperature: 18 } },
1771
+ });
1772
+ ```
1773
+
1774
+ The result is `{ bazaar: { info, schema } }`: `info.input` (`type: "http"`, `method`, then `bodyType` and `body` for a body method, or `queryParams` for a query method, plus optional `headers`), `info.output` (`type`, default `json`, and `example`), and `schema`, the JSON Schema (draft 2020-12) that `info` validates against. `bodyType` is `json` (default), `form-data` or `text` (then `body` is a string). A body method without `body`, a query method with one, or a method the spec does not name (`CONNECT`, `OPTIONS`, ...) throws. `extensions` is a v2 field: `create402Response` throws if the response would be v1 rather than dropping it, and without `extensions` it returns exactly what it returned before.
1775
+
1687
1776
  ## x402 v2 requests (`buildVerifyRequestV2` / `buildSettleRequestV2`)
1688
1777
 
1689
1778
  If your 402 advertises CAIP-2 networks (`eip155:8453`), you are speaking v2 and
@@ -1,6 +1,7 @@
1
1
  import { X as X402Version, a as PaymentResult } from '../index-DagQ74ZQ.mjs';
2
- export { E as EnvKeyAdapter, O as OWSWallet, a as OWSWalletAdapter } from '../ows-Z9v4GxOZ.mjs';
3
- import '../wallet-w7BnImDG.mjs';
2
+ export { E as EnvKeyAdapter, O as OWSAccountInfo, a as OWSCore, b as OWSSignResult, c as OWSWallet, d as OWSWalletAdapter, e as OWSWalletAdapterOptions } from '../ows-DazT4KQH.mjs';
3
+ import '../wallet-T0NFUUkT.mjs';
4
+ import 'ethers';
4
5
 
5
6
  /**
6
7
  * uvd-x402-sdk - Wagmi/Viem Adapter
@@ -1,6 +1,7 @@
1
1
  import { X as X402Version, a as PaymentResult } from '../index-DagQ74ZQ.js';
2
- export { E as EnvKeyAdapter, O as OWSWallet, a as OWSWalletAdapter } from '../ows-C-KmORG9.js';
3
- import '../wallet-w7BnImDG.js';
2
+ export { E as EnvKeyAdapter, O as OWSAccountInfo, a as OWSCore, b as OWSSignResult, c as OWSWallet, d as OWSWalletAdapter, e as OWSWalletAdapterOptions } from '../ows-BB6Sgj0W.js';
3
+ import '../wallet-T0NFUUkT.js';
4
+ import 'ethers';
4
5
 
5
6
  /**
6
7
  * uvd-x402-sdk - Wagmi/Viem Adapter