@x1id/resolve 0.23.0 → 0.43.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 (49) hide show
  1. package/README.md +71 -0
  2. package/dist/accounts.d.ts +6 -0
  3. package/dist/accounts.js +6 -1
  4. package/dist/agent.d.ts +184 -8
  5. package/dist/agent.js +351 -3
  6. package/dist/agentPolicy.d.ts +238 -0
  7. package/dist/agentPolicy.js +364 -0
  8. package/dist/attestation.d.ts +25 -0
  9. package/dist/attestation.js +25 -0
  10. package/dist/checkout.d.ts +216 -0
  11. package/dist/checkout.js +327 -0
  12. package/dist/credentials.d.ts +466 -0
  13. package/dist/credentials.js +669 -0
  14. package/dist/gate.d.ts +94 -4
  15. package/dist/gate.js +206 -7
  16. package/dist/gateClient.d.ts +12 -0
  17. package/dist/giftLink.d.ts +272 -0
  18. package/dist/giftLink.js +452 -0
  19. package/dist/index.d.ts +13 -0
  20. package/dist/index.js +32 -0
  21. package/dist/loginButton.d.ts +69 -0
  22. package/dist/loginButton.js +207 -0
  23. package/dist/logo.d.ts +1 -0
  24. package/dist/logo.js +8 -0
  25. package/dist/messaging.d.ts +439 -0
  26. package/dist/messaging.js +979 -0
  27. package/dist/nsGate.d.ts +98 -0
  28. package/dist/nsGate.js +172 -0
  29. package/dist/oidc.d.ts +272 -0
  30. package/dist/oidc.js +641 -0
  31. package/dist/pay.d.ts +513 -0
  32. package/dist/pay.js +756 -0
  33. package/dist/payment.d.ts +9 -2
  34. package/dist/payment.js +9 -2
  35. package/dist/recovery.d.ts +186 -0
  36. package/dist/recovery.js +276 -0
  37. package/dist/recoveryNft.d.ts +183 -0
  38. package/dist/recoveryNft.js +291 -0
  39. package/dist/shield.d.ts +373 -0
  40. package/dist/shield.js +695 -0
  41. package/dist/subscription.d.ts +439 -0
  42. package/dist/subscription.js +642 -0
  43. package/dist/textRecords.d.ts +52 -6
  44. package/dist/textRecords.js +80 -8
  45. package/dist/types.d.ts +3 -0
  46. package/dist/x402Receipt.d.ts +246 -0
  47. package/dist/x402Receipt.js +374 -0
  48. package/package.json +18 -1
  49. package/schema/agent-manifest.json +91 -8
package/README.md CHANGED
@@ -544,6 +544,22 @@ the supplied on-chain records disagree. `agentVerificationLevel` reports only
544
544
  the highest level it actually checked — L1 requires the manifest's claimed
545
545
  attestation to match a *live* one, never assumed from presence alone.
546
546
 
547
+ **Manifest v2** (0.32.0, `docs/agent-records.md` §3.1) adds per-capability /
548
+ per-endpoint `pricing` (`{amount, mint, unit}`), `payment.methods` (x402 on
549
+ the `x1` or `cdp` rail) and a name-bound `payment.payTo: {name}` — never an
550
+ address. Resolve what to pay from the chain:
551
+
552
+ ```ts
553
+ import { resolveManifestPayTo, manifestOffers, manifestCapabilities, payToWarnings } from "@x1id/resolve";
554
+
555
+ // records / authority: the payTo name's decoded address records and its
556
+ // current owner (or pNFT holder) — the inputs of paymentAddressFor (W16).
557
+ const perMethod = resolveManifestPayTo(result.manifest, { records, authority });
558
+ // [{ method, chain: "X1", payTo: { address, basis: "verified-record" } }, …]
559
+ const offers = manifestOffers(result.manifest); // [{ capability, url, price }, …]
560
+ const warnings = payToWarnings(result.manifest, { X1: perMethod[0]?.payTo?.address });
561
+ ```
562
+
547
563
  ## Verifying a non-SVM address record
