@leashmarket/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/agent/agent.d.ts +8 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +14 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/treasury-pda.d.ts +49 -0
- package/dist/agent/treasury-pda.d.ts.map +1 -0
- package/dist/agent/treasury-pda.js +55 -0
- package/dist/agent/treasury-pda.js.map +1 -0
- package/dist/explorer/index.d.ts +55 -0
- package/dist/explorer/index.d.ts.map +1 -0
- package/dist/explorer/index.js +95 -0
- package/dist/explorer/index.js.map +1 -0
- package/dist/fees/leash-fee.d.ts +248 -0
- package/dist/fees/leash-fee.d.ts.map +1 -0
- package/dist/fees/leash-fee.js +246 -0
- package/dist/fees/leash-fee.js.map +1 -0
- package/dist/format/index.d.ts +55 -0
- package/dist/format/index.d.ts.map +1 -0
- package/dist/format/index.js +130 -0
- package/dist/format/index.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/evaluate.d.ts +17 -0
- package/dist/policy/evaluate.d.ts.map +1 -0
- package/dist/policy/evaluate.js +46 -0
- package/dist/policy/evaluate.js.map +1 -0
- package/dist/policy/state.d.ts +8 -0
- package/dist/policy/state.d.ts.map +1 -0
- package/dist/policy/state.js +2 -0
- package/dist/policy/state.js.map +1 -0
- package/dist/receipt/build.d.ts +5 -0
- package/dist/receipt/build.d.ts.map +1 -0
- package/dist/receipt/build.js +9 -0
- package/dist/receipt/build.js.map +1 -0
- package/dist/receipt/hash.d.ts +15 -0
- package/dist/receipt/hash.d.ts.map +1 -0
- package/dist/receipt/hash.js +40 -0
- package/dist/receipt/hash.js.map +1 -0
- package/dist/receipt/verify.d.ts +10 -0
- package/dist/receipt/verify.d.ts.map +1 -0
- package/dist/receipt/verify.js +36 -0
- package/dist/receipt/verify.js.map +1 -0
- package/dist/tokens/index.d.ts +86 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +163 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/treasury/balance.d.ts +3 -0
- package/dist/treasury/balance.d.ts.map +1 -0
- package/dist/treasury/balance.js +13 -0
- package/dist/treasury/balance.js.map +1 -0
- package/dist/treasury/inspect-token-account.d.ts +46 -0
- package/dist/treasury/inspect-token-account.d.ts.map +1 -0
- package/dist/treasury/inspect-token-account.js +67 -0
- package/dist/treasury/inspect-token-account.js.map +1 -0
- package/dist/treasury/list-balances.d.ts +57 -0
- package/dist/treasury/list-balances.d.ts.map +1 -0
- package/dist/treasury/list-balances.js +115 -0
- package/dist/treasury/list-balances.js.map +1 -0
- package/dist/treasury/pause.d.ts +32 -0
- package/dist/treasury/pause.d.ts.map +1 -0
- package/dist/treasury/pause.js +40 -0
- package/dist/treasury/pause.js.map +1 -0
- package/dist/treasury/withdraw.d.ts +13 -0
- package/dist/treasury/withdraw.d.ts.map +1 -0
- package/dist/treasury/withdraw.js +4 -0
- package/dist/treasury/withdraw.js.map +1 -0
- package/dist/wallet/index.d.ts +3 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +2 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/x402/client.d.ts +72 -0
- package/dist/x402/client.d.ts.map +1 -0
- package/dist/x402/client.js +94 -0
- package/dist/x402/client.js.map +1 -0
- package/dist/x402/delegate-scheme.d.ts +107 -0
- package/dist/x402/delegate-scheme.d.ts.map +1 -0
- package/dist/x402/delegate-scheme.js +268 -0
- package/dist/x402/delegate-scheme.js.map +1 -0
- package/dist/x402/discovery.d.ts +110 -0
- package/dist/x402/discovery.d.ts.map +1 -0
- package/dist/x402/discovery.js +213 -0
- package/dist/x402/discovery.js.map +1 -0
- package/dist/x402/envelope.d.ts +65 -0
- package/dist/x402/envelope.d.ts.map +1 -0
- package/dist/x402/envelope.js +67 -0
- package/dist/x402/envelope.js.map +1 -0
- package/dist/x402/facilitator.d.ts +45 -0
- package/dist/x402/facilitator.d.ts.map +1 -0
- package/dist/x402/facilitator.js +61 -0
- package/dist/x402/facilitator.js.map +1 -0
- package/dist/x402/headers.d.ts +51 -0
- package/dist/x402/headers.d.ts.map +1 -0
- package/dist/x402/headers.js +84 -0
- package/dist/x402/headers.js.map +1 -0
- package/dist/x402/parse.d.ts +20 -0
- package/dist/x402/parse.d.ts.map +1 -0
- package/dist/x402/parse.js +31 -0
- package/dist/x402/parse.js.map +1 -0
- package/dist/x402/webhook.d.ts +48 -0
- package/dist/x402/webhook.d.ts.map +1 -0
- package/dist/x402/webhook.js +88 -0
- package/dist/x402/webhook.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Leash payment envelope.
|
|
3
|
+
*
|
|
4
|
+
* After a successful x402 settlement the seller's `/x/<id>` route attaches a
|
|
5
|
+
* compact summary of the payment to the response — both as `X-Leash-*`
|
|
6
|
+
* response headers and (optionally) as a JSON `_leash` field via
|
|
7
|
+
* `wrap_receipt`. That summary is also the body of every webhook delivered
|
|
8
|
+
* to the configured `webhook_url`.
|
|
9
|
+
*
|
|
10
|
+
* Putting the shape + builder in `@leashmarket/core` means producers (the seller
|
|
11
|
+
* route) and consumers (buyer-kit, downstream agents) share one TypeScript
|
|
12
|
+
* type. Don't construct envelope objects ad-hoc; always go through
|
|
13
|
+
* {@link buildLeashEnvelope}.
|
|
14
|
+
*/
|
|
15
|
+
import type { ReceiptV1 } from '@leashmarket/schemas';
|
|
16
|
+
import { type ExplorerProvider } from '../explorer/index.js';
|
|
17
|
+
import type { TokenNetwork } from '../tokens/index.js';
|
|
18
|
+
export type LeashPaymentEnvelope = {
|
|
19
|
+
/** Settled SPL transaction signature (null if no settlement happened). */
|
|
20
|
+
tx_sig: string | null;
|
|
21
|
+
/** SHA-256 of the canonical receipt — useful as an idempotency key. */
|
|
22
|
+
receipt_hash: string;
|
|
23
|
+
/** Mint address of the agent that earned the payment. */
|
|
24
|
+
agent: string;
|
|
25
|
+
/** Friendly slug like `solana-devnet`. May be `null` for legacy receipts. */
|
|
26
|
+
network: string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Atomic `amount` + display `currency`. Decode against
|
|
29
|
+
* {@link KNOWN_TOKENS} via `formatTokenBalance` to render decimals.
|
|
30
|
+
*/
|
|
31
|
+
amount: {
|
|
32
|
+
amount: string;
|
|
33
|
+
currency: string;
|
|
34
|
+
} | null;
|
|
35
|
+
/** Facilitator URL that settled the transfer. */
|
|
36
|
+
facilitator: string | null;
|
|
37
|
+
explorer: {
|
|
38
|
+
/** Explorer URL for the SPL transfer (null if no signature). */
|
|
39
|
+
tx: string | null;
|
|
40
|
+
/** Explorer URL for the agent / app surfacing the agent. */
|
|
41
|
+
agent: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export type BuildLeashEnvelopeOptions = {
|
|
45
|
+
/** Web origin used to build the `explorer.agent` link. */
|
|
46
|
+
origin: string;
|
|
47
|
+
/**
|
|
48
|
+
* Used to derive the `?cluster=` query for the on-chain explorer link.
|
|
49
|
+
* Leash maps `solana-testnet` → `devnet` here because v0.1 has no testnet
|
|
50
|
+
* facilitator; consumers can override by passing `'mainnet'` or `'devnet'`
|
|
51
|
+
* explicitly.
|
|
52
|
+
*/
|
|
53
|
+
network?: TokenNetwork;
|
|
54
|
+
/** Explorer provider for the `tx` link. Defaults to Solscan. */
|
|
55
|
+
explorerProvider?: ExplorerProvider;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Build a {@link LeashPaymentEnvelope} from a settled `earn` `ReceiptV1`.
|
|
59
|
+
*
|
|
60
|
+
* The receipt is treated as the source of truth for `tx_sig`, `agent`,
|
|
61
|
+
* `price`, and `facilitator`. Explorer links are derived from `network` so
|
|
62
|
+
* devnet receipts get the `?cluster=devnet` suffix automatically.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildLeashEnvelope(receipt: ReceiptV1, opts: BuildLeashEnvelopeOptions): LeashPaymentEnvelope;
|
|
65
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Leash payment envelope.
|
|
3
|
+
*
|
|
4
|
+
* After a successful x402 settlement the seller's `/x/<id>` route attaches a
|
|
5
|
+
* compact summary of the payment to the response — both as `X-Leash-*`
|
|
6
|
+
* response headers and (optionally) as a JSON `_leash` field via
|
|
7
|
+
* `wrap_receipt`. That summary is also the body of every webhook delivered
|
|
8
|
+
* to the configured `webhook_url`.
|
|
9
|
+
*
|
|
10
|
+
* Putting the shape + builder in `@leashmarket/core` means producers (the seller
|
|
11
|
+
* route) and consumers (buyer-kit, downstream agents) share one TypeScript
|
|
12
|
+
* type. Don't construct envelope objects ad-hoc; always go through
|
|
13
|
+
* {@link buildLeashEnvelope}.
|
|
14
|
+
*/
|
|
15
|
+
import { agentExplorerUrl, transactionExplorerUrl, } from '../explorer/index.js';
|
|
16
|
+
import { networkFromCaip2 } from './client.js';
|
|
17
|
+
/**
|
|
18
|
+
* Build a {@link LeashPaymentEnvelope} from a settled `earn` `ReceiptV1`.
|
|
19
|
+
*
|
|
20
|
+
* The receipt is treated as the source of truth for `tx_sig`, `agent`,
|
|
21
|
+
* `price`, and `facilitator`. Explorer links are derived from `network` so
|
|
22
|
+
* devnet receipts get the `?cluster=devnet` suffix automatically.
|
|
23
|
+
*/
|
|
24
|
+
export function buildLeashEnvelope(receipt, opts) {
|
|
25
|
+
const network = opts.network ?? deriveTokenNetwork(receipt);
|
|
26
|
+
const provider = opts.explorerProvider ?? 'solscan';
|
|
27
|
+
return {
|
|
28
|
+
tx_sig: receipt.tx_sig ?? null,
|
|
29
|
+
receipt_hash: receipt.receipt_hash,
|
|
30
|
+
agent: receipt.agent,
|
|
31
|
+
network: receipt.price?.network ?? null,
|
|
32
|
+
amount: receipt.price
|
|
33
|
+
? { amount: receipt.price.amount, currency: receipt.price.currency }
|
|
34
|
+
: null,
|
|
35
|
+
facilitator: receipt.facilitator ?? null,
|
|
36
|
+
explorer: {
|
|
37
|
+
tx: transactionExplorerUrl(receipt.tx_sig ?? null, { network, provider }),
|
|
38
|
+
agent: agentAppUrl(opts.origin, receipt.agent, provider, network),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Derive a friendly `TokenNetwork` from a receipt's `price.network`. Returns
|
|
44
|
+
* `'devnet'` as a safe default when the receipt is missing network info —
|
|
45
|
+
* matches the Leash playground's primary cluster.
|
|
46
|
+
*/
|
|
47
|
+
function deriveTokenNetwork(receipt) {
|
|
48
|
+
const slug = receipt.price?.network ?? null;
|
|
49
|
+
const friendly = networkFromCaip2(slug);
|
|
50
|
+
if (friendly === 'solana-mainnet')
|
|
51
|
+
return 'mainnet';
|
|
52
|
+
return 'devnet';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build the in-app agent profile URL. We always link to the *app* (not raw
|
|
56
|
+
* Solscan) for the agent because the Leash agent profile is the richer view
|
|
57
|
+
* (treasury + receipts + delegation). Solscan-only callers can derive the
|
|
58
|
+
* raw chain explorer URL via {@link agentExplorerUrl}.
|
|
59
|
+
*/
|
|
60
|
+
function agentAppUrl(origin, mint, provider, network) {
|
|
61
|
+
// Origin form is preferred for anything served by a Leash deployment;
|
|
62
|
+
// `agentExplorerUrl` is the chain-explorer fallback for off-app contexts.
|
|
63
|
+
if (origin)
|
|
64
|
+
return `${origin}/agents/${mint}`;
|
|
65
|
+
return agentExplorerUrl(mint, { provider, network }) ?? `solana://${mint}`;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default x402 facilitator URLs for the networks Leash currently supports.
|
|
3
|
+
*
|
|
4
|
+
* The buyer never talks to the facilitator directly (the seller does), but
|
|
5
|
+
* we record the URL on every receipt so explorers can independently
|
|
6
|
+
* re-verify settlement. Centralising the defaults here keeps buyer-kit and
|
|
7
|
+
* seller-kit honest — they both fall back to the same value, and an
|
|
8
|
+
* environment-level override (`LEASH_FACILITATOR_URL`) flows through the
|
|
9
|
+
* stack uniformly.
|
|
10
|
+
*
|
|
11
|
+
* Defaults (as of April 2026):
|
|
12
|
+
*
|
|
13
|
+
* - **Solana devnet** → `https://devnet-facilitator.leash.market`
|
|
14
|
+
* Leash-operated `@leashmarket/facilitator` instance. Gas-sponsored, supports
|
|
15
|
+
* the `exact` SVM scheme (x402 v1 + v2), Token-2022, and the Leash
|
|
16
|
+
* 1% protocol fee leg. The facilitator auto-provisions destination ATAs
|
|
17
|
+
* (seller payTo + fee vault) so first-time USDG/USDT settlements work
|
|
18
|
+
* without manual ATA setup.
|
|
19
|
+
*
|
|
20
|
+
* - **Solana mainnet** → `https://facilitator.leash.market`
|
|
21
|
+
* Leash-operated mainnet instance. Same wire contract as devnet.
|
|
22
|
+
*
|
|
23
|
+
* To override: set `LEASH_FACILITATOR_URL` in the buyer/seller process, or
|
|
24
|
+
* pass `facilitator: '…'` directly to `createBuyer` / `createSeller`.
|
|
25
|
+
*/
|
|
26
|
+
import type { LeashX402Network } from './client.js';
|
|
27
|
+
export declare const DEFAULT_FACILITATORS: Partial<Record<LeashX402Network, string>>;
|
|
28
|
+
/** Canonical Leash devnet facilitator URL. */
|
|
29
|
+
export declare const LEASH_FACILITATOR_URL = "https://devnet-facilitator.leash.market";
|
|
30
|
+
/** Universal fallback when nothing else resolves. */
|
|
31
|
+
export declare const FALLBACK_FACILITATOR_URL = "https://devnet-facilitator.leash.market";
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the facilitator URL Leash should default to.
|
|
34
|
+
*
|
|
35
|
+
* Resolution order:
|
|
36
|
+
*
|
|
37
|
+
* 1. `process.env.LEASH_FACILITATOR_URL` if set (works everywhere `process`
|
|
38
|
+
* exists; safely no-ops in browser bundles where `process` is shimmed
|
|
39
|
+
* out by Webpack/Next).
|
|
40
|
+
* 2. The first network's hosted default in {@link DEFAULT_FACILITATORS}.
|
|
41
|
+
* 3. {@link FALLBACK_FACILITATOR_URL} (svmacc devnet) — keeps the API total
|
|
42
|
+
* so callers never have to handle "no default".
|
|
43
|
+
*/
|
|
44
|
+
export declare function defaultFacilitatorFor(networks: ReadonlyArray<LeashX402Network> | LeashX402Network | undefined): string;
|
|
45
|
+
//# sourceMappingURL=facilitator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../src/x402/facilitator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,oBAAoB,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAG1E,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,qBAAqB,4CAA4C,CAAC;AAE/E,qDAAqD;AACrD,eAAO,MAAM,wBAAwB,4CAA4C,CAAC;AAElF;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,GAAG,SAAS,GACvE,MAAM,CAcR"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default x402 facilitator URLs for the networks Leash currently supports.
|
|
3
|
+
*
|
|
4
|
+
* The buyer never talks to the facilitator directly (the seller does), but
|
|
5
|
+
* we record the URL on every receipt so explorers can independently
|
|
6
|
+
* re-verify settlement. Centralising the defaults here keeps buyer-kit and
|
|
7
|
+
* seller-kit honest — they both fall back to the same value, and an
|
|
8
|
+
* environment-level override (`LEASH_FACILITATOR_URL`) flows through the
|
|
9
|
+
* stack uniformly.
|
|
10
|
+
*
|
|
11
|
+
* Defaults (as of April 2026):
|
|
12
|
+
*
|
|
13
|
+
* - **Solana devnet** → `https://devnet-facilitator.leash.market`
|
|
14
|
+
* Leash-operated `@leashmarket/facilitator` instance. Gas-sponsored, supports
|
|
15
|
+
* the `exact` SVM scheme (x402 v1 + v2), Token-2022, and the Leash
|
|
16
|
+
* 1% protocol fee leg. The facilitator auto-provisions destination ATAs
|
|
17
|
+
* (seller payTo + fee vault) so first-time USDG/USDT settlements work
|
|
18
|
+
* without manual ATA setup.
|
|
19
|
+
*
|
|
20
|
+
* - **Solana mainnet** → `https://facilitator.leash.market`
|
|
21
|
+
* Leash-operated mainnet instance. Same wire contract as devnet.
|
|
22
|
+
*
|
|
23
|
+
* To override: set `LEASH_FACILITATOR_URL` in the buyer/seller process, or
|
|
24
|
+
* pass `facilitator: '…'` directly to `createBuyer` / `createSeller`.
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_FACILITATORS = {
|
|
27
|
+
'solana-devnet': 'https://devnet-facilitator.leash.market',
|
|
28
|
+
'solana-mainnet': 'https://facilitator.leash.market',
|
|
29
|
+
};
|
|
30
|
+
/** Canonical Leash devnet facilitator URL. */
|
|
31
|
+
export const LEASH_FACILITATOR_URL = 'https://devnet-facilitator.leash.market';
|
|
32
|
+
/** Universal fallback when nothing else resolves. */
|
|
33
|
+
export const FALLBACK_FACILITATOR_URL = 'https://devnet-facilitator.leash.market';
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the facilitator URL Leash should default to.
|
|
36
|
+
*
|
|
37
|
+
* Resolution order:
|
|
38
|
+
*
|
|
39
|
+
* 1. `process.env.LEASH_FACILITATOR_URL` if set (works everywhere `process`
|
|
40
|
+
* exists; safely no-ops in browser bundles where `process` is shimmed
|
|
41
|
+
* out by Webpack/Next).
|
|
42
|
+
* 2. The first network's hosted default in {@link DEFAULT_FACILITATORS}.
|
|
43
|
+
* 3. {@link FALLBACK_FACILITATOR_URL} (svmacc devnet) — keeps the API total
|
|
44
|
+
* so callers never have to handle "no default".
|
|
45
|
+
*/
|
|
46
|
+
export function defaultFacilitatorFor(networks) {
|
|
47
|
+
const envOverride = typeof process !== 'undefined' && process.env?.LEASH_FACILITATOR_URL
|
|
48
|
+
? process.env.LEASH_FACILITATOR_URL
|
|
49
|
+
: null;
|
|
50
|
+
if (envOverride)
|
|
51
|
+
return envOverride;
|
|
52
|
+
const arr = networks == null ? [] : Array.isArray(networks) ? networks : [networks];
|
|
53
|
+
const first = arr[0];
|
|
54
|
+
if (first) {
|
|
55
|
+
const url = DEFAULT_FACILITATORS[first];
|
|
56
|
+
if (url)
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
return FALLBACK_FACILITATOR_URL;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=facilitator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.js","sourceRoot":"","sources":["../../src/x402/facilitator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAA8C;IAC7E,eAAe,EAAE,yCAAyC;IAC1D,gBAAgB,EAAE,kCAAkC;CACrD,CAAC;AAEF,8CAA8C;AAC9C,MAAM,CAAC,MAAM,qBAAqB,GAAG,yCAAyC,CAAC;AAE/E,qDAAqD;AACrD,MAAM,CAAC,MAAM,wBAAwB,GAAG,yCAAyC,CAAC;AAElF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAwE;IAExE,MAAM,WAAW,GACf,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,qBAAqB;QAClE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB;QACnC,CAAC,CAAC,IAAI,CAAC;IACX,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IACpC,MAAM,GAAG,GACP,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAA4B,CAAC,CAAC;IAC9F,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACrB,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,GAAG,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;IACtB,CAAC;IACD,OAAO,wBAAwB,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `X-Leash-*` HTTP header names and helpers.
|
|
3
|
+
*
|
|
4
|
+
* Sellers stamp these headers onto every successfully-settled response so
|
|
5
|
+
* buyers (and proxies/observers) can read the payment envelope without
|
|
6
|
+
* parsing the response body. Keep the names lowercase here — Hono / Next.js
|
|
7
|
+
* normalise to lowercase, and the underlying x402 wire uses lowercase too.
|
|
8
|
+
*
|
|
9
|
+
* The set is exported as a single readonly map so consumers can:
|
|
10
|
+
* - reference the canonical name (`LEASH_HEADERS.txSig`)
|
|
11
|
+
* - generate the `Access-Control-Expose-Headers` value
|
|
12
|
+
* - parse without misspelling header names
|
|
13
|
+
*/
|
|
14
|
+
import type { LeashPaymentEnvelope } from './envelope.js';
|
|
15
|
+
export declare const LEASH_HEADERS: {
|
|
16
|
+
readonly txSig: "x-leash-tx-sig";
|
|
17
|
+
readonly receiptHash: "x-leash-receipt-hash";
|
|
18
|
+
readonly agent: "x-leash-agent";
|
|
19
|
+
readonly txExplorer: "x-leash-tx-explorer";
|
|
20
|
+
readonly agentExplorer: "x-leash-agent-explorer";
|
|
21
|
+
};
|
|
22
|
+
export type LeashHeaderName = (typeof LEASH_HEADERS)[keyof typeof LEASH_HEADERS];
|
|
23
|
+
/** All `X-Leash-*` headers as a single comma-separated list. */
|
|
24
|
+
export declare const LEASH_HEADERS_EXPOSE: string;
|
|
25
|
+
/**
|
|
26
|
+
* Header buyers (or middleware) can include on a request to opt into a
|
|
27
|
+
* per-call webhook callback. The seller `/x/<id>` route fires this URL in
|
|
28
|
+
* addition to the seller-configured `webhook_url`.
|
|
29
|
+
*/
|
|
30
|
+
export declare const LEASH_CALLBACK_HEADER = "x-leash-callback";
|
|
31
|
+
/**
|
|
32
|
+
* Mutate a `Headers` instance in place with the canonical `X-Leash-*` set
|
|
33
|
+
* for a settled payment. Also appends to `Access-Control-Expose-Headers`
|
|
34
|
+
* so cross-origin browser callers can read the values via `fetch`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildLeashHeaders(envelope: LeashPaymentEnvelope, headers: Headers): Headers;
|
|
37
|
+
/** Result of {@link parseLeashHeaders} — narrow read of the wire envelope. */
|
|
38
|
+
export type ParsedLeashHeaders = {
|
|
39
|
+
txSig: string | null;
|
|
40
|
+
receiptHash: string | null;
|
|
41
|
+
agent: string | null;
|
|
42
|
+
txExplorer: string | null;
|
|
43
|
+
agentExplorer: string | null;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Read the `X-Leash-*` set off a `Response` (or any `Headers`-like). Empty
|
|
47
|
+
* string values are normalised to `null` (the producer always emits all
|
|
48
|
+
* keys, but uses empty strings when a settled tx_sig is missing).
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseLeashHeaders(input: Headers | Response): ParsedLeashHeaders;
|
|
51
|
+
//# sourceMappingURL=headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/x402/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAEjF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,QAA0C,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ3F;AAED,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,kBAAkB,CAS/E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `X-Leash-*` HTTP header names and helpers.
|
|
3
|
+
*
|
|
4
|
+
* Sellers stamp these headers onto every successfully-settled response so
|
|
5
|
+
* buyers (and proxies/observers) can read the payment envelope without
|
|
6
|
+
* parsing the response body. Keep the names lowercase here — Hono / Next.js
|
|
7
|
+
* normalise to lowercase, and the underlying x402 wire uses lowercase too.
|
|
8
|
+
*
|
|
9
|
+
* The set is exported as a single readonly map so consumers can:
|
|
10
|
+
* - reference the canonical name (`LEASH_HEADERS.txSig`)
|
|
11
|
+
* - generate the `Access-Control-Expose-Headers` value
|
|
12
|
+
* - parse without misspelling header names
|
|
13
|
+
*/
|
|
14
|
+
export const LEASH_HEADERS = {
|
|
15
|
+
txSig: 'x-leash-tx-sig',
|
|
16
|
+
receiptHash: 'x-leash-receipt-hash',
|
|
17
|
+
agent: 'x-leash-agent',
|
|
18
|
+
txExplorer: 'x-leash-tx-explorer',
|
|
19
|
+
agentExplorer: 'x-leash-agent-explorer',
|
|
20
|
+
};
|
|
21
|
+
/** All `X-Leash-*` headers as a single comma-separated list. */
|
|
22
|
+
export const LEASH_HEADERS_EXPOSE = Object.values(LEASH_HEADERS).join(', ');
|
|
23
|
+
/**
|
|
24
|
+
* Header buyers (or middleware) can include on a request to opt into a
|
|
25
|
+
* per-call webhook callback. The seller `/x/<id>` route fires this URL in
|
|
26
|
+
* addition to the seller-configured `webhook_url`.
|
|
27
|
+
*/
|
|
28
|
+
export const LEASH_CALLBACK_HEADER = 'x-leash-callback';
|
|
29
|
+
/**
|
|
30
|
+
* Mutate a `Headers` instance in place with the canonical `X-Leash-*` set
|
|
31
|
+
* for a settled payment. Also appends to `Access-Control-Expose-Headers`
|
|
32
|
+
* so cross-origin browser callers can read the values via `fetch`.
|
|
33
|
+
*/
|
|
34
|
+
export function buildLeashHeaders(envelope, headers) {
|
|
35
|
+
headers.set(LEASH_HEADERS.txSig, envelope.tx_sig ?? '');
|
|
36
|
+
headers.set(LEASH_HEADERS.receiptHash, envelope.receipt_hash);
|
|
37
|
+
headers.set(LEASH_HEADERS.agent, envelope.agent);
|
|
38
|
+
if (envelope.explorer.tx)
|
|
39
|
+
headers.set(LEASH_HEADERS.txExplorer, envelope.explorer.tx);
|
|
40
|
+
headers.set(LEASH_HEADERS.agentExplorer, envelope.explorer.agent);
|
|
41
|
+
appendExposeHeaders(headers, LEASH_HEADERS_EXPOSE);
|
|
42
|
+
return headers;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Read the `X-Leash-*` set off a `Response` (or any `Headers`-like). Empty
|
|
46
|
+
* string values are normalised to `null` (the producer always emits all
|
|
47
|
+
* keys, but uses empty strings when a settled tx_sig is missing).
|
|
48
|
+
*/
|
|
49
|
+
export function parseLeashHeaders(input) {
|
|
50
|
+
const h = input instanceof Response ? input.headers : input;
|
|
51
|
+
return {
|
|
52
|
+
txSig: nonEmpty(h.get(LEASH_HEADERS.txSig)),
|
|
53
|
+
receiptHash: nonEmpty(h.get(LEASH_HEADERS.receiptHash)),
|
|
54
|
+
agent: nonEmpty(h.get(LEASH_HEADERS.agent)),
|
|
55
|
+
txExplorer: nonEmpty(h.get(LEASH_HEADERS.txExplorer)),
|
|
56
|
+
agentExplorer: nonEmpty(h.get(LEASH_HEADERS.agentExplorer)),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function nonEmpty(s) {
|
|
60
|
+
if (s == null)
|
|
61
|
+
return null;
|
|
62
|
+
return s.length > 0 ? s : null;
|
|
63
|
+
}
|
|
64
|
+
function appendExposeHeaders(headers, value) {
|
|
65
|
+
const existing = headers.get('access-control-expose-headers');
|
|
66
|
+
if (!existing) {
|
|
67
|
+
headers.set('access-control-expose-headers', value);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Avoid duplicating entries on repeated calls.
|
|
71
|
+
const seen = new Set(existing.split(',').map((s) => s.trim().toLowerCase()));
|
|
72
|
+
const additions = value.split(',').map((s) => s.trim());
|
|
73
|
+
let dirty = false;
|
|
74
|
+
for (const a of additions) {
|
|
75
|
+
if (!seen.has(a.toLowerCase())) {
|
|
76
|
+
seen.add(a.toLowerCase());
|
|
77
|
+
dirty = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (dirty) {
|
|
81
|
+
headers.set('access-control-expose-headers', [...seen].join(', '));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.js","sourceRoot":"","sources":["../../src/x402/headers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports of x402 protocol types so consumers don't have to depend on
|
|
3
|
+
* `@x402/core` directly. The actual parsing of `paymentRequirements` lives
|
|
4
|
+
* inside `@x402/fetch`'s `wrapFetchWithPayment` (buyer) and `@x402/hono`'s
|
|
5
|
+
* `paymentMiddleware` (seller); we keep this module purely as a typed surface.
|
|
6
|
+
*/
|
|
7
|
+
export type { Network, PaymentPayload, PaymentRequired, PaymentRequirements, } from '@x402/core/types';
|
|
8
|
+
export { decodePaymentResponseHeader } from '@x402/core/http';
|
|
9
|
+
import type { PaymentRequirements } from '@x402/core/types';
|
|
10
|
+
/**
|
|
11
|
+
* SHA-256 (hex) of the canonical JSON form of a `PaymentRequirements` object.
|
|
12
|
+
* Used as the `payment_requirements_hash` field on `ReceiptV1` so a `spend`
|
|
13
|
+
* receipt is cryptographically tied to the offer it paid against.
|
|
14
|
+
*
|
|
15
|
+
* Keys are sorted lexicographically before hashing to make the digest stable
|
|
16
|
+
* across producers. Returns `null` for null/undefined input so callers can
|
|
17
|
+
* pass `requirements ?? null` without branching.
|
|
18
|
+
*/
|
|
19
|
+
export declare function paymentRequirementsHash(requirements: PaymentRequirements | null | undefined): string | null;
|
|
20
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/x402/parse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,YAAY,EACV,OAAO,EACP,cAAc,EACd,eAAe,EACf,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAI9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,GACnD,MAAM,GAAG,IAAI,CAIf"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { decodePaymentResponseHeader } from '@x402/core/http';
|
|
2
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
3
|
+
import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils';
|
|
4
|
+
/**
|
|
5
|
+
* SHA-256 (hex) of the canonical JSON form of a `PaymentRequirements` object.
|
|
6
|
+
* Used as the `payment_requirements_hash` field on `ReceiptV1` so a `spend`
|
|
7
|
+
* receipt is cryptographically tied to the offer it paid against.
|
|
8
|
+
*
|
|
9
|
+
* Keys are sorted lexicographically before hashing to make the digest stable
|
|
10
|
+
* across producers. Returns `null` for null/undefined input so callers can
|
|
11
|
+
* pass `requirements ?? null` without branching.
|
|
12
|
+
*/
|
|
13
|
+
export function paymentRequirementsHash(requirements) {
|
|
14
|
+
if (requirements == null)
|
|
15
|
+
return null;
|
|
16
|
+
const canonical = canonicalize(requirements);
|
|
17
|
+
return bytesToHex(sha256(utf8ToBytes(canonical)));
|
|
18
|
+
}
|
|
19
|
+
function canonicalize(value) {
|
|
20
|
+
if (value === null || value === undefined)
|
|
21
|
+
return 'null';
|
|
22
|
+
if (typeof value !== 'object')
|
|
23
|
+
return JSON.stringify(value);
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return `[${value.map((v) => canonicalize(v)).join(',')}]`;
|
|
26
|
+
}
|
|
27
|
+
const obj = value;
|
|
28
|
+
const keys = Object.keys(obj).sort();
|
|
29
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`).join(',')}}`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/x402/parse.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAG9D;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,YAAoD;IAEpD,IAAI,YAAY,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,SAAS,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAC7C,OAAO,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACzD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC5D,CAAC;IACD,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leash webhook payload contract.
|
|
3
|
+
*
|
|
4
|
+
* After a successful payment the seller `/x/<id>` route POSTs a JSON body
|
|
5
|
+
* shaped like {@link WebhookPayload} to:
|
|
6
|
+
* - the seller-configured `endpoint.webhook_url` (set when the link was
|
|
7
|
+
* created), and
|
|
8
|
+
* - any per-call `x-leash-callback` URL the buyer attached to the request.
|
|
9
|
+
*
|
|
10
|
+
* Webhook delivery is **fire-and-forget** — a slow or 5xx-returning
|
|
11
|
+
* downstream never blocks the buyer's HTTP response. Downstream agents
|
|
12
|
+
* receiving these payloads should treat them as ephemeral and idempotency-
|
|
13
|
+
* key off `payment.receipt_hash`.
|
|
14
|
+
*/
|
|
15
|
+
import type { LeashPaymentEnvelope } from './envelope.js';
|
|
16
|
+
/** Payload posted to a webhook URL after a settled payment. */
|
|
17
|
+
export type WebhookPayload = {
|
|
18
|
+
/** Stable schema version. Bump on breaking shape changes. */
|
|
19
|
+
v: '0.1';
|
|
20
|
+
/** Discriminator so downstream routers can reject other Leash events. */
|
|
21
|
+
kind: 'leash.payment.settled';
|
|
22
|
+
/** ISO-8601 timestamp of the post (server clock at delivery time). */
|
|
23
|
+
ts: string;
|
|
24
|
+
/** Compact payment summary — the same envelope stamped on `X-Leash-*` headers. */
|
|
25
|
+
payment: LeashPaymentEnvelope;
|
|
26
|
+
/**
|
|
27
|
+
* The seller's response body, parsed as JSON when possible, otherwise the
|
|
28
|
+
* raw text. `null` when the body was empty.
|
|
29
|
+
*/
|
|
30
|
+
response: unknown;
|
|
31
|
+
};
|
|
32
|
+
export type BuildWebhookPayloadInput = {
|
|
33
|
+
envelope: LeashPaymentEnvelope;
|
|
34
|
+
/** Already-parsed response body. Pass the raw string for non-JSON responses. */
|
|
35
|
+
response: unknown;
|
|
36
|
+
/** Override the timestamp (e.g. for tests). */
|
|
37
|
+
ts?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Construct a typed {@link WebhookPayload} from an envelope + response body. */
|
|
40
|
+
export declare function buildWebhookPayload(input: BuildWebhookPayloadInput): WebhookPayload;
|
|
41
|
+
/**
|
|
42
|
+
* Parse and validate a payload received on the webhook endpoint side.
|
|
43
|
+
*
|
|
44
|
+
* Throws on shape mismatches so consumers can `try/catch` and reject the
|
|
45
|
+
* delivery with a 4xx (which Leash will silently swallow — no retry today).
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseWebhookPayload(input: unknown): WebhookPayload;
|
|
48
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/x402/webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,CAAC,EAAE,KAAK,CAAC;IACT,yEAAyE;IACzE,IAAI,EAAE,uBAAuB,CAAC;IAC9B,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,kFAAkF;IAClF,OAAO,EAAE,oBAAoB,CAAC;IAC9B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAC;IAClB,+CAA+C;IAC/C,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,cAAc,CAQnF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CA0BlE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leash webhook payload contract.
|
|
3
|
+
*
|
|
4
|
+
* After a successful payment the seller `/x/<id>` route POSTs a JSON body
|
|
5
|
+
* shaped like {@link WebhookPayload} to:
|
|
6
|
+
* - the seller-configured `endpoint.webhook_url` (set when the link was
|
|
7
|
+
* created), and
|
|
8
|
+
* - any per-call `x-leash-callback` URL the buyer attached to the request.
|
|
9
|
+
*
|
|
10
|
+
* Webhook delivery is **fire-and-forget** — a slow or 5xx-returning
|
|
11
|
+
* downstream never blocks the buyer's HTTP response. Downstream agents
|
|
12
|
+
* receiving these payloads should treat them as ephemeral and idempotency-
|
|
13
|
+
* key off `payment.receipt_hash`.
|
|
14
|
+
*/
|
|
15
|
+
/** Construct a typed {@link WebhookPayload} from an envelope + response body. */
|
|
16
|
+
export function buildWebhookPayload(input) {
|
|
17
|
+
return {
|
|
18
|
+
v: '0.1',
|
|
19
|
+
kind: 'leash.payment.settled',
|
|
20
|
+
ts: input.ts ?? new Date().toISOString(),
|
|
21
|
+
payment: input.envelope,
|
|
22
|
+
response: input.response ?? null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse and validate a payload received on the webhook endpoint side.
|
|
27
|
+
*
|
|
28
|
+
* Throws on shape mismatches so consumers can `try/catch` and reject the
|
|
29
|
+
* delivery with a 4xx (which Leash will silently swallow — no retry today).
|
|
30
|
+
*/
|
|
31
|
+
export function parseWebhookPayload(input) {
|
|
32
|
+
if (!input || typeof input !== 'object') {
|
|
33
|
+
throw new Error('webhook payload: body is not an object');
|
|
34
|
+
}
|
|
35
|
+
const obj = input;
|
|
36
|
+
if (obj.v !== '0.1') {
|
|
37
|
+
throw new Error(`webhook payload: unsupported version "${String(obj.v)}", expected "0.1"`);
|
|
38
|
+
}
|
|
39
|
+
if (obj.kind !== 'leash.payment.settled') {
|
|
40
|
+
throw new Error(`webhook payload: unsupported kind "${String(obj.kind)}"`);
|
|
41
|
+
}
|
|
42
|
+
if (typeof obj.ts !== 'string' || obj.ts.length === 0) {
|
|
43
|
+
throw new Error('webhook payload: ts must be a non-empty string');
|
|
44
|
+
}
|
|
45
|
+
if (!obj.payment || typeof obj.payment !== 'object') {
|
|
46
|
+
throw new Error('webhook payload: payment must be an object');
|
|
47
|
+
}
|
|
48
|
+
const payment = parseEnvelope(obj.payment);
|
|
49
|
+
return {
|
|
50
|
+
v: '0.1',
|
|
51
|
+
kind: 'leash.payment.settled',
|
|
52
|
+
ts: obj.ts,
|
|
53
|
+
payment,
|
|
54
|
+
// Response is intentionally `unknown` — sellers can ship any shape.
|
|
55
|
+
response: 'response' in obj ? (obj.response ?? null) : null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function parseEnvelope(raw) {
|
|
59
|
+
const o = raw;
|
|
60
|
+
if (typeof o.receipt_hash !== 'string' || o.receipt_hash.length === 0) {
|
|
61
|
+
throw new Error('webhook payload: payment.receipt_hash must be a non-empty string');
|
|
62
|
+
}
|
|
63
|
+
if (typeof o.agent !== 'string' || o.agent.length === 0) {
|
|
64
|
+
throw new Error('webhook payload: payment.agent must be a non-empty string');
|
|
65
|
+
}
|
|
66
|
+
const explorer = (o.explorer ?? {});
|
|
67
|
+
return {
|
|
68
|
+
tx_sig: typeof o.tx_sig === 'string' ? o.tx_sig : null,
|
|
69
|
+
receipt_hash: o.receipt_hash,
|
|
70
|
+
agent: o.agent,
|
|
71
|
+
network: typeof o.network === 'string' ? o.network : null,
|
|
72
|
+
amount: parseAmount(o.amount),
|
|
73
|
+
facilitator: typeof o.facilitator === 'string' ? o.facilitator : null,
|
|
74
|
+
explorer: {
|
|
75
|
+
tx: typeof explorer.tx === 'string' ? explorer.tx : null,
|
|
76
|
+
agent: typeof explorer.agent === 'string' ? explorer.agent : '',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function parseAmount(raw) {
|
|
81
|
+
if (!raw || typeof raw !== 'object')
|
|
82
|
+
return null;
|
|
83
|
+
const o = raw;
|
|
84
|
+
if (typeof o.amount !== 'string' || typeof o.currency !== 'string')
|
|
85
|
+
return null;
|
|
86
|
+
return { amount: o.amount, currency: o.currency };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/x402/webhook.ts"],"names":[],"mappings":"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"}
|