@leashmarket/core 0.1.0 → 0.2.1

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 (50) hide show
  1. package/README.md +16 -3
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/mpp/client.d.ts +82 -0
  7. package/dist/mpp/client.d.ts.map +1 -0
  8. package/dist/mpp/client.js +155 -0
  9. package/dist/mpp/client.js.map +1 -0
  10. package/dist/mpp/envelope.d.ts +38 -0
  11. package/dist/mpp/envelope.d.ts.map +1 -0
  12. package/dist/mpp/envelope.js +25 -0
  13. package/dist/mpp/envelope.js.map +1 -0
  14. package/dist/mpp/headers.d.ts +56 -0
  15. package/dist/mpp/headers.d.ts.map +1 -0
  16. package/dist/mpp/headers.js +88 -0
  17. package/dist/mpp/headers.js.map +1 -0
  18. package/dist/mpp/index.d.ts +5 -0
  19. package/dist/mpp/index.d.ts.map +1 -0
  20. package/dist/mpp/index.js +5 -0
  21. package/dist/mpp/index.js.map +1 -0
  22. package/dist/mpp/parse.d.ts +26 -0
  23. package/dist/mpp/parse.d.ts.map +1 -0
  24. package/dist/mpp/parse.js +55 -0
  25. package/dist/mpp/parse.js.map +1 -0
  26. package/dist/mpp-helpers/base64-json.d.ts +7 -0
  27. package/dist/mpp-helpers/base64-json.d.ts.map +1 -0
  28. package/dist/mpp-helpers/base64-json.js +25 -0
  29. package/dist/mpp-helpers/base64-json.js.map +1 -0
  30. package/dist/payments/detect.d.ts +55 -0
  31. package/dist/payments/detect.d.ts.map +1 -0
  32. package/dist/payments/detect.js +77 -0
  33. package/dist/payments/detect.js.map +1 -0
  34. package/dist/payments/index.d.ts +3 -0
  35. package/dist/payments/index.d.ts.map +1 -0
  36. package/dist/payments/index.js +2 -0
  37. package/dist/payments/index.js.map +1 -0
  38. package/dist/receipt/build.d.ts +7 -1
  39. package/dist/receipt/build.d.ts.map +1 -1
  40. package/dist/receipt/build.js +6 -0
  41. package/dist/receipt/build.js.map +1 -1
  42. package/dist/x402/client.d.ts +8 -0
  43. package/dist/x402/client.d.ts.map +1 -1
  44. package/dist/x402/client.js +71 -2
  45. package/dist/x402/client.js.map +1 -1
  46. package/dist/x402/envelope.d.ts +4 -4
  47. package/dist/x402/envelope.d.ts.map +1 -1
  48. package/dist/x402/envelope.js +18 -4
  49. package/dist/x402/envelope.js.map +1 -1
  50. package/package.json +2 -2
package/README.md CHANGED
@@ -3,6 +3,16 @@
3
3
  Policy evaluation, receipt hashing / chain verification, real x402 client
4
4
  adapter for Solana, treasury helpers, and an env-based kill-switch.
5
5
 
6
+ ## Install
7
+
8
+ ```bash
9
+ npm install @leashmarket/core
10
+ # or
11
+ pnpm add @leashmarket/core
12
+ ```
13
+
14
+ ## Usage
15
+
6
16
  ```ts
7
17
  import {
8
18
  evaluate,
@@ -22,11 +32,14 @@ import { createSvmBuyerFetch } from '@leashmarket/core/x402';
22
32
  All hashing uses `@noble/hashes` so the package runs unchanged in Node,
23
33
  the browser, and edge runtimes.
24
34
 
35
+ ## Docs
36
+
37
+ [docs.leash.market/sdk/core](https://docs.leash.market/sdk/core)
38
+
39
+ See also: [Real x402 on Solana](https://docs.leash.market/standards/x402-on-solana)
40
+
25
41
  ## Test
26
42
 
27
43
  ```bash
28
44
  pnpm --filter @leashmarket/core test
