@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.
- package/README.md +16 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mpp/client.d.ts +82 -0
- package/dist/mpp/client.d.ts.map +1 -0
- package/dist/mpp/client.js +155 -0
- package/dist/mpp/client.js.map +1 -0
- package/dist/mpp/envelope.d.ts +38 -0
- package/dist/mpp/envelope.d.ts.map +1 -0
- package/dist/mpp/envelope.js +25 -0
- package/dist/mpp/envelope.js.map +1 -0
- package/dist/mpp/headers.d.ts +56 -0
- package/dist/mpp/headers.d.ts.map +1 -0
- package/dist/mpp/headers.js +88 -0
- package/dist/mpp/headers.js.map +1 -0
- package/dist/mpp/index.d.ts +5 -0
- package/dist/mpp/index.d.ts.map +1 -0
- package/dist/mpp/index.js +5 -0
- package/dist/mpp/index.js.map +1 -0
- package/dist/mpp/parse.d.ts +26 -0
- package/dist/mpp/parse.d.ts.map +1 -0
- package/dist/mpp/parse.js +55 -0
- package/dist/mpp/parse.js.map +1 -0
- package/dist/mpp-helpers/base64-json.d.ts +7 -0
- package/dist/mpp-helpers/base64-json.d.ts.map +1 -0
- package/dist/mpp-helpers/base64-json.js +25 -0
- package/dist/mpp-helpers/base64-json.js.map +1 -0
- package/dist/payments/detect.d.ts +55 -0
- package/dist/payments/detect.d.ts.map +1 -0
- package/dist/payments/detect.js +77 -0
- package/dist/payments/detect.js.map +1 -0
- package/dist/payments/index.d.ts +3 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +2 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/receipt/build.d.ts +7 -1
- package/dist/receipt/build.d.ts.map +1 -1
- package/dist/receipt/build.js +6 -0
- package/dist/receipt/build.js.map +1 -1
- package/dist/x402/client.d.ts +8 -0
- package/dist/x402/client.d.ts.map +1 -1
- package/dist/x402/client.js +71 -2
- package/dist/x402/client.js.map +1 -1
- package/dist/x402/envelope.d.ts +4 -4
- package/dist/x402/envelope.d.ts.map +1 -1
- package/dist/x402/envelope.js +18 -4
- package/dist/x402/envelope.js.map +1 -1
- 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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,OAAO,IAAI,SAAS,EAGpB,oCAAoC,EACpC,wBAAwB,EACxB,+BAA+B,EAC/B,0CAA0C,EAC1C,IAAI,EACJ,oCAAoC,EACpC,6BAA6B,EAC7B,2CAA2C,GAC5C,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iCAAiC,EACjC,qCAAqC,GACtC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,6CAA6C,EAC7C,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIlF,OAAO,EAA0C,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAwB,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,0BAA0B,GAAG,OAAO,CAAC;AAC3C,MAAM,wCAAwC,GAAG,MAAM,CAAC;AAkDxD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAA8B;IAC9D,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAa,CACrF,CAAC;IACF,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEnF,OAAO,KAAK,UAAU,QAAQ,CAC5B,KAA6B,EAC7B,IAAkB;QAElB,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1D,IAAI,aAAa,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,aAAa,CAAC;QACvD,mEAAmE;QACnE,iEAAiE;QACjE,IAAI,SAAyB,CAAC;QAC9B,IAAI,CAAC;YACH,SAAS,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CACb,kCAAkC,SAAS,CAAC,OAAO,CAAC,OAAO,mCAAmC,CAC/F,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC;YAC7C,SAAS;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChD,CAAC,CAAC;QACH,MAAM,UAAU,GAAoB;YAClC,CAAC,EAAE,GAAG;YACN,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,QAAQ;SACT,CAAC;QACF,MAAM,UAAU,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAgB;YAC7B,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;YACf,OAAO,EAAE,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC;SAC7D,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACzD,OAAO,2BAA2B,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC9D,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,IAK7C;IACC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACnC,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,CAAC,OAAO,CAAC,OAAgC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7F,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,KAAgB,CAAC,CAAC;IAC3E,MAAM,mBAAmB,GAAG,SAAS,CAAC,cAAc,CAAC;IACrD,IACE,mBAAmB,CAAC,QAAQ,EAAE,KAAK,qBAAqB,CAAC,QAAQ,EAAE;QACnE,mBAAmB,CAAC,QAAQ,EAAE,KAAK,0BAA0B,CAAC,QAAQ,EAAE,EACxE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,MAAM;YACJ,OAAO,IAAI,CAAC,kBAAkB,KAAK,QAAQ;gBACzC,CAAC,CAAE,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAa;gBACjD,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,sBAAsB,CAAC;YAC9C,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,KAAgB;YACxC,KAAK,EAAE,MAAM,CAAC,OAAO;YACrB,YAAY,EAAE,mBAAmB;SAClC,CAAC,CAAC;QACH,MAAM,GAAG,QAAQ,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,sBAAsB,CAAC;QACpD,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,KAAgB;QACxC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,SAAoB;QAC7C,YAAY,EAAE,mBAAmB;KAClC,CAAC,CAAC;IAEH,MAAM,eAAe,GAAY,SAAS,CAAC,OAAO,CAAC,QAAQ;QACzD,CAAC,CAAE,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAa;QACpD,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IACnB,MAAM,cAAc,GAAG,eAAuD,CAAC;IAE/E,MAAM,oBAAoB,GAAG,6CAA6C,CAAC;QACzE,KAAK,EAAE,cAAc;QACrB,GAAG,EAAE,cAAc;QACnB,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,SAAoB;QAC7C,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,KAAgB;QACxC,YAAY,EAAE,mBAAmB;KAClC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,6BAA6B,CAC9C;QACE,MAAM;QACN,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,KAAgB;QACxC,WAAW,EAAE,cAAc;QAC3B,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QACxC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,QAAQ;KAClC,EACD,EAAE,cAAc,EAAE,mBAAmB,EAAE,CACxC,CAAC;IAEF,mEAAmE;IACnE,sEAAsE;IACtE,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3E,IAAI,SAAS,CAAC,UAAU,GAAG,cAAc,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,yCAAyC,cAAc,QAAQ,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,MAAM,GAAG;QACb,cAAc,EAAE,oBAA+B;QAC/C,QAAQ,EAAE,EAAW;QACrB,IAAI,EAAE,SAAS;KAChB,CAAC;IAEF,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,GAAG,CAAC,kBAAkB,EAAE,CAAC,IAAI,EAAE,CAAC;IAEzE,MAAM,EAAE,GAAG,IAAI,CACb,wBAAwB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EACxC,CAAC,CAAC,EAAE,EAAE,CAAC,qCAAqC,CAAC,wCAAwC,EAAE,CAAC,CAAC,EACzF,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,CAAC,eAAe,EAAE,CAAC,CAAC,EACxD,CAAC,CAAC,EAAE,EAAE,CACJ,oCAAoC,CAClC,iCAAiC,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,EACxE,CAAC,CACF,EACH,CAAC,CAAC,EAAE,EAAE,CAAC,oCAAoC,CAAC,CAAC,oBAAoB,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAC1F,CAAC,CAAC,EAAE,EAAE,CAAC,2CAA2C,CAAC,eAAe,EAAE,CAAC,CAAC,CACvE,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,0CAA0C,CAAC,EAAE,CAAC,CAAC;IACpE,OAAO,+BAA+B,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,wBAAwB,CAAC,QAAgC,EAAE,SAAiB;IACnF,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAqC,CAAC,CAAC;IAC5E,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAClC,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,SAAS,2BAA2B,CAAC,QAAkB,EAAE,eAAuB;IAC9E,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/receipt/build.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ReceiptV1 } from '@leashmarket/schemas';
|
|
2
2
|
export type ReceiptDraft = Omit<ReceiptV1, 'receipt_hash'>;
|
|
3
|
-
|
|
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,
|
|
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"}
|
package/dist/receipt/build.js
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/x402/client.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/x402/client.js
CHANGED
|
@@ -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
|
|
160
|
+
return wrapFetchWithMppAwarePayment(globalThis.fetch, client);
|
|
92
161
|
}
|
|
93
162
|
export { wrapFetchWithPayment, x402Client, ExactSvmScheme, LeashDelegateExactSvmScheme, LeashExactSvmScheme, };
|
|
94
163
|
//# sourceMappingURL=client.js.map
|
package/dist/x402/client.js.map
CHANGED
|
@@ -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/
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/x402/client.ts"],"names":[],"mappings":"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"}
|
package/dist/x402/envelope.d.ts
CHANGED
|
@@ -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 {
|
|
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`
|
|
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
|
|
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:
|
|
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,
|
|
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"}
|
package/dist/x402/envelope.js
CHANGED
|
@@ -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`
|
|
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
|
|
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:
|
|
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(
|
|
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,
|
|
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
|
|
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
|
|
34
|
+
"@leashmarket/schemas": "0.2.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"typescript": "^5.7.2",
|