548
564
 
549
565
  Prove control of an ETH, BTC, or another SVM address so its `Record` gets
@@ -702,6 +718,61 @@ the SIMD-0048 off-chain envelope). A nonce is single-use and expires, so on
702
718
  This is the hosted-session flow. For a server-less proof your own backend
703
719
  verifies, see `signInWithX1ID` in [SIGNIN.md](./SIGNIN.md).
704
720
 
721
+ ## Sign in with X1ID (OpenID Connect, `@x1id/resolve/oidc`)
722
+
723
+ For apps that want a standard OIDC login at `auth.x1id.io` (code + PKCE,
724
+ verified ID token, `/me` claims) instead of handling wallet signatures
725
+ themselves:
726
+
727
+ ```ts
728
+ import { createX1idOidcClient, completeX1idLogin } from "@x1id/resolve/oidc";
729
+ import { createX1idLoginButton } from "@x1id/resolve/login-button";
730
+
731
+ const x1id = createX1idOidcClient({ clientId: "x1c_…", redirectUri: "https://app.example/callback" });
732
+ document.querySelector("#login")!.append(createX1idLoginButton({ client: x1id })); // login page
733
+ const { sub, userInfo } = await completeX1idLogin(x1id); // /callback page
734
+ ```
735
+
736
+ `sub` is the wallet address (the account key); a login proves wallet control
737
+ at sign-in, not legal identity. Server (confidential) clients, refresh,
738
+ logout and the custom element are in
739
+ [services/auth/README.md](../services/auth/README.md#relying-party-quick-start).
740
+
741
+ ## Messaging (`@x1id/resolve/messaging`)
742
+
743
+ End-to-end encrypted messages between @names
744
+ ([spec](../docs/specs/x1id-messaging.md)). A separate entry point: it is the
745
+ only part of the package with runtime dependencies (the audited
746
+ `@noble/curves`, `@noble/ciphers`, `@noble/hashes`), so the root import never
747
+ loads them.
748
+
749
+ ```ts
750
+ import {
751
+ messagingKeyDerivationMessage, deriveMessagingKeyPair, encodeMessagingKeyRecord,
752
+ resolveMessagingKey, sealMessage, attachSignature, openMessage, buildMessageProofMemoIx,
753
+ } from "@x1id/resolve/messaging";
754
+
755
+ // 1. Key from a wallet signature (sign twice on set-up; both must match).
756
+ const sig = await wallet.signMessage(messagingKeyDerivationMessage(me, 0));
757
+ const keys = deriveMessagingKeyPair(sig, me, 0);
758
+ // 2. The owner publishes it as the `x1.msg.key` text record (owner pays):
759
+ // value = encodeMessagingKeyRecord({ publicKey: keys.publicKey, wallet: me, index: 0 })
760
+ // 3. Resolve a recipient with the trust rule (key set after the current
761
+ // holder's ownership epoch, by the holder or a delegate granted after it).
762
+ const r = await resolveMessagingKey("@bob", { rpcUrl, handleProgramId, wasm, find });
763
+ if (!r.verdict.ok) throw new Error(`@bob can't receive messages (${r.verdict.reason})`);
764
+ // 4. Seal for ONE network (bound into the signed header), have the sender's wallet
765
+ // sign the digest, send the envelope (+ recipientName: "bob") to that network's relay.
766
+ const u = sealMessage({ network: "mainnet", sender: me, recipient: r.verdict.key.wallet, recipientKey: r.verdict.key.publicKey, senderKey: keys.publicKey, text });
767
+ const envelope = attachSignature(u, await wallet.signMessage(u.signingMessage));
768
+ // 5. The recipient: openMessage(envelope, theirKeys, { network: "mainnet" }) verifies and decrypts.
769
+ // Optional sender-paid proof: buildMessageProofMemoIx({ sender: me, digest: u.digest }).
770
+ ```
771
+
772
+ Wallets whose message signatures don't verify on X1 sign a never-broadcast
773
+ memo transaction instead: `envelopeSigningTransaction` +
774
+ `attachTransactionSignature`.
775
+
705
776
  ## Errors
706
777
 
707
778
  `ResolveError` carries a `code` a UI can branch on:
@@ -43,6 +43,12 @@ export interface ParsedHandle {
43
43
  readonly holderEpoch: bigint;
44
44
  /** Set when the handle is tokenized (NFT extension present). */
45
45
  readonly nftMint: Uint8Array | null;
46
+ /** `Handle.recovery` — the configured recovery key, or null (Recovery 2). */
47
+ readonly recovery: Uint8Array | null;
48
+ /** `Handle.recovery_initiated_at` (0 = no recovery pending). */
49
+ readonly recoveryInitiatedAt: bigint;
50
+ /** `Handle.recovery_target` — who owns it once a pending recovery completes. */
51
+ readonly recoveryTarget: Uint8Array | null;
46
52
  }
47
53
  export declare function readI64(data: Uint8Array, offset: number): bigint;
48
54
  export declare function readU64(data: Uint8Array, offset: number): bigint;
package/dist/accounts.js CHANGED
@@ -96,11 +96,16 @@ export function parseHandleAccount(data) {
96
96
  // recovery: Option<Pubkey>
97
97
  if (pos >= data.length)
98
98
  return null;
99
+ const recovery = data[pos] === 1 ? data.slice(pos + 1, pos + 33) : null;
99
100
  pos += 1 + (data[pos] === 1 ? 32 : 0);
101
+ if (pos + 8 > data.length)
102
+ return null;
103
+ const recoveryInitiatedAt = readI64(data, pos);
100
104
  pos += 8; // recovery_initiated_at
101
105
  // recovery_target: Option<Pubkey>
102
106
  if (pos >= data.length)
103
107
  return null;
108
+ const recoveryTarget = data[pos] === 1 ? data.slice(pos + 1, pos + 33) : null;
104
109
  pos += 1 + (data[pos] === 1 ? 32 : 0);
105
110
  if (pos + 8 > data.length)
106
111
  return null;
@@ -110,7 +115,7 @@ export function parseHandleAccount(data) {
110
115
  : null;
111
116
  const recordsClearedAt = data.length >= RECORDS_CLEARED_EXT_OFFSET + 8 ? readI64(data, RECORDS_CLEARED_EXT_OFFSET) : 0n;
112
117
  const holderEpoch = data.length >= HOLDER_EPOCH_EXT_OFFSET + 8 ? readI64(data, HOLDER_EPOCH_EXT_OFFSET) : 0n;
113
- return { name, owner, registeredAt, recordsClearedAt, holderEpoch, nftMint };
118
+ return { name, owner, registeredAt, recordsClearedAt, holderEpoch, nftMint, recovery, recoveryInitiatedAt, recoveryTarget };
114
119
  }
115
120
  /** Build the RPC plumbing every reader in this package shares. */
116
121
  export function makeAccountReader(rpcUrl, fetchImpl) {
package/dist/agent.d.ts CHANGED
@@ -26,6 +26,8 @@
26
26
  import type { HandleTextRecord } from "./textRecords.js";
27
27
  import type { HandleAttestation } from "./attestation.js";
28
28
  import type { HandleRecord } from "./records.js";
29
+ import { type PaymentRecordLike, type PaymentResolution } from "./payment.js";
30
+ import { type Chain } from "./types.js";
29
31
  /** The six well-known `TextRecord` keys an agent handle may set. Every
30
32
  * value must be `https://` EXCEPT `manifest`, which may also be
31
33
  * `ipfs://<cid>` — see {@link checkAgentUrl}. */
@@ -38,11 +40,66 @@ export declare const AGENT_RECORD_KEYS: Readonly<{
38
40
  readonly capabilities: "agent.capabilities";
39
41
  }>;
40
42
  export type AgentEndpointType = "x402" | "mcp" | "a2a" | "http";
41
- /** `agent.manifest` v1 (`docs/agent-records.md` §3), as accepted by
42
- * {@link validateManifest}. */
43
+ /** Manifest versions {@link validateManifest} accepts. v1 is the original
44
+ * shape; v2 (`docs/agent-records.md` §3.1) adds per-capability / per-endpoint
45
+ * pricing, accepted payment methods and a name-bound `payTo`. A v1 manifest
46
+ * validates exactly as it always did. */
47
+ export declare const AGENT_MANIFEST_VERSIONS: readonly [1, 2];
48
+ export type AgentManifestVersion = (typeof AGENT_MANIFEST_VERSIONS)[number];
49
+ /** Billing units a v2 price may use. `per-call` is the x402 "exact" unit; the
50
+ * rest are metered units the seller's live 402 quotes per request. */
51
+ export declare const AGENT_PRICE_UNITS: readonly ["per-call", "per-1k-tokens", "per-1k-chars", "per-minute", "per-mb"];
52
+ export type AgentPriceUnit = (typeof AGENT_PRICE_UNITS)[number];
53
+ /** The native-asset sentinel for {@link AgentPrice.mint}: XNT on X1. */
54
+ export declare const AGENT_NATIVE_MINT = "XNT";
55
+ /** One v2 price. `amount` is a decimal string of the asset's SMALLEST units
56
+ * (lamports for XNT, base units for an SPL mint) — never a float. */
57
+ export interface AgentPrice {
58
+ readonly amount: string;
59
+ /** `"XNT"` (native) or an SPL mint (base58) on X1; a CDP-rail asset may also
60
+ * be an EVM token address (`0x…`). */
61
+ readonly mint: string;
62
+ readonly unit: AgentPriceUnit;
63
+ }
64
+ /** One accepted payment method (v2). `rail: "x1"` is the X1-native x402 rail
65
+ * (self-sponsored, settled on X1); `rail: "cdp"` is the Coinbase CDP
66
+ * facilitator rail (e.g. USDC on Solana / Base). */
67
+ export interface AgentPaymentMethod {
68
+ readonly id?: string;
69
+ readonly type: "x402";
70
+ readonly rail: "x1" | "cdp";
71
+ /** CAIP-2 network id — for `x1` the X1 network matching `x1id.network`
72
+ * (`X1_TESTNET_NETWORK` / `X1_MAINNET_NETWORK`). */
73
+ readonly network: string;
74
+ readonly scheme?: string;
75
+ readonly facilitator?: string;
76
+ /** Mints this method settles (same spelling as {@link AgentPrice.mint}). */
77
+ readonly assets?: readonly string[];
78
+ }
79
+ /** One advertised capability (v2), searchable in the directory by `id`. */
80
+ export interface AgentCapability {
81
+ readonly id: string;
82
+ readonly description?: string;
83
+ /** The `endpoints[].id` that serves this capability. */
84
+ readonly endpoint?: string;
85
+ readonly pricing?: readonly AgentPrice[];
86
+ }
87
+ export interface AgentEndpoint {
88
+ /** v2: stable id, referenced from `capabilities.items[].endpoint`. */
89
+ readonly id?: string;
90
+ readonly type: AgentEndpointType;
91
+ readonly url: string;
92
+ /** v2: capability ids served here. */
93
+ readonly capabilities?: readonly string[];
94
+ /** v2: this endpoint's own price(s). */
95
+ readonly pricing?: readonly AgentPrice[];
96
+ }
97
+ /** `agent.manifest` (`docs/agent-records.md` §3), v1 or v2, as accepted by
98
+ * {@link validateManifest}. Fields marked v2 are checked (and meaningful)
99
+ * only when `x1id.version === 2`. */
43
100
  export interface AgentManifest {
44
101
  readonly x1id: {
45
- readonly version: 1;
102
+ readonly version: AgentManifestVersion;
46
103
  readonly name: string;
47
104
  readonly network: "testnet" | "mainnet";
48
105
  /** Base58 address of the `Handle` PDA — the uniqueness anchor. */
@@ -56,15 +113,26 @@ export interface AgentManifest {
56
113
  readonly attestation?: string;
57
114
  readonly description?: string;
58
115
  };
59
- readonly endpoints?: readonly {
60
- readonly type: AgentEndpointType;
61
- readonly url: string;
62
- }[];
116
+ readonly endpoints?: readonly AgentEndpoint[];
63
117
  readonly capabilities?: {
64
118
  readonly schema?: string;
65
- readonly url: string;
119
+ /** Required in v1; optional in v2 when `items` is present. */
120
+ readonly url?: string;
121
+ /** v2: the searchable capability list. */
122
+ readonly items?: readonly AgentCapability[];
66
123
  };
67
124
  readonly payment?: {
125
+ /** v2: WHO gets paid — always an @name, never an address. The address is
126
+ * resolved from the chain under the one payment rule (W16,
127
+ * `paymentAddressFor`, the program's `name_pays_to`), so it cannot drift
128
+ * from the name. Required in v2 whenever anything is priced. */
129
+ readonly payTo?: {
130
+ readonly name: string;
131
+ };
132
+ /** v2: accepted payment methods. Required in v2 whenever anything is priced. */
133
+ readonly methods?: readonly AgentPaymentMethod[];
134
+ /** v1 mirror of the address records (still accepted in v2, never used as
135
+ * a v2 payTo). */
68
136
  readonly addresses?: readonly {
69
137
  readonly coinType: number;
70
138
  readonly address: string;
@@ -79,6 +147,8 @@ export interface AgentManifest {
79
147
  };
80
148
  };
81
149
  }
150
+ /** v2 id grammar (capability / endpoint / method ids): a lowercase slug. */
151
+ export declare const AGENT_ID_RE: RegExp;
82
152
  /** URL rule (`docs/agent-records.md` §2): every URL field is `https://`
83
153
  * ONLY, except `agent.manifest`'s own record value, which may also be
84
154
  * `ipfs://<cid>` (`allowIpfs`). */
@@ -120,6 +190,56 @@ export type ManifestValidationError = {
120
190
  } | {
121
191
  readonly code: "overclaims-verified";
122
192
  readonly coinType: number;
193
+ }
194
+ /** A v2 field has the wrong JSON type, or an array is over its cap. */
195
+ | {
196
+ readonly code: "bad-field";
197
+ readonly field: string;
198
+ } | {
199
+ readonly code: "bad-id";
200
+ readonly field: string;
201
+ } | {
202
+ readonly code: "duplicate-id";
203
+ readonly field: string;
204
+ readonly id: string;
205
+ }
206
+ /** An endpoint lists a capability id `capabilities.items[]` doesn't define. */
207
+ | {
208
+ readonly code: "unknown-capability";
209
+ readonly id: string;
210
+ }
211
+ /** A capability names an endpoint id `endpoints[]` doesn't define. */
212
+ | {
213
+ readonly code: "unknown-endpoint";
214
+ readonly id: string;
215
+ } | {
216
+ readonly code: "bad-price";
217
+ readonly field: string;
218
+ }
219
+ /** Something is priced but `payment.payTo` is absent. */
220
+ | {
221
+ readonly code: "missing-payto";
222
+ }
223
+ /** `payment.payTo.name` is not this manifest's own `x1id.name`. */
224
+ | {
225
+ readonly code: "payto-name-mismatch";
226
+ }
227
+ /** `payment.payTo` carries an address (or anything but `name`) — v2 never
228
+ * accepts a free-form pay-to address; it is resolved from the name. */
229
+ | {
230
+ readonly code: "free-form-payto";
231
+ }
232
+ /** Something is priced but `payment.methods` is empty / absent. */
233
+ | {
234
+ readonly code: "missing-payment-method";
235
+ } | {
236
+ readonly code: "bad-payment-method";
237
+ readonly field: string;
238
+ }
239
+ /** A price's mint is not settled by any listed payment method. */
240
+ | {
241
+ readonly code: "unsupported-price-mint";
242
+ readonly mint: string;
123
243
  };
124
244
  export type ManifestValidationResult = {
125
245
  readonly ok: true;
@@ -134,6 +254,62 @@ export type ManifestValidationResult = {
134
254
  * itself over what the caller already knows to be true on-chain.
135
255
  */
136
256
  export declare function validateManifest(raw: unknown, opts: ValidateManifestOptions): ManifestValidationResult;
257
+ /** Every capability id a (validated) manifest advertises: v2 `items[].id`
258
+ * plus endpoint tags, deduped, in first-seen order. `[]` for v1. Used by the
259
+ * directory to index capability search. */
260
+ export declare function manifestCapabilities(manifest: AgentManifest): string[];
261
+ /** One priced thing a manifest offers (flattened for display / discovery). */
262
+ export interface AgentOffer {
263
+ /** Capability id, or null for an endpoint-level price. */
264
+ readonly capability: string | null;
265
+ /** Endpoint id, when known. */
266
+ readonly endpoint: string | null;
267
+ /** Endpoint URL, when the price is (or the capability points) at one. */
268
+ readonly url: string | null;
269
+ readonly endpointType: AgentEndpointType | null;
270
+ readonly price: AgentPrice;
271
+ }
272
+ /** Flatten a v2 manifest's prices into offers. `[]` for v1. */
273
+ export declare function manifestOffers(manifest: AgentManifest): AgentOffer[];
274
+ /** The chain a payment method settles on, for the W16 rule. `null` = a
275
+ * network the rule cannot resolve (the method is then flagged unpayable). */
276
+ export declare function paymentMethodChain(method: Pick<AgentPaymentMethod, "rail" | "network">): Chain | null;
277
+ export interface ResolvedPaymentMethod {
278
+ readonly method: AgentPaymentMethod;
279
+ readonly chain: Chain | null;
280
+ /** The address to pay for this method, resolved from the @name — or null
281
+ * when the name has no honest address on that chain (see `reason`). */
282
+ readonly payTo: PaymentResolution | null;
283
+ readonly reason?: "unsupported-network" | "no-verified-record" | "no-authority";
284
+ }
285
+ /**
286
+ * Resolve a v2 manifest's payTo per payment method from the CHAIN — never from
287
+ * the manifest. `records` are the payTo name's decoded address records,
288
+ * `authority` its current authority (owner / pNFT holder), exactly the inputs
289
+ * of {@link paymentAddressFor} (W16, the program's `name_pays_to`).
290
+ *
291
+ * The owner fallback is only meaningful on SVM chains (X1 / SOL — the
292
+ * authority is an SVM key); on ETH only a live VERIFIED record pays, else the
293
+ * method has no address (`no-verified-record`), never the owner's SVM key.
294
+ */
295
+ export declare function resolveManifestPayTo(manifest: AgentManifest, input: {
296
+ readonly records: readonly PaymentRecordLike[];
297
+ readonly authority: string | null;
298
+ }): ResolvedPaymentMethod[];
299
+ /** A divergence between what a manifest SAYS about its pay-to and what the
300
+ * chain resolves for the name. Reported, never silently resolved. */
301
+ export interface PayToWarning {
302
+ readonly code: "payto-diverges";
303
+ readonly coinType: number;
304
+ /** The address the manifest mirrors. */
305
+ readonly claimed: string;
306
+ /** The W16-resolved address for that chain. */
307
+ readonly resolved: string;
308
+ }
309
+ /** Flag every `payment.addresses[]` mirror entry (v1 or v2) whose chain has a
310
+ * W16-resolved address that differs. `resolved` maps chain → the address
311
+ * {@link paymentAddressFor} returned for the name. */
312
+ export declare function payToWarnings(manifest: AgentManifest, resolved: Partial<Record<Chain, string>>): PayToWarning[];
137
313
  /** Pick the agent-related well-known keys out of a handle's live text
138
314
  * records (pass the output of `liveTextRecords` — stale entries excluded
139
315
  * already, matching every other read path's convention). */