@leashmarket/seller-kit 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 ADDED
@@ -0,0 +1,73 @@
1
+ # @leashmarket/seller-kit
2
+
3
+ Hono integration for Leash sellers. Three responsibilities:
4
+
5
+ 1. **Real x402 middleware on Solana.** `createSeller` mounts
6
+ `paymentMiddlewareFromHTTPServer` from `@x402/hono`, configured via
7
+ `createSvmResourceServer` (which wraps `ExactSvmScheme` from
8
+ `@x402/svm`) and pointed at an HTTPS facilitator (default
9
+ `https://facilitator.svmacc.tech`). Unauthenticated traffic gets
10
+ `402 + PAYMENT-REQUIRED`; settled traffic invokes the real handler.
11
+ 2. **Asset Signer PDA `payTo`.** The middleware always credits the seller
12
+ agent's Asset Signer PDA (derived via `mpl-core`), so funds land in the
13
+ on-chain treasury without the seller agent needing a private key.
14
+ 3. **`earn` receipts.** Every settled call emits a tamper-evident
15
+ `ReceiptV1` (with the real `tx_sig` and
16
+ `payment_requirements_hash` from the facilitator's
17
+ `PAYMENT-RESPONSE`) to the user-supplied `onReceipt` callback. Receipts
18
+ are nonce-ordered and hash-chained per seller agent, mirroring
19
+ `@leashmarket/buyer-kit` so explorers can verify both sides of the trade.
20
+
21
+ ```ts
22
+ import { createSeller } from '@leashmarket/seller-kit';
23
+
24
+ createSeller(app, {
25
+ umi,
26
+ sellerAgent: { asset: assetMint },
27
+ routes: { 'POST /tag': { price: '$0.001', description: 'tag' } },
28
+ onReceipt: (r) =>
29
+ fetch(`${RUNNER}/a/${r.agent}/receipts`, {
30
+ method: 'POST',
31
+ body: JSON.stringify(r),
32
+ }),
33
+ });
34
+ ```
35
+
36
+ ## Receipt semantics
37
+
38
+ - **402 → no receipt.** No settled trade to record.
39
+ - **2xx after settle → one earn receipt** with `tx_sig` and
40
+ `payment_requirements_hash` lifted from `PAYMENT-RESPONSE`.
41
+ - **Handler 4xx/5xx after payment → no receipt.** Recording would lie
42
+ about a settled trade.
43
+ - **Chain.** `prev_receipt_hash` links to the previous receipt's
44
+ `receipt_hash` for the same seller agent (in-process state).
45
+
46
+ ## Price parsing
47
+
48
+ `SellerRouteConfig.price` is a human display string. Use `parsePrice()` to
49
+ inspect what lands on a receipt:
50
+
51
+ ```ts
52
+ parsePrice('$0.001'); // { amount: '0.001', currency: 'USDC' }
53
+ parsePrice('0.5 USDT'); // { amount: '0.5', currency: 'USDT' }
54
+ parsePrice('0.01'); // { amount: '0.01', currency: 'USDC' }
55
+ ```
56
+
57
+ `$` and `USD` normalise to `USDC` since SVM settlement uses USDC.
58
+
59
+ ## Configuring the facilitator
60
+
61
+ ```ts
62
+ import { createSvmResourceServer } from '@leashmarket/seller-kit/x402';
63
+
64
+ const server = createSvmResourceServer({
65
+ network: 'solana-devnet',
66
+ payTo,
67
+ asset: '<USDC mint>',
68
+ facilitatorUrl: 'https://your-facilitator.example.com',
69
+ });
70
+ ```
71
+
72
+ See the [`Real x402 on Solana`](../../apps/docs/standards/x402-on-solana.mdx)
73
+ doc for the protocol-level walkthrough.
@@ -0,0 +1,109 @@
1
+ import type { Hono } from 'hono';
2
+ import type { Context as UmiContext } from '@metaplex-foundation/umi';
3
+ import type { ReceiptV1 } from '@leashmarket/schemas';
4
+ import { type KnownStableSymbol } from '@leashmarket/core';
5
+ import type { FacilitatorClient } from '@x402/core/server';
6
+ import { type LeashSellerNetwork } from '../x402/svm-server.js';
7
+ import { type AgentSellerConfig } from '../seller/agent-seller.js';
8
+ export type SellerRouteConfig = {
9
+ description: string;
10
+ /**
11
+ * Display price e.g. `"$0.001"`, `"0.01 USDC"`, or `"0.5"`. Parsed locally
12
+ * via {@link parsePrice} into atomic units against the route's `currency`
13
+ * (defaults to `'USDC'`), then advertised on the wire as an
14
+ * `AssetAmount` payment option so the facilitator settles in exactly that
15
+ * stablecoin. The same parsed `{ amount, currency, asset }` is stamped onto
16
+ * every `earn` `ReceiptV1` so explorers can render the correct value
17
+ * without re-parsing.
18
+ */
19
+ price: string;
20
+ /**
21
+ * Settlement currency for the price. Must be a Leash-known stablecoin
22
+ * (`USDC` / `USDT` / `USDG`) so the seller-kit can resolve a real mint via
23
+ * `@leashmarket/core/tokens`. Defaults to `'USDC'`.
24
+ */
25
+ currency?: KnownStableSymbol;
26
+ /**
27
+ * Additional stablecoins this route also accepts. When set, the runner
28
+ * advertises an `accepts[]` of equivalent payment options (same dollar
29
+ * amount across each stable, since v0.1 treats them as 1:1 USD pegs) so a
30
+ * paying agent can choose which token to debit. The route's primary
31
+ * `currency` is always included implicitly.
32
+ */
33
+ acceptsCurrencies?: KnownStableSymbol[];
34
+ /** Optional MIME type for the response. Defaults to `application/json`. */
35
+ mimeType?: string;
36
+ };
37
+ export type CreateSellerOptions = {
38
+ umi: Pick<UmiContext, 'eddsa' | 'programs'>;
39
+ sellerAgent: AgentSellerConfig;
40
+ routes: Record<string, SellerRouteConfig>;
41
+ /**
42
+ * CAIP-2 Solana network to settle on. Defaults to `'solana-devnet'`. The
43
+ * same network is stamped onto `ReceiptV1.price.network` and into the
44
+ * `paymentRequirements.network` advertised in 402 responses.
45
+ */
46
+ network?: LeashSellerNetwork;
47
+ /**
48
+ * Hosted x402 facilitator URL, or a pre-built `FacilitatorClient`. Defaults
49
+ * to `https://facilitator.svmacc.tech` (free, gas-sponsored). The URL is
50
+ * also stamped onto `ReceiptV1.facilitator` so consumers can verify the
51
+ * settlement out-of-band.
52
+ */
53
+ facilitator?: string | FacilitatorClient;
54
+ /**
55
+ * Called with every settled `earn` receipt. Receipts only fire on
56
+ * successful x402 settlements (the underlying `onAfterSettle` hook), so a
57
+ * 402 / 4xx / 5xx never produces a (false) earn receipt. Use this to ship
58
+ * receipts to the Leash runner — e.g.
59
+ * `onReceipt: (r) => fetch(`${RUNNER}/a/${r.agent}/receipts`, { method: 'POST', body: JSON.stringify(r) })`.
60
+ * Errors thrown here are swallowed so a runner outage never breaks a
61
+ * paying customer's request.
62
+ *
63
+ * Pass `false` to explicitly disable receipt publishing, even if env-
64
+ * level defaults (LEASH_RUNNER_URL / LEASH_API_URL) are configured.
65
+ */
66
+ onReceipt?: ((receipt: ReceiptV1) => void | Promise<void>) | false;
67
+ /**
68
+ * Optional fan-out destinations applied when `onReceipt` is undefined.
69
+ * Either or both can be set; `process.env.LEASH_RUNNER_URL`,
70
+ * `LEASH_API_URL`, and `LEASH_API_KEY` are also read so the most
71
+ * common production setup needs zero seller-kit code changes.
72
+ * Setting `LEASH_RECEIPTS_DISABLED=1` is the global kill switch.
73
+ */
74
+ receipts?: SellerReceiptForwardConfig;
75
+ /** Override the policy version stamped onto receipts. Defaults to `'0.1'`. */
76
+ policyVersion?: string;
77
+ };
78
+ export type SellerReceiptForwardConfig = {
79
+ runnerUrl?: string;
80
+ apiUrl?: string;
81
+ apiKey?: string;
82
+ fetch?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
83
+ };
84
+ export type Seller = {
85
+ /** Asset Signer PDA derived from `sellerAgent.asset` — the on-chain `payTo`. */
86
+ payTo: string;
87
+ /** Resolved facilitator URL written to receipts (null if a custom client was passed). */
88
+ facilitatorUrl: string | null;
89
+ /** CAIP-2 network the seller settles on. */
90
+ network: string;
91
+ };
92
+ /**
93
+ * Wires real x402-on-Solana payment enforcement onto a Hono app. For each
94
+ * route entry (`'METHOD /path'`), 402 responses include a proper
95
+ * `paymentRequirements[]` JSON; clients (e.g. `@leashmarket/buyer-kit` or any
96
+ * `@x402/fetch` consumer) sign an SPL `TransferChecked` to the agent's
97
+ * Asset Signer PDA and replay the request with `X-PAYMENT`. The configured
98
+ * facilitator verifies + settles the transaction on-chain, and `onReceipt`
99
+ * is invoked with a tamper-evident `earn` `ReceiptV1` populated with the
100
+ * real Solana transaction signature.
101
+ */
102
+ export declare function createSeller(app: Hono, opts: CreateSellerOptions): Seller;
103
+ /**
104
+ * Resolver shared with `@leashmarket/buyer-kit`. Lives here as a small inline
105
+ * copy (instead of importing from buyer-kit) so the seller package stays
106
+ * server-only and doesn't pull in the buyer's `@solana/kit` dependency.
107
+ */
108
+ export declare function resolveSellerReceiptSink(onReceipt: CreateSellerOptions['onReceipt'], forward: SellerReceiptForwardConfig | undefined): (receipt: ReceiptV1) => Promise<void>;
109
+ //# sourceMappingURL=create-seller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-seller.d.ts","sourceRoot":"","sources":["../../src/hono/create-seller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAUL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGvF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC;IAC5C,WAAW,EAAE,iBAAiB,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC1C;;;;OAIG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACzC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;IACnE;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,0BAA0B,CAAC;IACtC,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClF,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAOF;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAwIzE;AA2ID;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAC3C,OAAO,EAAE,0BAA0B,GAAG,SAAS,GAC9C,CAAC,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAmDvC"}
@@ -0,0 +1,325 @@
1
+ import { buildLeashFeeExtra, computeFeeAtoms as computeFeeAtomsHelper, finalizeReceipt, KNOWN_STABLE_SYMBOLS, lookupTokenBySymbol, networkFromCaip2, parseLeashFeeExtra, paymentRequirementsHash, requestHash, } from '@leashmarket/core';
2
+ import { paymentMiddlewareFromHTTPServer } from '@x402/hono';
3
+ import { x402HTTPResourceServer } from '@x402/core/server';
4
+ import { caip2ForSellerNetwork, createSvmResourceServer, DEFAULT_FACILITATOR_URL, } from '../x402/svm-server.js';
5
+ import { resolveSellerPayTo } from '../seller/agent-seller.js';
6
+ import { parsePrice } from '../receipts/price.js';
7
+ /**
8
+ * Wires real x402-on-Solana payment enforcement onto a Hono app. For each
9
+ * route entry (`'METHOD /path'`), 402 responses include a proper
10
+ * `paymentRequirements[]` JSON; clients (e.g. `@leashmarket/buyer-kit` or any
11
+ * `@x402/fetch` consumer) sign an SPL `TransferChecked` to the agent's
12
+ * Asset Signer PDA and replay the request with `X-PAYMENT`. The configured
13
+ * facilitator verifies + settles the transaction on-chain, and `onReceipt`
14
+ * is invoked with a tamper-evident `earn` `ReceiptV1` populated with the
15
+ * real Solana transaction signature.
16
+ */
17
+ export function createSeller(app, opts) {
18
+ const payTo = resolveSellerPayTo(opts.umi, opts.sellerAgent);
19
+ const agent = String(opts.sellerAgent.asset);
20
+ const policyVersion = opts.policyVersion ?? '0.1';
21
+ const sellerNetwork = opts.network ?? 'solana-devnet';
22
+ const networkCaip2 = caip2ForSellerNetwork(sellerNetwork);
23
+ const state = { nonce: 0, prevReceiptHash: null };
24
+ // Same precedence as buyer-kit: explicit `false` => off, function =>
25
+ // user controls the sink, undefined => env + opts fan-out.
26
+ const receiptSink = resolveSellerReceiptSink(opts.onReceipt, opts.receipts);
27
+ const { server, facilitatorUrl } = createSvmResourceServer({
28
+ networks: [sellerNetwork],
29
+ facilitator: opts.facilitator ?? DEFAULT_FACILITATOR_URL,
30
+ });
31
+ const recordedFacilitator = typeof opts.facilitator === 'string'
32
+ ? opts.facilitator
33
+ : (facilitatorUrl ?? DEFAULT_FACILITATOR_URL);
34
+ const tokenNetwork = networkAliasFor(sellerNetwork) === 'solana-mainnet' ? 'mainnet' : 'devnet';
35
+ const routes = {};
36
+ for (const [routeKey, cfg] of Object.entries(opts.routes)) {
37
+ const [method, path] = routeKey.split(/\s+/, 2);
38
+ if (!method || !path) {
39
+ throw new Error(`Invalid route key: ${routeKey}`);
40
+ }
41
+ const accepts = buildAccepts({
42
+ payTo,
43
+ networkCaip2,
44
+ tokenNetwork,
45
+ priceString: cfg.price,
46
+ currency: cfg.currency ?? 'USDC',
47
+ extraCurrencies: cfg.acceptsCurrencies ?? [],
48
+ });
49
+ routes[`${method.toUpperCase()} ${path}`] = {
50
+ description: cfg.description,
51
+ mimeType: cfg.mimeType ?? 'application/json',
52
+ accepts: accepts.length === 1 ? accepts[0] : accepts,
53
+ };
54
+ }
55
+ const httpServer = new x402HTTPResourceServer(server, routes);
56
+ /**
57
+ * `onAfterSettle` fires once the facilitator has confirmed the SPL
58
+ * transfer. The `result.transaction` is the real Solana signature.
59
+ *
60
+ * The receipt's `price` is sourced from the **settled** payment
61
+ * requirements (so multi-currency endpoints stamp the actual debited
62
+ * token), then enriched with the friendly Leash network slug.
63
+ *
64
+ * We additionally stamp `result.paymentRequirements = requirements`
65
+ * BEFORE the x402 middleware encodes `PAYMENT-RESPONSE`. Why: the
66
+ * upstream x402 SDK only puts the settlement `transaction` (and
67
+ * payer / network / amount) into the response header, not the
68
+ * matched `PaymentRequirements`. That leaves any buyer reading the
69
+ * header — including our own buyer-kit's `parseSettlement` — unable
70
+ * to recover the price/asset and forces them to stamp `price: null`
71
+ * on the spend receipt. Mutating `result` here lets the encoder
72
+ * pick up the requirements via JSON spread (the field rides along
73
+ * inside the same base64 payload), and `parseSettlement` already
74
+ * looks for `obj.paymentRequirements` on the decoded side, so the
75
+ * fix is end-to-end with zero changes on the buyer.
76
+ *
77
+ * We also fan into `extensions['leash.paymentRequirements']` as a
78
+ * second carrier for future buyers that prefer the namespaced
79
+ * extension surface (per x402's extension contract).
80
+ */
81
+ server.onAfterSettle(async ({ requirements, result, transportContext }) => {
82
+ if (!result.success)
83
+ return;
84
+ // Cast through `unknown` because `SettleResponse` doesn't declare
85
+ // `paymentRequirements` in its type but the JSON encoder is
86
+ // permissive — extra fields round-trip cleanly.
87
+ result.paymentRequirements =
88
+ requirements;
89
+ const extensions = (result.extensions ?? {});
90
+ extensions['leash.paymentRequirements'] = requirements;
91
+ result.extensions = extensions;
92
+ const httpCtx = transportContext;
93
+ const reqCtx = httpCtx?.request;
94
+ const method = reqCtx?.method ?? 'POST';
95
+ const url = reqCtx?.adapter.getUrl?.() ?? reqCtx?.path ?? '';
96
+ const route = findRouteForPath(opts.routes, reqCtx);
97
+ const settledCurrency = lookupTokenBySymbol('USDC', tokenNetwork)?.mint === requirements.asset
98
+ ? 'USDC'
99
+ : (lookupCurrencyBySymbol(requirements.asset, tokenNetwork) ?? route?.currency ?? 'USDC');
100
+ // Enrich the receipt's price with protocol-fee context when the
101
+ // settled requirements carry an `extra['leash.fee']` block. We
102
+ // compute the atomic fee + gross from the seller's net amount + bps
103
+ // (same logic as the buyer scheme + facilitator), so explorers can
104
+ // render `gross / fee / net` without re-deriving anything. Vanilla
105
+ // x402 settlements (no fee block) keep the slim shape.
106
+ const feeExtra = parseLeashFeeExtra((requirements.extra ?? null));
107
+ const netAtomic = BigInt(requirements.amount);
108
+ const feeAtomic = feeExtra ? computeFeeAtomsHelper(netAtomic, feeExtra.bps) : 0n;
109
+ const grossAtomic = netAtomic + feeAtomic;
110
+ const enrichedPrice = {
111
+ amount: requirements.amount,
112
+ currency: settledCurrency,
113
+ network: networkFromCaip2(networkCaip2) ?? sellerNetwork,
114
+ asset: requirements.asset,
115
+ ...(feeExtra
116
+ ? {
117
+ fee: feeAtomic.toString(),
118
+ gross: grossAtomic.toString(),
119
+ feeBps: feeExtra.bps,
120
+ feeAuthority: feeExtra.feeAuthority,
121
+ }
122
+ : {}),
123
+ };
124
+ await emitEarnReceipt({
125
+ state,
126
+ agent,
127
+ policyVersion,
128
+ method,
129
+ url,
130
+ bodyText: null,
131
+ responseStatus: 200,
132
+ txSig: result.transaction ?? null,
133
+ facilitator: recordedFacilitator,
134
+ paymentReqHash: paymentRequirementsHash(requirements),
135
+ price: enrichedPrice,
136
+ sink: receiptSink,
137
+ });
138
+ });
139
+ app.use(paymentMiddlewareFromHTTPServer(httpServer));
140
+ return { payTo, facilitatorUrl: recordedFacilitator, network: networkCaip2 };
141
+ }
142
+ /**
143
+ * Find the user-supplied SellerRouteConfig that matches a verified payment.
144
+ * Matches `'METHOD /path'` keys against the live request context; falls back
145
+ * to the first entry so single-route sellers always resolve correctly.
146
+ */
147
+ function findRouteForPath(routes, reqCtx) {
148
+ if (reqCtx) {
149
+ const path = reqCtx.path;
150
+ const method = reqCtx.method.toUpperCase();
151
+ for (const [key, cfg] of Object.entries(routes)) {
152
+ const [m, p] = key.split(/\s+/, 2);
153
+ if (m && p && m.toUpperCase() === method && p === path)
154
+ return cfg;
155
+ }
156
+ }
157
+ const first = Object.values(routes)[0];
158
+ return first ?? null;
159
+ }
160
+ /**
161
+ * Build the x402 `accepts[]` payment options for a route. The primary
162
+ * `currency` always comes first; any `extraCurrencies` are appended at
163
+ * the same dollar-equivalent amount (1:1 USD assumption is fine for v0.1
164
+ * since we only support 6-dec USD-pegged stables in the registry).
165
+ *
166
+ * Each option is encoded as an `AssetAmount` so the facilitator settles
167
+ * in exactly the buyer-chosen mint — no implicit USDC fallback.
168
+ */
169
+ function buildAccepts(args) {
170
+ const all = uniq([args.currency, ...args.extraCurrencies]);
171
+ // One-shot fee descriptor reused across every accepts[] entry. Bps +
172
+ // authority are the same for the whole route — only the destination
173
+ // ATA differs per asset, and that's derived buyer/facilitator-side
174
+ // from `(asset, tokenProgram, authority)` so it never lives on the
175
+ // wire.
176
+ const leashFee = buildLeashFeeExtra({ network: args.tokenNetwork });
177
+ return all.map((currency) => {
178
+ const parsed = parsePrice(args.priceString, {
179
+ network: args.tokenNetwork,
180
+ defaultCurrency: currency,
181
+ });
182
+ if (!parsed) {
183
+ throw new Error(`Invalid price "${args.priceString}" for currency ${currency} on ${args.tokenNetwork}.`);
184
+ }
185
+ // `extra['leash.fee']` rides along inside the `AssetAmount.extra`
186
+ // bag and surfaces on `paymentRequirements.extra` at 402 time. The
187
+ // x402 SDK forwards arbitrary extras through verbatim, so the
188
+ // buyer-kit / facilitator can read it without touching this layer.
189
+ return {
190
+ scheme: 'exact',
191
+ network: args.networkCaip2,
192
+ payTo: args.payTo,
193
+ price: { asset: parsed.asset, amount: parsed.amount, extra: { 'leash.fee': leashFee } },
194
+ };
195
+ });
196
+ }
197
+ function uniq(arr) {
198
+ return Array.from(new Set(arr));
199
+ }
200
+ /** Reverse-resolve a stablecoin symbol from a settled mint, if known. */
201
+ function lookupCurrencyBySymbol(asset, network) {
202
+ for (const sym of KNOWN_STABLE_SYMBOLS) {
203
+ if (lookupTokenBySymbol(sym, network)?.mint === asset)
204
+ return sym;
205
+ }
206
+ return null;
207
+ }
208
+ /**
209
+ * v0.1 collapses `solana-testnet` → `solana-devnet` for the token registry
210
+ * lookup. Mirrors {@link networkAlias} from `../x402/svm-server.ts` but
211
+ * exists locally to avoid a circular import in barrel files.
212
+ */
213
+ function networkAliasFor(net) {
214
+ return net === 'solana-mainnet' ? 'solana-mainnet' : 'solana-devnet';
215
+ }
216
+ async function emitEarnReceipt(args) {
217
+ // The sink is always callable; it short-circuits internally when the
218
+ // user passed `onReceipt: false` or `LEASH_RECEIPTS_DISABLED=1`.
219
+ // We still build the receipt in that case so the chain (`prev_receipt_hash`)
220
+ // stays consistent across calls — disabling publishing must not mutate
221
+ // the receipt graph.
222
+ const draft = {
223
+ v: '0.1',
224
+ kind: 'earn',
225
+ agent: args.agent,
226
+ nonce: args.state.nonce,
227
+ ts: new Date().toISOString(),
228
+ policy_v: args.policyVersion,
229
+ request: {
230
+ method: args.method,
231
+ url: args.url,
232
+ body_hash: args.bodyText
233
+ ? requestHash({ method: args.method, url: args.url, body: args.bodyText })
234
+ : null,
235
+ },
236
+ decision: 'allow',
237
+ reason: null,
238
+ price: args.price,
239
+ facilitator: args.facilitator,
240
+ tx_sig: args.txSig,
241
+ payment_requirements_hash: args.paymentReqHash,
242
+ response: { status: args.responseStatus, body_hash: null },
243
+ prev_receipt_hash: args.state.prevReceiptHash,
244
+ };
245
+ const receipt = finalizeReceipt(draft);
246
+ args.state.nonce += 1;
247
+ args.state.prevReceiptHash = receipt.receipt_hash;
248
+ await args.sink(receipt);
249
+ }
250
+ /**
251
+ * Resolver shared with `@leashmarket/buyer-kit`. Lives here as a small inline
252
+ * copy (instead of importing from buyer-kit) so the seller package stays
253
+ * server-only and doesn't pull in the buyer's `@solana/kit` dependency.
254
+ */
255
+ export function resolveSellerReceiptSink(onReceipt, forward) {
256
+ if (onReceipt === false || envFlag('LEASH_RECEIPTS_DISABLED')) {
257
+ return async () => { };
258
+ }
259
+ if (typeof onReceipt === 'function') {
260
+ return async (receipt) => {
261
+ try {
262
+ await onReceipt(receipt);
263
+ }
264
+ catch {
265
+ // Intentionally swallowed.
266
+ }
267
+ };
268
+ }
269
+ const env = readEnvForwardConfig();
270
+ const merged = {
271
+ runnerUrl: forward?.runnerUrl ?? env.runnerUrl,
272
+ apiUrl: forward?.apiUrl ?? env.apiUrl,
273
+ apiKey: forward?.apiKey ?? env.apiKey,
274
+ ...(forward?.fetch ? { fetch: forward.fetch } : {}),
275
+ };
276
+ const fetchImpl = merged.fetch ?? globalThis.fetch;
277
+ return async (receipt) => {
278
+ const tasks = [];
279
+ if (merged.runnerUrl) {
280
+ tasks.push(doPost(fetchImpl, `${merged.runnerUrl.replace(/\/+$/, '')}/a/${encodeURIComponent(receipt.agent)}/receipts`, receipt));
281
+ }
282
+ if (merged.apiUrl && merged.apiKey) {
283
+ tasks.push(doPost(fetchImpl, `${merged.apiUrl.replace(/\/+$/, '')}/v1/receipts/${encodeURIComponent(receipt.agent)}`, receipt, { authorization: `Bearer ${merged.apiKey}` }));
284
+ }
285
+ if (tasks.length === 0)
286
+ return;
287
+ const settled = await Promise.allSettled(tasks);
288
+ for (const r of settled) {
289
+ if (r.status === 'rejected') {
290
+ // eslint-disable-next-line no-console
291
+ console.warn('[seller-kit] receipt forward failed:', r.reason.message);
292
+ }
293
+ }
294
+ };
295
+ }
296
+ async function doPost(fetchImpl, url, receipt, extraHeaders = {}) {
297
+ const res = await fetchImpl(url, {
298
+ method: 'POST',
299
+ headers: { 'content-type': 'application/json', ...extraHeaders },
300
+ body: JSON.stringify(receipt),
301
+ });
302
+ if (!res.ok) {
303
+ const detail = await res.text().catch(() => '');
304
+ throw new Error(`POST ${url} -> ${res.status}: ${detail.slice(0, 200)}`);
305
+ }
306
+ }
307
+ function readEnvForwardConfig() {
308
+ if (typeof process === 'undefined' || !process.env)
309
+ return {};
310
+ const env = process.env;
311
+ return {
312
+ ...(env.LEASH_RUNNER_URL ? { runnerUrl: env.LEASH_RUNNER_URL } : {}),
313
+ ...(env.LEASH_API_URL ? { apiUrl: env.LEASH_API_URL } : {}),
314
+ ...(env.LEASH_API_KEY ? { apiKey: env.LEASH_API_KEY } : {}),
315
+ };
316
+ }
317
+ function envFlag(name) {
318
+ if (typeof process === 'undefined' || !process.env)
319
+ return false;
320
+ const raw = process.env[name];
321
+ if (!raw)
322
+ return false;
323
+ return raw === '1' || raw.toLowerCase() === 'true';
324
+ }
325
+ //# sourceMappingURL=create-seller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-seller.js","sourceRoot":"","sources":["../../src/hono/create-seller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ /**
3
+ * Minimal x402-shaped gate: 402 without payment header, forwards when present.
4
+ * Swap for `@x402/hono` `paymentMiddleware` + PayAI facilitator in production.
5
+ */
6
+ export declare function simpleX402Gate(): MiddlewareHandler;
7
+ //# sourceMappingURL=simple-x402.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-x402.d.ts","sourceRoot":"","sources":["../../src/hono/simple-x402.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAI9C;;;GAGG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAOlD"}
@@ -0,0 +1,14 @@
1
+ const HEADER = 'x-payment';
2
+ /**
3
+ * Minimal x402-shaped gate: 402 without payment header, forwards when present.
4
+ * Swap for `@x402/hono` `paymentMiddleware` + PayAI facilitator in production.
5
+ */
6
+ export function simpleX402Gate() {
7
+ return async (c, next) => {
8
+ if (!c.req.header(HEADER)) {
9
+ return c.json({ error: 'payment_required', protocol: 'x402-shaped' }, 402);
10
+ }
11
+ await next();
12
+ };
13
+ }
14
+ //# sourceMappingURL=simple-x402.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-x402.js","sourceRoot":"","sources":["../../src/hono/simple-x402.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAG,WAAW,CAAC;AAE3B;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './hono/create-seller.js';
2
+ export * from './x402/svm-server.js';
3
+ export * from './seller/agent-seller.js';
4
+ export * from './receipts/store.js';
5
+ export * from './receipts/price.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './hono/create-seller.js';
2
+ export * from './x402/svm-server.js';
3
+ export * from './seller/agent-seller.js';
4
+ export * from './receipts/store.js';
5
+ export * from './receipts/price.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ReceiptV1 } from '@leashmarket/schemas';
2
+ import { type KnownStableSymbol, type TokenNetwork } from '@leashmarket/core';
3
+ type Price = NonNullable<ReceiptV1['price']>;
4
+ /**
5
+ * Parse a human-readable `price` string used in `SellerRouteConfig`
6
+ * (e.g. `"$0.001"`, `"0.01 USDG"`, `"0.5"`) into the structured
7
+ * `{ amount, currency, asset? }` shape stored inside `ReceiptV1.price`.
8
+ *
9
+ * `amount` is returned as the **atomic integer** for the resolved currency
10
+ * on the supplied `network` (e.g. `"$0.001"` → `"1000"` for USDC's 6
11
+ * decimals). This keeps every receipt — earn or spend — using the same
12
+ * on-the-wire representation, so format helpers in `@leashmarket/core/format`
13
+ * never have to guess whether a string is decimal or atomic.
14
+ *
15
+ * Resolution rules:
16
+ * - A leading `$` (or trailing `USD`) is treated as the supplied
17
+ * `defaultCurrency` (defaults to `'USDC'`). v0.1 settles only in known
18
+ * stablecoins on Solana, so dollars map cleanly onto a 6-dec stable.
19
+ * - A trailing token symbol (`USDC`, `USDT`, `USDG`) is preserved.
20
+ * - A bare number falls back to `defaultCurrency`.
21
+ * - Unknown stables (or non-stables in v0.1) return `null` so callers can
22
+ * fail loudly instead of stamping a wrong asset onto the receipt.
23
+ */
24
+ export declare function parsePrice(input: string, opts?: {
25
+ network?: TokenNetwork;
26
+ defaultCurrency?: KnownStableSymbol;
27
+ }): Price | null;
28
+ export {};
29
+ //# sourceMappingURL=price.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../src/receipts/price.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B,KAAK,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,YAAY,CAAC;IAAC,eAAe,CAAC,EAAE,iBAAiB,CAAA;CAAO,GACzE,KAAK,GAAG,IAAI,CAyBd"}
@@ -0,0 +1,58 @@
1
+ import { decimalToAtomic, KNOWN_STABLE_SYMBOLS, lookupTokenBySymbol, } from '@leashmarket/core';
2
+ /**
3
+ * Parse a human-readable `price` string used in `SellerRouteConfig`
4
+ * (e.g. `"$0.001"`, `"0.01 USDG"`, `"0.5"`) into the structured
5
+ * `{ amount, currency, asset? }` shape stored inside `ReceiptV1.price`.
6
+ *
7
+ * `amount` is returned as the **atomic integer** for the resolved currency
8
+ * on the supplied `network` (e.g. `"$0.001"` → `"1000"` for USDC's 6
9
+ * decimals). This keeps every receipt — earn or spend — using the same
10
+ * on-the-wire representation, so format helpers in `@leashmarket/core/format`
11
+ * never have to guess whether a string is decimal or atomic.
12
+ *
13
+ * Resolution rules:
14
+ * - A leading `$` (or trailing `USD`) is treated as the supplied
15
+ * `defaultCurrency` (defaults to `'USDC'`). v0.1 settles only in known
16
+ * stablecoins on Solana, so dollars map cleanly onto a 6-dec stable.
17
+ * - A trailing token symbol (`USDC`, `USDT`, `USDG`) is preserved.
18
+ * - A bare number falls back to `defaultCurrency`.
19
+ * - Unknown stables (or non-stables in v0.1) return `null` so callers can
20
+ * fail loudly instead of stamping a wrong asset onto the receipt.
21
+ */
22
+ export function parsePrice(input, opts = {}) {
23
+ const trimmed = input.trim();
24
+ if (!trimmed)
25
+ return null;
26
+ const network = opts.network ?? 'devnet';
27
+ const defaultCurrency = opts.defaultCurrency ?? 'USDC';
28
+ const dollar = trimmed.match(/^\$\s*([0-9]+(?:\.[0-9]+)?)$/);
29
+ if (dollar) {
30
+ return finalize(dollar[1], defaultCurrency, network);
31
+ }
32
+ const suffixed = trimmed.match(/^([0-9]+(?:\.[0-9]+)?)\s*([A-Z][A-Z0-9]{1,9})$/i);
33
+ if (suffixed) {
34
+ const sym = suffixed[2].toUpperCase();
35
+ const currency = sym === 'USD' ? defaultCurrency : sym;
36
+ if (!isKnownStable(currency))
37
+ return null;
38
+ return finalize(suffixed[1], currency, network);
39
+ }
40
+ const bare = trimmed.match(/^([0-9]+(?:\.[0-9]+)?)$/);
41
+ if (bare) {
42
+ return finalize(bare[1], defaultCurrency, network);
43
+ }
44
+ return null;
45
+ }
46
+ function finalize(decimal, currency, network) {
47
+ const token = lookupTokenBySymbol(currency, network);
48
+ if (!token)
49
+ return null;
50
+ const atomic = decimalToAtomic(decimal, token.decimals);
51
+ if (atomic === null)
52
+ return null;
53
+ return { amount: atomic.toString(), currency, asset: token.mint };
54
+ }
55
+ function isKnownStable(symbol) {
56
+ return KNOWN_STABLE_SYMBOLS.includes(symbol);
57
+ }
58
+ //# sourceMappingURL=price.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"price.js","sourceRoot":"","sources":["../../src/receipts/price.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,mBAAmB,GAGpB,MAAM,mBAAmB,CAAC;AAI3B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,OAAwE,EAAE;IAE1E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,OAAO,GAAiB,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC;IACvD,MAAM,eAAe,GAAsB,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC;IAE1E,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC7D,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAClF,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC;QACvD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACtD,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CACf,OAAe,EACf,QAA2B,EAC3B,OAAqB;IAErB,MAAM,KAAK,GAAG,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;AACpE,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,OAAQ,oBAA8C,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ReceiptV1 } from '@leashmarket/schemas';
2
+ export type ReceiptStore = {
3
+ append(receipt: ReceiptV1): Promise<void>;
4
+ };
5
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/receipts/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/receipts/store.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import type { Context, PublicKey } from '@metaplex-foundation/umi';
2
+ export type AgentSellerConfig = {
3
+ asset: string | PublicKey;
4
+ };
5
+ export declare function resolveSellerPayTo(umi: Pick<Context, 'eddsa' | 'programs'>, cfg: AgentSellerConfig): string;
6
+ //# sourceMappingURL=agent-seller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-seller.d.ts","sourceRoot":"","sources":["../../src/seller/agent-seller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGnE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAAC,EACxC,GAAG,EAAE,iBAAiB,GACrB,MAAM,CAIR"}
@@ -0,0 +1,8 @@
1
+ import { findAssetSignerPda } from '@metaplex-foundation/mpl-core';
2
+ import { publicKey } from '@metaplex-foundation/umi';
3
+ export function resolveSellerPayTo(umi, cfg) {
4
+ const asset = typeof cfg.asset === 'string' ? publicKey(cfg.asset) : cfg.asset;
5
+ const [addr] = findAssetSignerPda(umi, { asset });
6
+ return String(addr);
7
+ }
8
+ //# sourceMappingURL=agent-seller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-seller.js","sourceRoot":"","sources":["../../src/seller/agent-seller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAMrD,MAAM,UAAU,kBAAkB,CAChC,GAAwC,EACxC,GAAsB;IAEtB,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IAC/E,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { FacilitatorClient } from '@x402/core/server';
2
+ /**
3
+ * In-memory x402 facilitator for Vitest and demo smoke tests. Avoids HTTP
4
+ * round-trips to the default hosted facilitator (which may be unreachable
5
+ * in CI or offline).
6
+ */
7
+ export declare function stubFacilitator(opts?: {
8
+ txSig?: string;
9
+ }): FacilitatorClient;
10
+ //# sourceMappingURL=stub-facilitator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub-facilitator.d.ts","sourceRoot":"","sources":["../../src/test-utils/stub-facilitator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAY3D;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAoC5E"}
@@ -0,0 +1,39 @@
1
+ import { SOLANA_DEVNET_CAIP2 } from '@x402/svm';
2
+ const FACILITATOR_FEEPAYER = 'FaciliTatoR1111111111111111111111111111111';
3
+ /**
4
+ * In-memory x402 facilitator for Vitest and demo smoke tests. Avoids HTTP
5
+ * round-trips to the default hosted facilitator (which may be unreachable
6
+ * in CI or offline).
7
+ */
8
+ export function stubFacilitator(opts) {
9
+ let nonce = 0;
10
+ return {
11
+ async getSupported() {
12
+ return {
13
+ kinds: [
14
+ {
15
+ x402Version: 2,
16
+ scheme: 'exact',
17
+ network: SOLANA_DEVNET_CAIP2,
18
+ extra: { feePayer: FACILITATOR_FEEPAYER },
19
+ },
20
+ ],
21
+ extensions: [],
22
+ signers: {},
23
+ };
24
+ },
25
+ async verify(_payload, _requirements) {
26
+ return { isValid: true, payer: 'Buyer1111111111111111111111111111111111' };
27
+ },
28
+ async settle(_payload, requirements) {
29
+ nonce += 1;
30
+ return {
31
+ success: true,
32
+ transaction: `${opts?.txSig ?? 'sig'}-${nonce}`,
33
+ network: requirements.network,
34
+ payer: 'Buyer1111111111111111111111111111111111',
35
+ };
36
+ },
37
+ };
38
+ }
39
+ //# sourceMappingURL=stub-facilitator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub-facilitator.js","sourceRoot":"","sources":["../../src/test-utils/stub-facilitator.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,oBAAoB,GAAG,4CAA4C,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAyB;IACvD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO;QACL,KAAK,CAAC,YAAY;YAChB,OAAO;gBACL,KAAK,EAAE;oBACL;wBACE,WAAW,EAAE,CAAC;wBACd,MAAM,EAAE,OAAO;wBACf,OAAO,EAAE,mBAAmB;wBAC5B,KAAK,EAAE,EAAE,QAAQ,EAAE,oBAAoB,EAAE;qBAC1C;iBACF;gBACD,UAAU,EAAE,EAAE;gBACd,OAAO,EAAE,EAAE;aACZ,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,MAAM,CACV,QAAwB,EACxB,aAAkC;YAElC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;QAC7E,CAAC;QACD,KAAK,CAAC,MAAM,CACV,QAAwB,EACxB,YAAiC;YAEjC,KAAK,IAAI,CAAC,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,WAAW,EAAE,GAAG,IAAI,EAAE,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE;gBAC/C,OAAO,EAAE,YAAY,CAAC,OAAO;gBAC7B,KAAK,EAAE,yCAAyC;aACjD,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { x402ResourceServer } from '@x402/core/server';
2
+ import type { FacilitatorClient } from '@x402/core/server';
3
+ import type { Network } from '@x402/core/types';
4
+ export type LeashSellerNetwork = 'solana-mainnet' | 'solana-devnet' | 'solana-testnet';
5
+ export declare function caip2ForSellerNetwork(network: LeashSellerNetwork): Network;
6
+ /**
7
+ * Collapse `solana-testnet` → `solana-devnet` for the purposes of choosing
8
+ * a facilitator / settlement network. v0.1 does not have a public testnet
9
+ * facilitator, so testnet endpoints settle on devnet rails.
10
+ *
11
+ * Used by the public `/x/<id>` route so seller links built on testnet
12
+ * still work end-to-end without a dedicated facilitator deploy.
13
+ */
14
+ export declare function networkAlias(network: LeashSellerNetwork): 'solana-mainnet' | 'solana-devnet';
15
+ /**
16
+ * Backwards-compatible alias. New code should prefer
17
+ * {@link defaultFacilitatorFor} from `@leashmarket/core` so devnet and mainnet pick
18
+ * appropriate hosts and `LEASH_FACILITATOR_URL` overrides flow uniformly.
19
+ */
20
+ export declare const DEFAULT_FACILITATOR_URL = "https://devnet-facilitator.leash.market";
21
+ export type CreateSvmResourceServerOptions = {
22
+ /** CAIP-2 networks the seller accepts. Defaults to `['solana-devnet']`. */
23
+ networks?: LeashSellerNetwork[];
24
+ /**
25
+ * Hosted x402 facilitator. Defaults to `https://facilitator.svmacc.tech`,
26
+ * the public SVM facilitator (gas-sponsored, no signup). Pass a different
27
+ * URL or a fully-built `FacilitatorClient` to point at PayAI, Corbits, or
28
+ * a self-hosted instance.
29
+ */
30
+ facilitator?: string | FacilitatorClient;
31
+ };
32
+ /**
33
+ * Build an `x402ResourceServer` configured with the SVM exact-payment scheme
34
+ * for one or more Solana clusters and a hosted facilitator client. This is
35
+ * what `createSeller` registers under the hood; export it so advanced
36
+ * callers can attach `onAfterSettle`/`onSettleFailure` hooks of their own.
37
+ */
38
+ export declare function createSvmResourceServer(opts?: CreateSvmResourceServerOptions): {
39
+ server: x402ResourceServer;
40
+ facilitatorUrl: string | null;
41
+ };
42
+ //# sourceMappingURL=svm-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svm-server.d.ts","sourceRoot":"","sources":["../../src/x402/svm-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAKhD,MAAM,MAAM,kBAAkB,GAAG,gBAAgB,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAQvF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAE1E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,kBAAkB,GAAG,gBAAgB,GAAG,eAAe,CAE5F;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,4CAA2B,CAAC;AAEhE,MAAM,MAAM,8BAA8B,GAAG;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAChC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;CAC1C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,8BAAmC,GAAG;IAClF,MAAM,EAAE,kBAAkB,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAiBA"}
@@ -0,0 +1,50 @@
1
+ import { HTTPFacilitatorClient, x402ResourceServer } from '@x402/core/server';
2
+ import { ExactSvmScheme } from '@x402/svm/exact/server';
3
+ import { SOLANA_DEVNET_CAIP2, SOLANA_MAINNET_CAIP2, SOLANA_TESTNET_CAIP2 } from '@x402/svm';
4
+ import { defaultFacilitatorFor, FALLBACK_FACILITATOR_URL } from '@leashmarket/core';
5
+ const NETWORK_TO_CAIP2 = {
6
+ 'solana-mainnet': SOLANA_MAINNET_CAIP2,
7
+ 'solana-devnet': SOLANA_DEVNET_CAIP2,
8
+ 'solana-testnet': SOLANA_TESTNET_CAIP2,
9
+ };
10
+ export function caip2ForSellerNetwork(network) {
11
+ return NETWORK_TO_CAIP2[network];
12
+ }
13
+ /**
14
+ * Collapse `solana-testnet` → `solana-devnet` for the purposes of choosing
15
+ * a facilitator / settlement network. v0.1 does not have a public testnet
16
+ * facilitator, so testnet endpoints settle on devnet rails.
17
+ *
18
+ * Used by the public `/x/<id>` route so seller links built on testnet
19
+ * still work end-to-end without a dedicated facilitator deploy.
20
+ */
21
+ export function networkAlias(network) {
22
+ return network === 'solana-mainnet' ? 'solana-mainnet' : 'solana-devnet';
23
+ }
24
+ /**
25
+ * Backwards-compatible alias. New code should prefer
26
+ * {@link defaultFacilitatorFor} from `@leashmarket/core` so devnet and mainnet pick
27
+ * appropriate hosts and `LEASH_FACILITATOR_URL` overrides flow uniformly.
28
+ */
29
+ export const DEFAULT_FACILITATOR_URL = FALLBACK_FACILITATOR_URL;
30
+ /**
31
+ * Build an `x402ResourceServer` configured with the SVM exact-payment scheme
32
+ * for one or more Solana clusters and a hosted facilitator client. This is
33
+ * what `createSeller` registers under the hood; export it so advanced
34
+ * callers can attach `onAfterSettle`/`onSettleFailure` hooks of their own.
35
+ */
36
+ export function createSvmResourceServer(opts = {}) {
37
+ const networks = opts.networks ?? ['solana-devnet'];
38
+ const defaultUrl = defaultFacilitatorFor(networks);
39
+ const facilitatorClient = typeof opts.facilitator === 'string'
40
+ ? new HTTPFacilitatorClient({ url: opts.facilitator })
41
+ : (opts.facilitator ?? new HTTPFacilitatorClient({ url: defaultUrl }));
42
+ const facilitatorUrl = facilitatorClient instanceof HTTPFacilitatorClient ? facilitatorClient.url : null;
43
+ const server = new x402ResourceServer(facilitatorClient);
44
+ const scheme = new ExactSvmScheme();
45
+ for (const n of networks) {
46
+ server.register(NETWORK_TO_CAIP2[n], scheme);
47
+ }
48
+ return { server, facilitatorUrl };
49
+ }
50
+ //# sourceMappingURL=svm-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svm-server.js","sourceRoot":"","sources":["../../src/x402/svm-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG9E,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAIpF,MAAM,gBAAgB,GAAwC;IAC5D,gBAAgB,EAAE,oBAA+B;IACjD,eAAe,EAAE,mBAA8B;IAC/C,gBAAgB,EAAE,oBAA+B;CAClD,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,OAA2B;IAC/D,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,OAA2B;IACtD,OAAO,OAAO,KAAK,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,eAAe,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAchE;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAuC,EAAE;IAI/E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,iBAAiB,GACrB,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;QAClC,CAAC,CAAC,IAAI,qBAAqB,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QACtD,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,qBAAqB,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;IAE3E,MAAM,cAAc,GAClB,iBAAiB,YAAY,qBAAqB,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAEpF,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;AACpC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@leashmarket/seller-kit",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./test-utils": {
14
+ "types": "./dist/test-utils/stub-facilitator.d.ts",
15
+ "import": "./dist/test-utils/stub-facilitator.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "@metaplex-foundation/mpl-core": "^1.10.0",
23
+ "@metaplex-foundation/umi": "^1.5.1",
24
+ "@metaplex-foundation/umi-bundle-defaults": "^1.5.1",
25
+ "@solana/kit": "^5.1.0",
26
+ "@x402/core": "^2.10.0",
27
+ "@x402/hono": "^2.10.0",
28
+ "@x402/svm": "^2.10.0",
29
+ "hono": "^4.6.14",
30
+ "@leashmarket/core": "0.1.0",
31
+ "@leashmarket/schemas": "0.1.0"
32
+ },
33
+ "devDependencies": {
34
+ "typescript": "^5.7.2",
35
+ "vitest": "^2.1.8"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.build.json",
42
+ "typecheck": "tsc -p tsconfig.json",
43
+ "lint": "eslint src",
44
+ "test": "vitest run"
45
+ }
46
+ }