29
45
  ```
30
-
31
- See the [`Real x402 on Solana`](../../apps/docs/standards/x402-on-solana.mdx)
32
- doc for the protocol-level walkthrough.
package/dist/index.d.ts CHANGED
@@ -13,6 +13,8 @@ export * from './x402/facilitator.js';
13
13
  export * from './x402/headers.js';
14
14
  export * from './x402/parse.js';
15
15
  export * from './x402/webhook.js';
16
+ export * from './mpp/index.js';
17
+ export * from './payments/index.js';
16
18
  export * from './treasury/balance.js';
17
19
  export * from './treasury/inspect-token-account.js';
18
20
  export * from './treasury/list-balances.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qCAAqC,CAAC;AACpD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qCAAqC,CAAC;AACpD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -13,6 +13,8 @@ export * from './x402/facilitator.js';
13
13
  export * from './x402/headers.js';
14
14
  export * from './x402/parse.js';
15
15
  export * from './x402/webhook.js';
16
+ export * from './mpp/index.js';
17
+ export * from './payments/index.js';
16
18
  export * from './treasury/balance.js';
17
19
  export * from './treasury/inspect-token-account.js';
18
20
  export * from './treasury/list-balances.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qCAAqC,CAAC;AACpD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qCAAqC,CAAC;AACpD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * MPP-on-Solana buyer client.
3
+ *
4
+ * Mirrors {@link createSvmBuyerFetch} (x402 client) but speaks the MPP
5
+ * wire shape: GET -> 402 with `application/problem+json` body ->
6
+ * build SPL `TransferChecked` matching `request.recipient/amount/asset`
7
+ * -> sign -> POST credential to facilitator (or local-settle) -> retry
8
+ * the original request with `Authorization: PaymentScheme <b64>` and
9
+ * carry the settlement metadata back to the caller.
10
+ *
11
+ * The returned `paidFetch` is a drop-in replacement for `fetch`, so
12
+ * buyer-kit can layer dual-protocol routing on top via
13
+ * {@link detectProtocol} without splitting its public API.
14
+ */
15
+ import { type Address } from '@solana/kit';
16
+ import type { ClientSvmSigner } from '@x402/svm';
17
+ import type { MppChallengeV1 } from '@leashmarket/schemas';
18
+ import { type LeashFetch, type LeashX402Network } from '../x402/client.js';
19
+ export type CreateSvmMppFetchOptions = {
20
+ /** Authority that signs the SPL transfer (delegate or owner of `sourceTokenAccount`). */
21
+ signer: ClientSvmSigner;
22
+ /**
23
+ * Solana clusters to allow. The buyer rejects challenges whose `network`
24
+ * is not in this list. Defaults to all three Solana clusters.
25
+ */
26
+ networks?: LeashX402Network[];
27
+ /** Optional RPC endpoint override forwarded to `@x402/svm` helpers. */
28
+ rpcUrl?: string;
29
+ /**
30
+ * If set, the SPL transfer debits from this token account and `signer`
31
+ * signs as the SPL **delegate** (mirror of LeashDelegateExactSvmScheme).
32
+ * Leave undefined for "signer pays from their own ATA".
33
+ */
34
+ sourceTokenAccount?: Address | string;
35
+ /**
36
+ * Facilitator URL the seller forwards credentials to. Buyers don't talk
37
+ * to the facilitator directly — the seller does — but we record it on
38
+ * the receipt so explorers can re-verify settlement. Defaults to the
39
+ * Leash devnet/mainnet facilitator depending on `networks`.
40
+ */
41
+ facilitatorUrl?: string;
42
+ };
43
+ /**
44
+ * Settlement output the buyer-kit layer reads off the wire after the
45
+ * retry succeeds. Fields are populated from response headers stamped by
46
+ * the seller (mirrors x402's `PAYMENT-RESPONSE`).
47
+ */
48
+ export type MppSettlement = {
49
+ challengeId: string;
50
+ /** Solana SPL transfer signature that satisfied the challenge. */
51
+ settlementTx: string;
52
+ settlementSlot: string | number;
53
+ };
54
+ /**
55
+ * Per-call result carried through the wrapped fetch so buyer-kit can
56
+ * stamp it onto a `ReceiptV02Mpp`. Exposed here so consumers writing
57
+ * their own client (without buyer-kit) can read it too.
58
+ */
59
+ export type MppPaidResponse = {
60
+ response: Response;
61
+ challenge: MppChallengeV1;
62
+ settlement: MppSettlement | null;
63
+ };
64
+ /**
65
+ * Build a paid `fetch` for MPP-on-Solana. Returns a function that
66
+ * accepts the same args as `fetch` and resolves to a regular `Response`.
67
+ * Buyer-kit (Phase 3) layers a richer return shape via the dual-fetch
68
+ * orchestrator; this raw fetch is convenient for tests + standalone use.
69
+ */
70
+ export declare function createSvmMppFetch(opts: CreateSvmMppFetchOptions): LeashFetch;
71
+ /**
72
+ * Lower-level: build and sign the SPL transfer that satisfies the
73
+ * challenge. Exported so seller-kit tests and the explorer can replay
74
+ * the buyer side without a real network call.
75
+ */
76
+ export declare function buildAndSignMppTransfer(args: {
77
+ challenge: MppChallengeV1;
78
+ signer: ClientSvmSigner;
79
+ sourceTokenAccount?: Address | string;
80
+ rpcUrl?: string;
81
+ }): Promise<string>;
82
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/mpp/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAEL,KAAK,OAAO,EAUb,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQ3E,MAAM,MAAM,wBAAwB,GAAG;IACrC,yFAAyF;IACzF,MAAM,EAAE,eAAe,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACtC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,cAAc,CAAC;IAC1B,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,UAAU,CA4C5E;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,SAAS,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,eAAe,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwFlB"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * MPP-on-Solana buyer client.
3
+ *
4
+ * Mirrors {@link createSvmBuyerFetch} (x402 client) but speaks the MPP
5
+ * wire shape: GET -> 402 with `application/problem+json` body ->
6
+ * build SPL `TransferChecked` matching `request.recipient/amount/asset`
7
+ * -> sign -> POST credential to facilitator (or local-settle) -> retry
8
+ * the original request with `Authorization: PaymentScheme <b64>` and
9
+ * carry the settlement metadata back to the caller.
10
+ *
11
+ * The returned `paidFetch` is a drop-in replacement for `fetch`, so
12
+ * buyer-kit can layer dual-protocol routing on top via
13
+ * {@link detectProtocol} without splitting its public API.
14
+ */
15
+ import { address as toAddress, appendTransactionMessageInstructions, createTransactionMessage, getBase64EncodedWireTransaction, partiallySignTransactionMessageWithSigners, pipe, prependTransactionMessageInstruction, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, } from '@solana/kit';
16
+ import { getSetComputeUnitLimitInstruction, setTransactionMessageComputeUnitPrice, } from '@solana-program/compute-budget';
17
+ import { fetchMint, findAssociatedTokenPda, getCreateAssociatedTokenIdempotentInstruction, getTransferCheckedInstruction, TOKEN_2022_PROGRAM_ADDRESS, } from '@solana-program/token-2022';
18
+ import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
19
+ import { createRpcClient, MEMO_PROGRAM_ADDRESS, MAX_MEMO_BYTES } from '@x402/svm';
20
+ import {} from '../x402/client.js';
21
+ import { defaultFacilitatorFor } from '../x402/facilitator.js';
22
+ import { buildMppAuthorizationHeader } from './headers.js';
23
+ import { parseMppChallenge } from './parse.js';
24
+ const DEFAULT_COMPUTE_UNIT_LIMIT = 200_000;
25
+ const DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 10_000;
26
+ /**
27
+ * Build a paid `fetch` for MPP-on-Solana. Returns a function that
28
+ * accepts the same args as `fetch` and resolves to a regular `Response`.
29
+ * Buyer-kit (Phase 3) layers a richer return shape via the dual-fetch
30
+ * orchestrator; this raw fetch is convenient for tests + standalone use.
31
+ */
32
+ export function createSvmMppFetch(opts) {
33
+ const allowedNetworks = new Set((opts.networks ?? ['solana-mainnet', 'solana-devnet', 'solana-testnet']));
34
+ const facilitatorUrl = opts.facilitatorUrl ?? defaultFacilitatorFor(opts.networks);
35
+ return async function mppFetch(input, init) {
36
+ const firstResponse = await globalThis.fetch(input, init);
37
+ if (firstResponse.status !== 402)
38
+ return firstResponse;
39
+ // Caller may have signalled a non-MPP 402 (x402). Fall back to the
40
+ // original response so the dual-protocol orchestrator can route.
41
+ let challenge;
42
+ try {
43
+ challenge = await parseMppChallenge(firstResponse);
44
+ }
45
+ catch {
46
+ return firstResponse;
47
+ }
48
+ if (!allowedNetworks.has(challenge.request.network)) {
49
+ throw new Error(`mpp: seller asked for network "${challenge.request.network}" which is not in allowedNetworks`);
50
+ }
51
+ const signedTx = await buildAndSignMppTransfer({
52
+ challenge,
53
+ signer: opts.signer,
54
+ sourceTokenAccount: opts.sourceTokenAccount,
55
+ ...(opts.rpcUrl ? { rpcUrl: opts.rpcUrl } : {}),
56
+ });
57
+ const credential = {
58
+ v: '1',
59
+ challengeId: challenge.challengeId,
60
+ signedTx,
61
+ };
62
+ const authHeader = buildMppAuthorizationHeader(credential);
63
+ const retryInit = {
64
+ ...(init ?? {}),
65
+ headers: mergeAuthorizationHeader(init?.headers, authHeader),
66
+ };
67
+ const settled = await globalThis.fetch(input, retryInit);
68
+ return attachFacilitatorOnResponse(settled, facilitatorUrl);
69
+ };
70
+ }
71
+ /**
72
+ * Lower-level: build and sign the SPL transfer that satisfies the
73
+ * challenge. Exported so seller-kit tests and the explorer can replay
74
+ * the buyer side without a real network call.
75
+ */
76
+ export async function buildAndSignMppTransfer(args) {
77
+ const { challenge, signer } = args;
78
+ // `createRpcClient` accepts the CAIP-2 / friendly slug forms x402 already
79
+ // emits; cast at the boundary so we can keep the schema's `string` shape.
80
+ const rpc = createRpcClient(challenge.request.network, args.rpcUrl);
81
+ const tokenMint = await fetchMint(rpc, challenge.request.asset);
82
+ const tokenProgramAddress = tokenMint.programAddress;
83
+ if (tokenProgramAddress.toString() !== TOKEN_PROGRAM_ADDRESS.toString() &&
84
+ tokenProgramAddress.toString() !== TOKEN_2022_PROGRAM_ADDRESS.toString()) {
85
+ throw new Error('mpp: asset was not created by a known token program');
86
+ }
87
+ let source;
88
+ if (args.sourceTokenAccount) {
89
+ source =
90
+ typeof args.sourceTokenAccount === 'string'
91
+ ? toAddress(args.sourceTokenAccount)
92
+ : args.sourceTokenAccount;
93
+ }
94
+ else {
95
+ const [ownerAta] = await findAssociatedTokenPda({
96
+ mint: challenge.request.asset,
97
+ owner: signer.address,
98
+ tokenProgram: tokenProgramAddress,
99
+ });
100
+ source = ownerAta;
101
+ }
102
+ const [destinationATA] = await findAssociatedTokenPda({
103
+ mint: challenge.request.asset,
104
+ owner: challenge.request.recipient,
105
+ tokenProgram: tokenProgramAddress,
106
+ });
107
+ const feePayerAddress = challenge.request.feePayer
108
+ ? toAddress(challenge.request.feePayer)
109
+ : signer.address;
110
+ const feePayerSigner = feePayerAddress;
111
+ const provisionSellerAtaIx = getCreateAssociatedTokenIdempotentInstruction({
112
+ payer: feePayerSigner,
113
+ ata: destinationATA,
114
+ owner: challenge.request.recipient,
115
+ mint: challenge.request.asset,
116
+ tokenProgram: tokenProgramAddress,
117
+ });
118
+ const transferIx = getTransferCheckedInstruction({
119
+ source,
120
+ mint: challenge.request.asset,
121
+ destination: destinationATA,
122
+ authority: signer,
123
+ amount: BigInt(challenge.request.amount),
124
+ decimals: tokenMint.data.decimals,
125
+ }, { programAddress: tokenProgramAddress });
126
+ // Memo binds challengeId to the on-chain tx so the facilitator can
127
+ // verify that this signed transfer matches the challenge it received.
128
+ const memoBytes = new TextEncoder().encode(`mpp:${challenge.challengeId}`);
129
+ if (memoBytes.byteLength > MAX_MEMO_BYTES) {
130
+ throw new Error(`mpp: challengeId memo exceeds maximum ${MAX_MEMO_BYTES} bytes`);
131
+ }
132
+ const memoIx = {
133
+ programAddress: MEMO_PROGRAM_ADDRESS,
134
+ accounts: [],
135
+ data: memoBytes,
136
+ };
137
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
138
+ const tx = pipe(createTransactionMessage({ version: 0 }), (t) => setTransactionMessageComputeUnitPrice(DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS, t), (t) => setTransactionMessageFeePayer(feePayerAddress, t), (t) => prependTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: DEFAULT_COMPUTE_UNIT_LIMIT }), t), (t) => appendTransactionMessageInstructions([provisionSellerAtaIx, transferIx, memoIx], t), (t) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, t));
139
+ const signed = await partiallySignTransactionMessageWithSigners(tx);
140
+ return getBase64EncodedWireTransaction(signed);
141
+ }
142
+ function mergeAuthorizationHeader(existing, authValue) {
143
+ const h = new Headers((existing ?? {}));
144
+ h.set('authorization', authValue);
145
+ return h;
146
+ }
147
+ /**
148
+ * Pass-through for now — placeholder for future client-side telemetry
149
+ * (e.g. recording the facilitator URL on a debug wrapper). Keeps the
150
+ * call-site readable and gives us a single hook for future logic.
151
+ */
152
+ function attachFacilitatorOnResponse(response, _facilitatorUrl) {
153
+ return response;
154
+ }
155
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mpp/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Hashing + canonical wire envelope for MPP receipts.
3
+ *
4
+ * MPP receipts (v0.2 mpp variant in `@leashmarket/schemas`) hash the
5
+ * same way x402 receipts do: SHA-256 of the canonical JSON of the
6
+ * draft (everything except `receipt_hash`). The `protocol` discriminator
7
+ * is part of the canonical body so x402 and MPP receipts in the same
8
+ * agent's chain can never collide on hash.
9
+ *
10
+ * This file also exports a thin helper to canonicalise an MPP challenge
11
+ * for replay-protection bookkeeping (sellers track issued challengeIds
12
+ * to reject reuse; the canonical form gives a stable id-by-content).
13
+ */
14
+ import type { MppChallengeV1 } from '@leashmarket/schemas';
15
+ /**
16
+ * Stable hash of a challenge — useful when persisting issued challenges
17
+ * to reject replays without storing the full body.
18
+ */
19
+ export declare function mppChallengeHash(challenge: MppChallengeV1): string;
20
+ /**
21
+ * Compact wire summary of a settled MPP payment, mirroring
22
+ * {@link LeashPaymentEnvelope} for x402. Sellers stamp this on response
23
+ * headers / webhooks so downstream consumers can render proofs without
24
+ * reading the full receipt.
25
+ */
26
+ export type MppPaymentEnvelope = {
27
+ protocol: 'mpp';
28
+ challengeId: string;
29
+ /** Solana SPL transfer signature that satisfied the challenge. */
30
+ settlementTx: string;
31
+ settlementSlot: string | number;
32
+ /** SHA-256 of the canonical receipt — useful as an idempotency key. */
33
+ receiptHash: string;
34
+ /** Mint address of the agent that earned the payment. */
35
+ agent: string;
36
+ network: string | null;
37
+ };
38
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/mpp/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAM3D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,CAGlE;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Hashing + canonical wire envelope for MPP receipts.
3
+ *
4
+ * MPP receipts (v0.2 mpp variant in `@leashmarket/schemas`) hash the
5
+ * same way x402 receipts do: SHA-256 of the canonical JSON of the
6
+ * draft (everything except `receipt_hash`). The `protocol` discriminator
7
+ * is part of the canonical body so x402 and MPP receipts in the same
8
+ * agent's chain can never collide on hash.
9
+ *
10
+ * This file also exports a thin helper to canonicalise an MPP challenge
11
+ * for replay-protection bookkeeping (sellers track issued challengeIds
12
+ * to reject reuse; the canonical form gives a stable id-by-content).
13
+ */
14
+ import { sha256 } from '@noble/hashes/sha256';
15
+ import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils';
16
+ import { canonicalJson } from '../receipt/hash.js';
17
+ /**
18
+ * Stable hash of a challenge — useful when persisting issued challenges
19
+ * to reject replays without storing the full body.
20
+ */
21
+ export function mppChallengeHash(challenge) {
22
+ const canonical = canonicalJson(challenge);
23
+ return bytesToHex(sha256(utf8ToBytes(canonical)));
24
+ }
25
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/mpp/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAyB;IACxD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * MPP credential header construction + parsing.
3
+ *
4
+ * MPP-on-Solana piggybacks on the standard HTTP `Authorization` header
5
+ * with a custom scheme prefix. The buyer signs an SPL transfer that
6
+ * matches the challenge `request` block (recipient/amount/asset), then
7
+ * sends:
8
+ *
9
+ * Authorization: PaymentScheme <base64(MppCredential)>
10
+ *
11
+ * The credential body shape we use mirrors the x402 PaymentPayload —
12
+ * a base64-wire signed Solana transaction plus the originating
13
+ * `challengeId`. The seller forwards `(challengeId, signedTx)` to the
14
+ * facilitator, which verifies and broadcasts.
15
+ */
16
+ export declare const MPP_AUTH_SCHEME = "PaymentScheme";
17
+ export declare const MPP_HEADERS: {
18
+ /** Buyer-supplied credential. */
19
+ readonly authorization: "authorization";
20
+ /** Seller -> buyer settlement proof header (mirror of x402 PAYMENT-RESPONSE). */
21
+ readonly paymentReceipt: "x-payment-receipt";
22
+ };
23
+ export type MppCredentialV1 = {
24
+ v: '1';
25
+ challengeId: string;
26
+ /** Base64-encoded wire transaction the facilitator will broadcast. */
27
+ signedTx: string;
28
+ /**
29
+ * Optional buyer signature over the canonicalised challenge nonce.
30
+ * Reserved for non-Solana rails; on Solana the SPL transfer signature
31
+ * is itself proof of authorization.
32
+ */
33
+ nonceSig?: string;
34
+ };
35
+ /**
36
+ * Encode an MPP credential into the value half of an `Authorization`
37
+ * header (everything after `PaymentScheme `).
38
+ */
39
+ export declare function encodeMppCredential(credential: MppCredentialV1): string;
40
+ /**
41
+ * Build a full `Authorization: PaymentScheme <base64>` header value.
42
+ */
43
+ export declare function buildMppAuthorizationHeader(credential: MppCredentialV1): string;
44
+ /**
45
+ * Parse a value already stripped of the scheme prefix into a typed
46
+ * credential. Throws on malformed input.
47
+ */
48
+ export declare function decodeMppCredential(encoded: string): MppCredentialV1;
49
+ /**
50
+ * Parse a raw `Authorization` header value (with or without the scheme
51
+ * prefix). Returns `null` when the header is absent or uses a different
52
+ * scheme — callers should treat that as "buyer didn't pay yet".
53
+ */
54
+ export declare function parseMppAuthorization(header: string | null | undefined): MppCredentialV1 | null;
55
+ export declare const MPP_CREDENTIAL_VERSION_LITERAL: "1";
56
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/mpp/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C,eAAO,MAAM,WAAW;IACtB,iCAAiC;;IAEjC,iFAAiF;;CAEzE,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG;IAC5B,CAAC,EAAE,GAAG,CAAC;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAIF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAUvE;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAE/E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAepE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,eAAe,GAAG,IAAI,CAW/F;AAED,eAAO,MAAM,8BAA8B,KAAyB,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * MPP credential header construction + parsing.
3
+ *
4
+ * MPP-on-Solana piggybacks on the standard HTTP `Authorization` header
5
+ * with a custom scheme prefix. The buyer signs an SPL transfer that
6
+ * matches the challenge `request` block (recipient/amount/asset), then
7
+ * sends:
8
+ *
9
+ * Authorization: PaymentScheme <base64(MppCredential)>
10
+ *
11
+ * The credential body shape we use mirrors the x402 PaymentPayload —
12
+ * a base64-wire signed Solana transaction plus the originating
13
+ * `challengeId`. The seller forwards `(challengeId, signedTx)` to the
14
+ * facilitator, which verifies and broadcasts.
15
+ */
16
+ import { decodeBase64Json } from '../mpp-helpers/base64-json.js';
17
+ export const MPP_AUTH_SCHEME = 'PaymentScheme';
18
+ export const MPP_HEADERS = {
19
+ /** Buyer-supplied credential. */
20
+ authorization: 'authorization',
21
+ /** Seller -> buyer settlement proof header (mirror of x402 PAYMENT-RESPONSE). */
22
+ paymentReceipt: 'x-payment-receipt',
23
+ };
24
+ const MPP_CREDENTIAL_VERSION = '1';
25
+ /**
26
+ * Encode an MPP credential into the value half of an `Authorization`
27
+ * header (everything after `PaymentScheme `).
28
+ */
29
+ export function encodeMppCredential(credential) {
30
+ const json = JSON.stringify(credential);
31
+ const bytes = new TextEncoder().encode(json);
32
+ // Browser-safe base64. Falls back to Node's Buffer when present.
33
+ if (typeof btoa === 'function') {
34
+ let bin = '';
35
+ for (let i = 0; i < bytes.length; i++)
36
+ bin += String.fromCharCode(bytes[i]);
37
+ return btoa(bin);
38
+ }
39
+ return Buffer.from(bytes).toString('base64');
40
+ }
41
+ /**
42
+ * Build a full `Authorization: PaymentScheme <base64>` header value.
43
+ */
44
+ export function buildMppAuthorizationHeader(credential) {
45
+ return `${MPP_AUTH_SCHEME} ${encodeMppCredential(credential)}`;
46
+ }
47
+ /**
48
+ * Parse a value already stripped of the scheme prefix into a typed
49
+ * credential. Throws on malformed input.
50
+ */
51
+ export function decodeMppCredential(encoded) {
52
+ const parsed = decodeBase64Json(encoded);
53
+ if (!parsed || typeof parsed !== 'object') {
54
+ throw new Error('mpp: malformed credential payload');
55
+ }
56
+ if (parsed.v !== MPP_CREDENTIAL_VERSION) {
57
+ throw new Error(`mpp: unsupported credential version "${parsed.v}"`);
58
+ }
59
+ if (typeof parsed.challengeId !== 'string' || parsed.challengeId.length === 0) {
60
+ throw new Error('mpp: credential missing challengeId');
61
+ }
62
+ if (typeof parsed.signedTx !== 'string' || parsed.signedTx.length === 0) {
63
+ throw new Error('mpp: credential missing signedTx');
64
+ }
65
+ return parsed;
66
+ }
67
+ /**
68
+ * Parse a raw `Authorization` header value (with or without the scheme
69
+ * prefix). Returns `null` when the header is absent or uses a different
70
+ * scheme — callers should treat that as "buyer didn't pay yet".
71
+ */
72
+ export function parseMppAuthorization(header) {
73
+ if (!header)
74
+ return null;
75
+ const trimmed = header.trim();
76
+ if (!trimmed)
77
+ return null;
78
+ // Accept both "PaymentScheme <b64>" and a bare b64 payload (defensive).
79
+ const prefix = `${MPP_AUTH_SCHEME} `;
80
+ const encoded = trimmed.toLowerCase().startsWith(prefix.toLowerCase())
81
+ ? trimmed.slice(prefix.length).trim()
82
+ : trimmed;
83
+ if (!encoded)
84
+ return null;
85
+ return decodeMppCredential(encoded);
86
+ }
87
+ export const MPP_CREDENTIAL_VERSION_LITERAL = MPP_CREDENTIAL_VERSION;
88
+ //# sourceMappingURL=headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../../src/mpp/headers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { parseMppChallenge, parseMppChallengeBody, looksLikeMppChallenge, MPP_PROBLEM_TYPE, } from './parse.js';
2
+ export { buildMppAuthorizationHeader, decodeMppCredential, encodeMppCredential, parseMppAuthorization, MPP_AUTH_SCHEME, MPP_HEADERS, MPP_CREDENTIAL_VERSION_LITERAL, type MppCredentialV1, } from './headers.js';
3
+ export { mppChallengeHash, type MppPaymentEnvelope } from './envelope.js';
4
+ export { buildAndSignMppTransfer, createSvmMppFetch, type CreateSvmMppFetchOptions, type MppPaidResponse, type MppSettlement, } from './client.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mpp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,8BAA8B,EAC9B,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { parseMppChallenge, parseMppChallengeBody, looksLikeMppChallenge, MPP_PROBLEM_TYPE, } from './parse.js';
2
+ export { buildMppAuthorizationHeader, decodeMppCredential, encodeMppCredential, parseMppAuthorization, MPP_AUTH_SCHEME, MPP_HEADERS, MPP_CREDENTIAL_VERSION_LITERAL, } from './headers.js';
3
+ export { mppChallengeHash } from './envelope.js';
4
+ export { buildAndSignMppTransfer, createSvmMppFetch, } from './client.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mpp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,8BAA8B,GAE/B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAA2B,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,iBAAiB,GAIlB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Parse an MPP `402 Payment Required` HTTP response into a typed
3
+ * {@link MppChallengeV1}. MPP carries the challenge in the **body** as
4
+ * `application/problem+json` (RFC 7807-flavoured) — distinct from x402,
5
+ * which carries it in the `payment-required` response header.
6
+ *
7
+ * Throws on every malformed shape so callers wrap once and surface the
8
+ * message verbatim. The discriminator (`type === '...payment-required'`
9
+ * + a non-empty `challengeId`) lets `detectProtocol` route confidently.
10
+ */
11
+ import { type MppChallengeV1 } from '@leashmarket/schemas';
12
+ export declare const MPP_PROBLEM_TYPE = "https://paymentauth.org/problems/payment-required";
13
+ /**
14
+ * Returns true if the Response body looks like an MPP 402 challenge.
15
+ * Cheap structural check — doesn't run full Zod validation.
16
+ */
17
+ export declare function looksLikeMppChallenge(body: unknown): boolean;
18
+ /**
19
+ * Parse a `Response` (must be 402) into a strict {@link MppChallengeV1}.
20
+ * The caller is responsible for confirming `response.status === 402`
21
+ * (raw 402s with non-MPP bodies are x402 territory).
22
+ */
23
+ export declare function parseMppChallenge(response: Response): Promise<MppChallengeV1>;
24
+ /** Lower-level form for callers that have already JSON-parsed the body. */
25
+ export declare function parseMppChallengeBody(body: unknown): MppChallengeV1;
26
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/mpp/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEjF,eAAO,MAAM,gBAAgB,sDAAsD,CAAC;AAiBpF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAI5D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAMnF;AAED,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAEnE"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Parse an MPP `402 Payment Required` HTTP response into a typed
3
+ * {@link MppChallengeV1}. MPP carries the challenge in the **body** as
4
+ * `application/problem+json` (RFC 7807-flavoured) — distinct from x402,
5
+ * which carries it in the `payment-required` response header.
6
+ *
7
+ * Throws on every malformed shape so callers wrap once and surface the
8
+ * message verbatim. The discriminator (`type === '...payment-required'`
9
+ * + a non-empty `challengeId`) lets `detectProtocol` route confidently.
10
+ */
11
+ import { MppChallengeV1Schema } from '@leashmarket/schemas';
12
+ export const MPP_PROBLEM_TYPE = 'https://paymentauth.org/problems/payment-required';
13
+ /**
14
+ * Read JSON safely from a Response — clones first so the caller can
15
+ * still consume the body afterwards (e.g. for a debugger UI dump).
16
+ */
17
+ async function readJsonClone(res) {
18
+ try {
19
+ const cloned = res.clone();
20
+ const text = await cloned.text();
21
+ if (!text)
22
+ return null;
23
+ return JSON.parse(text);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ /**
30
+ * Returns true if the Response body looks like an MPP 402 challenge.
31
+ * Cheap structural check — doesn't run full Zod validation.
32
+ */
33
+ export function looksLikeMppChallenge(body) {
34
+ if (!body || typeof body !== 'object')
35
+ return false;
36
+ const b = body;
37
+ return b.type === MPP_PROBLEM_TYPE && typeof b.challengeId === 'string';
38
+ }
39
+ /**
40
+ * Parse a `Response` (must be 402) into a strict {@link MppChallengeV1}.
41
+ * The caller is responsible for confirming `response.status === 402`
42
+ * (raw 402s with non-MPP bodies are x402 territory).
43
+ */
44
+ export async function parseMppChallenge(response) {
45
+ const body = await readJsonClone(response);
46
+ if (!looksLikeMppChallenge(body)) {
47
+ throw new Error('mpp: body is not an MPP problem+json challenge');
48
+ }
49
+ return MppChallengeV1Schema.parse(body);
50
+ }
51
+ /** Lower-level form for callers that have already JSON-parsed the body. */
52
+ export function parseMppChallengeBody(body) {
53
+ return MppChallengeV1Schema.parse(body);
54
+ }
55
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/mpp/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AAEjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,mDAAmD,CAAC;AAEpF;;;GAGG;AACH,KAAK,UAAU,aAAa,CAAC,GAAa;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpD,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,OAAO,CAAC,CAAC,IAAI,KAAK,gBAAgB,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAkB;IACxD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared base64 -> JSON decoder used by MPP credential / probe paths.
3
+ * Returns `null` instead of throwing on malformed input so callers can
4
+ * decide whether to surface a generic error.
5
+ */
6
+ export declare function decodeBase64Json(b64: string): unknown;
7
+ //# sourceMappingURL=base64-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64-json.d.ts","sourceRoot":"","sources":["../../src/mpp-helpers/base64-json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAerD"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared base64 -> JSON decoder used by MPP credential / probe paths.
3
+ * Returns `null` instead of throwing on malformed input so callers can
4
+ * decide whether to surface a generic error.
5
+ */
6
+ export function decodeBase64Json(b64) {
7
+ try {
8
+ let bin;
9
+ if (typeof atob === 'function') {
10
+ bin = atob(b64);
11
+ }
12
+ else {
13
+ bin = Buffer.from(b64, 'base64').toString('binary');
14
+ }
15
+ const bytes = new Uint8Array(bin.length);
16
+ for (let i = 0; i < bin.length; i++)
17
+ bytes[i] = bin.charCodeAt(i);
18
+ const text = new TextDecoder().decode(bytes);
19
+ return JSON.parse(text);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ //# sourceMappingURL=base64-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64-json.js","sourceRoot":"","sources":["../../src/mpp-helpers/base64-json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,IAAI,GAAW,CAAC;QAChB,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;YAC/B,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Single source of truth for "is this a 402 from x402 or MPP?".
3
+ *
4
+ * Used by buyer-kit, the MCP `pay_payment_link` tool, the CLI, and the
5
+ * frontend probe modal so every surface dispatches consistently.
6
+ *
7
+ * Contract:
8
+ * - x402: `payment-required` response header carrying a base64-JSON
9
+ * envelope with `accepts[]`.
10
+ * - MPP : `application/problem+json` body whose `type` is the MPP
11
+ * payment-required URI, plus a non-empty `challengeId`.
12
+ *
13
+ * Returns `null` if the response isn't a 402 at all (callers can short-
14
+ * circuit), or `{ protocol: 'unknown' }` for a 402 we couldn't parse —
15
+ * callers usually surface that as a hard failure.
16
+ */
17
+ import { MPP_PROBLEM_TYPE } from '../mpp/parse.js';
18
+ import type { MppChallengeV1 } from '@leashmarket/schemas';
19
+ export type ProtocolDetection = {
20
+ status: 402;
21
+ protocol: 'x402';
22
+ /** Raw `payment-required` header value (base64-JSON). Caller decodes if needed. */
23
+ paymentRequiredHeader: string;
24
+ } | {
25
+ status: 402;
26
+ protocol: 'mpp';
27
+ challenge: MppChallengeV1;
28
+ } | {
29
+ status: 402;
30
+ protocol: 'unknown';
31
+ /** Best-effort body / header diagnostics for the debugger UI. */
32
+ detail: string;
33
+ } | {
34
+ status: number;
35
+ protocol: 'none';
36
+ };
37
+ /**
38
+ * Detect the payment protocol of a `Response`. Clones the body before
39
+ * reading so the caller can still consume it afterwards (debugger UIs
40
+ * often want to render the raw bytes).
41
+ */
42
+ export declare function detectProtocol(response: Response): Promise<ProtocolDetection>;
43
+ /**
44
+ * Stricter form for callers that already know they hit a 402. Throws
45
+ * on `none` / `unknown` so the call-site can do `try/catch` cleanly.
46
+ */
47
+ export declare function detectProtocolStrict(response: Response): Promise<{
48
+ protocol: 'x402';
49
+ paymentRequiredHeader: string;
50
+ } | {
51
+ protocol: 'mpp';
52
+ challenge: MppChallengeV1;
53
+ }>;
54
+ export { MPP_PROBLEM_TYPE };
55
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/payments/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,gBAAgB,EAAgD,MAAM,iBAAiB,CAAC;AACjG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,iBAAiB,GACzB;IACE,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GACD;IACE,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,KAAK,CAAC;IAChB,SAAS,EAAE,cAAc,CAAC;CAC3B,GACD;IACE,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,SAAS,CAAC;IACpB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqCnF;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,QAAQ,GACjB,OAAO,CACN;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,qBAAqB,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,CACjD,CAYA;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Single source of truth for "is this a 402 from x402 or MPP?".
3
+ *
4
+ * Used by buyer-kit, the MCP `pay_payment_link` tool, the CLI, and the
5
+ * frontend probe modal so every surface dispatches consistently.
6
+ *
7
+ * Contract:
8
+ * - x402: `payment-required` response header carrying a base64-JSON
9
+ * envelope with `accepts[]`.
10
+ * - MPP : `application/problem+json` body whose `type` is the MPP
11
+ * payment-required URI, plus a non-empty `challengeId`.
12
+ *
13
+ * Returns `null` if the response isn't a 402 at all (callers can short-
14
+ * circuit), or `{ protocol: 'unknown' }` for a 402 we couldn't parse —
15
+ * callers usually surface that as a hard failure.
16
+ */
17
+ import { MPP_PROBLEM_TYPE, looksLikeMppChallenge, parseMppChallengeBody } from '../mpp/parse.js';
18
+ /**
19
+ * Detect the payment protocol of a `Response`. Clones the body before
20
+ * reading so the caller can still consume it afterwards (debugger UIs
21
+ * often want to render the raw bytes).
22
+ */
23
+ export async function detectProtocol(response) {
24
+ if (response.status !== 402) {
25
+ return { status: response.status, protocol: 'none' };
26
+ }
27
+ // Prefer an MPP problem+json body over `payment-required` when both are
28
+ // present. Some stacks attach x402-shaped headers on every 402; MPP is
29
+ // identified by the body and must win so buyer-kit runs tryMppRoute.
30
+ let bodyText = '';
31
+ try {
32
+ bodyText = await response.clone().text();
33
+ }
34
+ catch {
35
+ // ignore
36
+ }
37
+ if (bodyText.length > 0) {
38
+ let body = null;
39
+ try {
40
+ body = JSON.parse(bodyText);
41
+ }
42
+ catch {
43
+ body = null;
44
+ }
45
+ if (looksLikeMppChallenge(body)) {
46
+ return { status: 402, protocol: 'mpp', challenge: parseMppChallengeBody(body) };
47
+ }
48
+ }
49
+ const headerValue = response.headers.get('payment-required') ?? response.headers.get('PAYMENT-REQUIRED');
50
+ if (headerValue && headerValue.length > 0) {
51
+ return { status: 402, protocol: 'x402', paymentRequiredHeader: headerValue };
52
+ }
53
+ return {
54
+ status: 402,
55
+ protocol: 'unknown',
56
+ detail: bodyText ? bodyText.slice(0, 400) : 'no body, no payment-required header',
57
+ };
58
+ }
59
+ /**
60
+ * Stricter form for callers that already know they hit a 402. Throws
61
+ * on `none` / `unknown` so the call-site can do `try/catch` cleanly.
62
+ */
63
+ export async function detectProtocolStrict(response) {
64
+ const det = await detectProtocol(response);
65
+ if (det.protocol === 'none') {
66
+ throw new Error(`expected 402 from paywall, got HTTP ${det.status}`);
67
+ }
68
+ if (det.protocol === 'unknown') {
69
+ throw new Error(`paywall response is neither x402 nor MPP: ${det.detail}`);
70
+ }
71
+ if (det.protocol === 'x402') {
72
+ return { protocol: 'x402', paymentRequiredHeader: det.paymentRequiredHeader };
73
+ }
74
+ return { protocol: 'mpp', challenge: det.challenge };
75
+ }
76
+ export { MPP_PROBLEM_TYPE };
77
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/payments/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AA0BjG;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAkB;IACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACvD,CAAC;IAED,wEAAwE;IACxE,uEAAuE;IACvE,qEAAqE;IACrE,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,IAAI,GAAY,IAAI,CAAC;QACzB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAY,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;QACD,IAAI,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClF,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GACf,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACvF,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,qBAAqB,EAAE,WAAW,EAAE,CAAC;IAC/E,CAAC;IAED,OAAO;QACL,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,SAAS;QACnB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qCAAqC;KAClF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAkB;IAKlB,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,qBAAqB,EAAE,GAAG,CAAC,qBAAqB,EAAE,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;AACvD,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { detectProtocol, detectProtocolStrict, MPP_PROBLEM_TYPE } from './detect.js';
2
+ export type { ProtocolDetection } from './detect.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/payments/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACrF,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { detectProtocol, detectProtocolStrict, MPP_PROBLEM_TYPE } from './detect.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/payments/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
@@ -1,5 +1,11 @@
1
1
  import type { ReceiptV1 } from '@leashmarket/schemas';
2
2
  export type ReceiptDraft = Omit<ReceiptV1, 'receipt_hash'>;
3
- export declare function computeReceiptHash(draft: ReceiptDraft): string;
3
+ /**
4
+ * SHA-256 (hex) of the canonical JSON form of a receipt draft. Generic so
5
+ * v0.2 receipts (x402 + mpp variants) can be hashed without copy-pasting
6
+ * the implementation. The wire shape is identical — keys are sorted and
7
+ * `receipt_hash` itself is excluded from the input.
8
+ */
9
+ export declare function computeReceiptHash<T extends object>(draft: T): string;
4
10
  export declare function finalizeReceipt(draft: ReceiptDraft): ReceiptV1;
5
11
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/receipt/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AAE3D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,CAG9D"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/receipt/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAErE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,CAG9D"}
@@ -1,4 +1,10 @@
1
1
  import { canonicalJson, sha256Hex } from './hash.js';
2
+ /**
3
+ * SHA-256 (hex) of the canonical JSON form of a receipt draft. Generic so
4
+ * v0.2 receipts (x402 + mpp variants) can be hashed without copy-pasting
5
+ * the implementation. The wire shape is identical — keys are sorted and
6
+ * `receipt_hash` itself is excluded from the input.
7
+ */
2
8
  export function computeReceiptHash(draft) {
3
9
  return sha256Hex(canonicalJson(draft));
4
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/receipt/build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAIrD,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,OAAO,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAmB;IACjD,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/receipt/build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAIrD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAmB,KAAQ;IAC3D,OAAO,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAmB;IACjD,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC"}
@@ -6,6 +6,14 @@ import type { ClientSvmSigner } from '@x402/svm';
6
6
  import { LeashDelegateExactSvmScheme, LeashExactSvmScheme } from './delegate-scheme.js';
7
7
  import type { Address } from '@solana/kit';
8
8
  export type LeashFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
9
+ /**
10
+ * Like `@x402/fetch` `wrapFetchWithPayment`, but returns MPP `402` responses
11
+ * unchanged so the body stays valid for {@link detectProtocol} /
12
+ * buyer-kit `tryMppRoute`. Upstream `wrapFetchWithPayment` reads
13
+ * `response.text()` for every 402, which consumes MPP `problem+json`
14
+ * before Leash can act on it.
15
+ */
16
+ export declare function wrapFetchWithMppAwarePayment(fetchImpl: typeof globalThis.fetch, client: x402Client): LeashFetch;
9
17
  export type LeashX402Network = 'solana-mainnet' | 'solana-devnet' | 'solana-testnet';
10
18
  export declare function caip2ForNetwork(network: LeashX402Network): Network;
11
19
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/x402/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElG,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAQrF,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAElE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAWhF;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,eAAe,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACtC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,2BAA2B,GAAG,UAAU,CAmCjF;AAED,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,2BAA2B,EAC3B,mBAAmB,GACpB,CAAC;AACF,YAAY,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/x402/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElG;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAClC,MAAM,EAAE,UAAU,GACjB,UAAU,CAgEZ;AAED,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAQrF,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAElE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAWhF;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,eAAe,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACtC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,2BAA2B,GAAG,UAAU,CAmCjF;AAED,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,2BAA2B,EAC3B,mBAAmB,GACpB,CAAC;AACF,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -1,8 +1,77 @@
1
- import { x402Client } from '@x402/core/client';
1
+ import { x402Client, x402HTTPClient } from '@x402/core/client';
2
2
  import { wrapFetchWithPayment } from '@x402/fetch';
3
3
  import { ExactSvmScheme } from '@x402/svm';
4
4
  import { SOLANA_DEVNET_CAIP2, SOLANA_MAINNET_CAIP2, SOLANA_TESTNET_CAIP2 } from '@x402/svm';
5
5
  import { LeashDelegateExactSvmScheme, LeashExactSvmScheme } from './delegate-scheme.js';
6
+ import { detectProtocol } from '../payments/detect.js';
7
+ /**
8
+ * Like `@x402/fetch` `wrapFetchWithPayment`, but returns MPP `402` responses
9
+ * unchanged so the body stays valid for {@link detectProtocol} /
10
+ * buyer-kit `tryMppRoute`. Upstream `wrapFetchWithPayment` reads
11
+ * `response.text()` for every 402, which consumes MPP `problem+json`
12
+ * before Leash can act on it.
13
+ */
14
+ export function wrapFetchWithMppAwarePayment(fetchImpl, client) {
15
+ const httpClient = client instanceof x402HTTPClient ? client : new x402HTTPClient(client);
16
+ return async (input, init) => {
17
+ const request = new Request(input, init);
18
+ const clonedRequest = request.clone();
19
+ const response = await fetchImpl(request);
20
+ if (response.status !== 402) {
21
+ return response;
22
+ }
23
+ const det = await detectProtocol(response);
24
+ if (det.protocol === 'mpp') {
25
+ return response;
26
+ }
27
+ let paymentRequired;
28
+ try {
29
+ const getHeader = (name) => response.headers.get(name);
30
+ let body;
31
+ try {
32
+ const responseText = await response.text();
33
+ if (responseText) {
34
+ body = JSON.parse(responseText);
35
+ }
36
+ }
37
+ catch {
38
+ /* ignore */
39
+ }
40
+ paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);
41
+ }
42
+ catch (error) {
43
+ throw new Error(`Failed to parse payment requirements: ${error instanceof Error ? error.message : 'Unknown error'}`);
44
+ }
45
+ const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);
46
+ if (hookHeaders) {
47
+ const hookRequest = clonedRequest.clone();
48
+ for (const [key, value] of Object.entries(hookHeaders)) {
49
+ hookRequest.headers.set(key, value);
50
+ }
51
+ const hookResponse = await fetchImpl(hookRequest);
52
+ if (hookResponse.status !== 402) {
53
+ return hookResponse;
54
+ }
55
+ }
56
+ let paymentPayload;
57
+ try {
58
+ paymentPayload = await client.createPaymentPayload(paymentRequired);
59
+ }
60
+ catch (error) {
61
+ throw new Error(`Failed to create payment payload: ${error instanceof Error ? error.message : 'Unknown error'}`);
62
+ }
63
+ const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);
64
+ if (clonedRequest.headers.has('PAYMENT-SIGNATURE') || clonedRequest.headers.has('X-PAYMENT')) {
65
+ throw new Error('Payment already attempted');
66
+ }
67
+ for (const [key, value] of Object.entries(paymentHeaders)) {
68
+ clonedRequest.headers.set(key, value);
69
+ }
70
+ clonedRequest.headers.set('Access-Control-Expose-Headers', 'PAYMENT-RESPONSE,X-PAYMENT-RESPONSE');
71
+ const secondResponse = await fetchImpl(clonedRequest);
72
+ return secondResponse;
73
+ };
74
+ }
6
75
  const NETWORK_TO_CAIP2 = {
7
76
  'solana-mainnet': SOLANA_MAINNET_CAIP2,
8
77
  'solana-devnet': SOLANA_DEVNET_CAIP2,
@@ -88,7 +157,7 @@ export function createSvmBuyerFetch(opts) {
88
157
  });
89
158
  client.register(NETWORK_TO_CAIP2[n], scheme);
90
159
  }
91
- return wrapFetchWithPayment(globalThis.fetch, client);
160
+ return wrapFetchWithMppAwarePayment(globalThis.fetch, client);
92
161
  }
93
162
  export { wrapFetchWithPayment, x402Client, ExactSvmScheme, LeashDelegateExactSvmScheme, LeashExactSvmScheme, };
94
163
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/x402/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE5F,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAOxF,MAAM,gBAAgB,GAAsC;IAC1D,gBAAgB,EAAE,oBAA+B;IACjD,eAAe,EAAE,mBAA8B;IAC/C,gBAAgB,EAAE,oBAA+B;CAClD,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,OAAyB;IACvD,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgC;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,KAAK,KAAK,gBAAgB,IAAI,KAAK,KAAK,eAAe,IAAI,KAAK,KAAK,gBAAgB,EAAE,CAAC;QAC1F,OAAO,KAAK,CAAC;IACf,CAAC;IACD,+DAA+D;IAC/D,IAAI,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAChE,IAAI,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC;QAAE,OAAO,eAAe,CAAC;IAChE,IAAI,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC;QAAE,OAAO,gBAAgB,CAAC;IACjE,OAAO,KAAK,CAAC;AACf,CAAC;AA+BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAiC;IACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAC;IACxF,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IACnD,yEAAyE;IACzE,wEAAwE;IACxE,gEAAgE;IAEhE,MAAM,MAAM,GAAG,cAAc;QAC3B,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,cAAc,CAAC,CAAC;YAC3D,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzF,MAAM,IAAI,KAAK,CACb,0CAA0C,cAAc,mBAAmB,OAAO,IAAI,QAAQ,EAAE,CACjG,CAAC;QACJ,CAAC,CAAC;QACJ,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC;IACrB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,mEAAmE;QACnE,kEAAkE;QAClE,kEAAkE;QAClE,6DAA6D;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB;YACpC,CAAC,CAAC,IAAI,2BAA2B,CAAC;gBAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;gBAC3C,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChD,CAAC;YACJ,CAAC,CAAC,IAAI,mBAAmB,CAAC;gBACtB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChD,CAAC,CAAC;QACP,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,oBAAoB,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,2BAA2B,EAC3B,mBAAmB,GACpB,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/x402/client.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@
12
12
  * type. Don't construct envelope objects ad-hoc; always go through
13
13
  * {@link buildLeashEnvelope}.
14
14
  */
15
- import type { ReceiptV1 } from '@leashmarket/schemas';
15
+ import type { ReceiptAny } from '@leashmarket/schemas';
16
16
  import { type ExplorerProvider } from '../explorer/index.js';
17
17
  import type { TokenNetwork } from '../tokens/index.js';
18
18
  export type LeashPaymentEnvelope = {
@@ -55,11 +55,11 @@ export type BuildLeashEnvelopeOptions = {
55
55
  explorerProvider?: ExplorerProvider;
56
56
  };
57
57
  /**
58
- * Build a {@link LeashPaymentEnvelope} from a settled `earn` `ReceiptV1`.
58
+ * Build a {@link LeashPaymentEnvelope} from a settled `earn` receipt (v0.1 or v0.2).
59
59
  *
60
- * The receipt is treated as the source of truth for `tx_sig`, `agent`,
60
+ * The receipt is treated as the source of truth for settlement signature, `agent`,
61
61
  * `price`, and `facilitator`. Explorer links are derived from `network` so
62
62
  * devnet receipts get the `?cluster=devnet` suffix automatically.
63
63
  */
64
- export declare function buildLeashEnvelope(receipt: ReceiptV1, opts: BuildLeashEnvelopeOptions): LeashPaymentEnvelope;
64
+ export declare function buildLeashEnvelope(receipt: ReceiptAny, opts: BuildLeashEnvelopeOptions): LeashPaymentEnvelope;
65
65
  //# sourceMappingURL=envelope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/x402/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,oBAAoB,GAAG;IACjC,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,iDAAiD;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE;QACR,gEAAgE;QAChE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAClB,4DAA4D;QAC5D,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,EAClB,IAAI,EAAE,yBAAyB,GAC9B,oBAAoB,CAiBtB"}
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/x402/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,oBAAoB,GAAG;IACjC,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,iDAAiD;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE;QACR,gEAAgE;QAChE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAClB,4DAA4D;QAC5D,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAeF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,yBAAyB,GAC9B,oBAAoB,CAkBtB"}
@@ -12,20 +12,34 @@
12
12
  * type. Don't construct envelope objects ad-hoc; always go through
13
13
  * {@link buildLeashEnvelope}.
14
14
  */
15
+ import { isReceiptV02 } from '@leashmarket/schemas';
15
16
  import { agentExplorerUrl, transactionExplorerUrl, } from '../explorer/index.js';
16
17
  import { networkFromCaip2 } from './client.js';
18
+ function settlementTxForEnvelope(receipt) {
19
+ if (isReceiptV02(receipt) && receipt.protocol === 'mpp') {
20
+ const s = receipt.tx_sig ?? receipt.mpp_settlement_tx;
21
+ return s != null && s.length > 0 ? s : null;
22
+ }
23
+ if (isReceiptV02(receipt)) {
24
+ const s = receipt.tx_sig;
25
+ return s != null && s.length > 0 ? s : null;
26
+ }
27
+ const s = receipt.tx_sig;
28
+ return s != null && s.length > 0 ? s : null;
29
+ }
17
30
  /**
18
- * Build a {@link LeashPaymentEnvelope} from a settled `earn` `ReceiptV1`.
31
+ * Build a {@link LeashPaymentEnvelope} from a settled `earn` receipt (v0.1 or v0.2).
19
32
  *
20
- * The receipt is treated as the source of truth for `tx_sig`, `agent`,
33
+ * The receipt is treated as the source of truth for settlement signature, `agent`,
21
34
  * `price`, and `facilitator`. Explorer links are derived from `network` so
22
35
  * devnet receipts get the `?cluster=devnet` suffix automatically.
23
36
  */
24
37
  export function buildLeashEnvelope(receipt, opts) {
25
38
  const network = opts.network ?? deriveTokenNetwork(receipt);
26
39
  const provider = opts.explorerProvider ?? 'solscan';
40
+ const txSig = settlementTxForEnvelope(receipt);
27
41
  return {
28
- tx_sig: receipt.tx_sig ?? null,
42
+ tx_sig: txSig,
29
43
  receipt_hash: receipt.receipt_hash,
30
44
  agent: receipt.agent,
31
45
  network: receipt.price?.network ?? null,
@@ -34,7 +48,7 @@ export function buildLeashEnvelope(receipt, opts) {
34
48
  : null,
35
49
  facilitator: receipt.facilitator ?? null,
36
50
  explorer: {
37
- tx: transactionExplorerUrl(receipt.tx_sig ?? null, { network, provider }),
51
+ tx: transactionExplorerUrl(txSig, { network, provider }),
38
52
  agent: agentAppUrl(opts.origin, receipt.agent, provider, network),
39
53
  },
40
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/x402/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GAEvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAyC/C;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAkB,EAClB,IAA+B;IAE/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,IAAI,SAAS,CAAC;IACpD,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;QAC9B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,IAAI,IAAI;QACvC,MAAM,EAAE,OAAO,CAAC,KAAK;YACnB,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE;YACpE,CAAC,CAAC,IAAI;QACR,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,QAAQ,EAAE;YACR,EAAE,EAAE,sBAAsB,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YACzE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC;SAClE;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,OAAkB;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC;IAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,QAAQ,KAAK,gBAAgB;QAAE,OAAO,SAAS,CAAC;IACpD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAClB,MAAc,EACd,IAAY,EACZ,QAA0B,EAC1B,OAAqB;IAErB,sEAAsE;IACtE,0EAA0E;IAC1E,IAAI,MAAM;QAAE,OAAO,GAAG,MAAM,WAAW,IAAI,EAAE,CAAC;IAC9C,OAAO,gBAAgB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,YAAY,IAAI,EAAE,CAAC;AAC7E,CAAC"}
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/x402/envelope.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@leashmarket/core",
6
- "version": "0.1.0",
6
+ "version": "0.2.1",
7
7
  "private": false,
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "@x402/core": "^2.10.0",
32
32
  "@x402/fetch": "^2.10.0",
33
33
  "@x402/svm": "^2.10.0",
34
- "@leashmarket/schemas": "0.1.0"
34
+ "@leashmarket/schemas": "0.2.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "typescript": "^5.7.2",