@piprail/sdk 2.0.2 → 2.1.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/dist/index.cjs CHANGED
@@ -2019,19 +2019,119 @@ function normalizeNetwork(network) {
2019
2019
  async function searchOpenIndexes(opts = {}) {
2020
2020
  const sources = _nullishCoalesce(opts.sources, () => ( ["bazaar", "402index"]));
2021
2021
  const limit = _nullishCoalesce(opts.limit, () => ( 20));
2022
+ const filters = {
2023
+ ...optionalRaw("category", opts.category),
2024
+ ...optionalRaw("asset", opts.asset),
2025
+ ...optionalRaw("maxPrice", opts.maxPrice),
2026
+ ...optionalRaw("verified", opts.verified),
2027
+ ...optionalRaw("paymentValid", opts.paymentValid),
2028
+ ...optionalRaw("sort", opts.sort),
2029
+ ...optionalRaw("order", opts.order)
2030
+ };
2022
2031
  const results = await Promise.all(
2023
2032
  sources.map((source) => {
2024
2033
  if (source === "bazaar") return safeSearch(() => searchBazaar(opts.query, limit, opts.signal));
2025
- if (source === "402index") return safeSearch(() => search402Index(opts.query, limit, opts.signal));
2034
+ if (source === "402index") return safeSearch(() => search402Index(opts.query, limit, filters, opts.signal));
2026
2035
  return Promise.resolve([]);
2027
2036
  })
2028
2037
  );
2029
- return dedupeByResource(results.flat());
2038
+ const merged = applyClientFilters(dedupeByResource(results.flat()), opts);
2039
+ const wantRelevance = opts.query !== void 0 && (_nullishCoalesce(opts.sort, () => ( "relevance"))) === "relevance";
2040
+ if (wantRelevance) return rankResources(merged, opts.query);
2041
+ if (opts.sort && opts.sort !== "relevance") return sortResources(merged, opts.sort, _nullishCoalesce(opts.order, () => ( "desc")));
2042
+ return merged;
2043
+ }
2044
+ function optionalRaw(field, value) {
2045
+ return value !== void 0 ? { [field]: value } : {};
2046
+ }
2047
+ function applyClientFilters(items, opts) {
2048
+ let out = items;
2049
+ if (opts.category) {
2050
+ const want = opts.category.toLowerCase();
2051
+ out = out.filter((r) => r.category !== void 0 && r.category.toLowerCase().startsWith(want));
2052
+ }
2053
+ if (opts.maxPrice !== void 0) {
2054
+ const max = opts.maxPrice;
2055
+ out = out.filter((r) => r.priceUsd === void 0 || r.priceUsd <= max);
2056
+ }
2057
+ if (opts.asset) {
2058
+ const want = opts.asset.toLowerCase();
2059
+ out = out.filter((r) => {
2060
+ const known = r.rails.map((x) => _nullishCoalesce(x.symbol, () => ( x.asset))).filter((a) => !!a);
2061
+ return known.length === 0 || known.some((a) => a.toLowerCase() === want);
2062
+ });
2063
+ }
2064
+ if (opts.minReliability !== void 0) {
2065
+ const min = opts.minReliability;
2066
+ out = out.filter((r) => r.reliabilityScore === void 0 || r.reliabilityScore >= min);
2067
+ }
2068
+ return out;
2069
+ }
2070
+ function tokenize(s) {
2071
+ return _nullishCoalesce((_nullishCoalesce(s, () => ( ""))).toLowerCase().match(/[a-z0-9]+/g), () => ( []));
2072
+ }
2073
+ var FIELD_WEIGHTS = { name: 6, category: 4, tags: 4, path: 3, description: 2 };
2074
+ function fieldTokens(r) {
2075
+ let pathText = r.resource;
2076
+ try {
2077
+ const u = new URL(r.resource);
2078
+ pathText = `${u.hostname} ${u.pathname}`;
2079
+ } catch (e22) {
2080
+ }
2081
+ return [
2082
+ [tokenize(r.name), FIELD_WEIGHTS.name],
2083
+ [tokenize(r.category), FIELD_WEIGHTS.category],
2084
+ [tokenize((_nullishCoalesce(r.tags, () => ( []))).join(" ")), FIELD_WEIGHTS.tags],
2085
+ [tokenize(pathText), FIELD_WEIGHTS.path],
2086
+ [tokenize(r.description), FIELD_WEIGHTS.description]
2087
+ ];
2088
+ }
2089
+ function scoreResource(r, queryTokens) {
2090
+ if (queryTokens.length === 0) return 0;
2091
+ const fields = fieldTokens(r);
2092
+ let score = 0;
2093
+ let matched = 0;
2094
+ for (const qt of queryTokens) {
2095
+ let hit = false;
2096
+ for (const [toks, w] of fields) {
2097
+ if (toks.includes(qt)) {
2098
+ score += w;
2099
+ hit = true;
2100
+ } else if (qt.length >= 4 && toks.some((t) => t.startsWith(qt) || t.length >= 4 && qt.startsWith(t))) {
2101
+ score += w * 0.4;
2102
+ hit = true;
2103
+ }
2104
+ }
2105
+ if (hit) matched++;
2106
+ }
2107
+ if (matched === 0) return 0;
2108
+ if (matched === queryTokens.length) score += 8;
2109
+ if (r.reliabilityScore !== void 0) score += r.reliabilityScore / 1e3;
2110
+ return score;
2111
+ }
2112
+ function rankResources(items, query) {
2113
+ const qTokens = tokenize(query);
2114
+ if (qTokens.length === 0) return items;
2115
+ return items.map((r, i) => ({ r, i, s: scoreResource(r, qTokens) })).filter((x) => x.s > 0).sort((a, b) => b.s - a.s || a.i - b.i).map((x) => ({ ...x.r, score: x.s }));
2116
+ }
2117
+ function sortResources(items, sort, order) {
2118
+ const dir = order === "asc" ? 1 : -1;
2119
+ const key = (r) => sort === "reliability" || sort === "uptime" ? r.reliabilityScore : sort === "price" ? r.priceUsd : sort === "name" ? (_nullishCoalesce(r.name, () => ( r.resource))).toLowerCase() : void 0;
2120
+ return items.map((r, i) => ({ r, i })).sort((a, b) => {
2121
+ const ka = key(a.r);
2122
+ const kb = key(b.r);
2123
+ if (ka === void 0 && kb === void 0) return a.i - b.i;
2124
+ if (ka === void 0) return 1;
2125
+ if (kb === void 0) return -1;
2126
+ if (ka < kb) return -1 * dir;
2127
+ if (ka > kb) return 1 * dir;
2128
+ return a.i - b.i;
2129
+ }).map((x) => x.r);
2030
2130
  }
2031
2131
  async function safeSearch(run) {
2032
2132
  try {
2033
2133
  return await run();
2034
- } catch (e22) {
2134
+ } catch (e23) {
2035
2135
  return [];
2036
2136
  }
2037
2137
  }
@@ -2072,9 +2172,24 @@ function mapBazaarItem(raw) {
2072
2172
  ...optionalString("category", pickString(meta, "category"))
2073
2173
  };
2074
2174
  }
2075
- async function search402Index(query, limit, signal) {
2175
+ async function search402Index(query, limit, filters, signal) {
2176
+ const tokens = tokenize(query);
2177
+ const queries = query && tokens.length > 1 ? [.../* @__PURE__ */ new Set([query, ...tokens])].slice(0, 5) : [query];
2178
+ const pages = await Promise.all(queries.map((q) => safeSearch(() => fetch402Page(q, limit, filters, signal))));
2179
+ return dedupeByResource(pages.flat());
2180
+ }
2181
+ async function fetch402Page(query, limit, filters, signal) {
2076
2182
  const qs = new URLSearchParams({ limit: String(limit) });
2077
2183
  if (query) qs.set("q", query);
2184
+ if (filters.category) qs.set("category", filters.category);
2185
+ if (filters.asset) qs.set("payment_asset", filters.asset);
2186
+ if (filters.maxPrice !== void 0) qs.set("max_price_usd", String(filters.maxPrice));
2187
+ if (filters.verified) qs.set("verified", "true");
2188
+ if (filters.paymentValid) qs.set("payment_valid", "true");
2189
+ if (filters.sort && filters.sort !== "relevance") {
2190
+ qs.set("sort", filters.sort);
2191
+ qs.set("order", _nullishCoalesce(filters.order, () => ( "desc")));
2192
+ }
2078
2193
  const res = await fetch(`${INDEX402_SEARCH}?${qs.toString()}`, {
2079
2194
  headers: clientHeaders({ accept: "application/json" }),
2080
2195
  ...signal ? { signal } : {}
@@ -2093,16 +2208,26 @@ function map402IndexItem(raw) {
2093
2208
  if (protocol !== "x402") return null;
2094
2209
  const rails = Array.isArray(o.accepts) ? mapRails(o.accepts) : railFrom402IndexFields(o);
2095
2210
  const priceUsd = pickNumber(o, "price_usd", "priceUsd", "price");
2211
+ const reliabilityScore = pickNumber(o, "reliability_score", "reliabilityScore");
2212
+ const tags = pickStringArray(o, "tags", "keywords");
2096
2213
  return {
2097
2214
  resource,
2098
2215
  source: "402index",
2099
2216
  rails,
2100
2217
  ...priceUsd !== void 0 ? { priceUsd } : {},
2218
+ ...reliabilityScore !== void 0 ? { reliabilityScore } : {},
2219
+ ...tags ? { tags } : {},
2101
2220
  ...optionalString("name", pickString(o, "name", "title")),
2102
2221
  ...optionalString("description", pickString(o, "description")),
2103
- ...optionalString("category", pickString(o, "category", "tag"))
2222
+ ...optionalString("category", pickString(o, "category", "tag")),
2223
+ ...optionalString("health", pickString(o, "health_status", "health")),
2224
+ // 402 Index reports domain_verified as 0/1; surface a boolean only when the field is present.
2225
+ ...o.domain_verified !== void 0 || o.verified !== void 0 ? { verified: isTruthyFlag(o.domain_verified) || isTruthyFlag(o.verified) } : {}
2104
2226
  };
2105
2227
  }
2228
+ function isTruthyFlag(v) {
2229
+ return v === 1 || v === true || v === "1" || v === "true";
2230
+ }
2106
2231
  function railFrom402IndexFields(o) {
2107
2232
  const network = pickString(o, "payment_network", "network");
2108
2233
  const asset = pickString(o, "payment_asset", "asset", "token");
@@ -2119,7 +2244,8 @@ function railFrom402IndexFields(o) {
2119
2244
  async function register402Index(input) {
2120
2245
  try {
2121
2246
  const attributionOn = input.attribution !== false;
2122
- const description = attributionOn ? appendAttribution(input.description) : input.description;
2247
+ const withTags = appendKeywords(input.description, input.tags);
2248
+ const description = attributionOn ? appendAttribution(withTags) : withTags;
2123
2249
  const payload = {
2124
2250
  url: input.url,
2125
2251
  name: _nullishCoalesce(input.name, () => ( hostOf(input.url))),
@@ -2129,6 +2255,11 @@ async function register402Index(input) {
2129
2255
  ...input.asset ? { payment_asset: input.asset } : {},
2130
2256
  ...input.network ? { payment_network: input.network } : {},
2131
2257
  ...input.method ? { http_method: input.method.toUpperCase() } : {},
2258
+ ...input.category ? { category: input.category } : {},
2259
+ ...input.tags && input.tags.length > 0 ? { tags: input.tags } : {},
2260
+ ...input.provider ? { provider: input.provider } : {},
2261
+ ...input.contactEmail ? { contact_email: input.contactEmail } : {},
2262
+ ...input.probeBody !== void 0 ? { probe_body: input.probeBody } : {},
2132
2263
  ...attributionOn ? { via: "@piprail/sdk" } : {}
2133
2264
  };
2134
2265
  const res = await fetch(INDEX402_REGISTER, {
@@ -2166,7 +2297,7 @@ async function readIndexError(res) {
2166
2297
  (p) => typeof p === "string" && p.length > 0
2167
2298
  );
2168
2299
  return parts.length ? [...new Set(parts)].join(" \u2014 ") : void 0;
2169
- } catch (e23) {
2300
+ } catch (e24) {
2170
2301
  return void 0;
2171
2302
  }
2172
2303
  }
@@ -2288,7 +2419,7 @@ async function readSiwxInfo(res) {
2288
2419
  return info;
2289
2420
  }
2290
2421
  return null;
2291
- } catch (e24) {
2422
+ } catch (e25) {
2292
2423
  return null;
2293
2424
  }
2294
2425
  }
@@ -2335,8 +2466,24 @@ function mapRails(accepts) {
2335
2466
  return out;
2336
2467
  }
2337
2468
  function matchesQuery(r, query) {
2338
- const q = query.toLowerCase();
2339
- return r.resource.toLowerCase().includes(q) || (_nullishCoalesce(_optionalChain([r, 'access', _18 => _18.name, 'optionalAccess', _19 => _19.toLowerCase, 'call', _20 => _20(), 'access', _21 => _21.includes, 'call', _22 => _22(q)]), () => ( false))) || (_nullishCoalesce(_optionalChain([r, 'access', _23 => _23.description, 'optionalAccess', _24 => _24.toLowerCase, 'call', _25 => _25(), 'access', _26 => _26.includes, 'call', _27 => _27(q)]), () => ( false)));
2469
+ const haystack = [r.name, r.description, r.category, (_nullishCoalesce(r.tags, () => ( []))).join(" "), r.resource].filter(Boolean).join(" ").toLowerCase();
2470
+ if (haystack.includes(query.toLowerCase())) return true;
2471
+ const qTokens = tokenize(query);
2472
+ const hayTokens = new Set(tokenize(haystack));
2473
+ return qTokens.some((t) => hayTokens.has(t));
2474
+ }
2475
+ function pickStringArray(o, ...keys) {
2476
+ for (const k of keys) {
2477
+ const v = o[k];
2478
+ if (Array.isArray(v)) {
2479
+ const arr = v.filter((x) => typeof x === "string" && x.length > 0);
2480
+ if (arr.length) return arr;
2481
+ } else if (typeof v === "string" && v.trim()) {
2482
+ const arr = v.split(/[,\s]+/).filter((x) => x.length > 0);
2483
+ if (arr.length) return arr;
2484
+ }
2485
+ }
2486
+ return void 0;
2340
2487
  }
2341
2488
  function pickString(o, ...keys) {
2342
2489
  for (const k of keys) {
@@ -2369,7 +2516,7 @@ function hostOf(url) {
2369
2516
  try {
2370
2517
  const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`;
2371
2518
  return new URL(withScheme).hostname || url;
2372
- } catch (e25) {
2519
+ } catch (e26) {
2373
2520
  return url;
2374
2521
  }
2375
2522
  }
@@ -2383,6 +2530,17 @@ function appendAttribution(description) {
2383
2530
  const next = `${description.trimEnd()} ${REGISTER_ATTRIBUTION}`;
2384
2531
  return next.length <= 500 ? next : description;
2385
2532
  }
2533
+ function appendKeywords(description, tags) {
2534
+ const clean = (_nullishCoalesce(tags, () => ( []))).map((t) => t.trim()).filter((t) => t.length > 0);
2535
+ if (clean.length === 0) return description;
2536
+ const have = (_nullishCoalesce(description, () => ( ""))).toLowerCase();
2537
+ const fresh = [...new Set(clean.filter((t) => !have.includes(t.toLowerCase())))];
2538
+ if (fresh.length === 0) return description;
2539
+ const tail = `Keywords: ${fresh.join(", ")}`;
2540
+ if (!description) return tail;
2541
+ const next = `${description.trimEnd()} \xB7 ${tail}`;
2542
+ return next.length <= 500 ? next : description;
2543
+ }
2386
2544
  function encodeBase642(str) {
2387
2545
  if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
2388
2546
  if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
@@ -2524,7 +2682,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
2524
2682
  }
2525
2683
  /** Running total (base units) already spent on this (network, asset). */
2526
2684
  totalFor(network, asset) {
2527
- return _nullishCoalesce(_optionalChain([this, 'access', _28 => _28.buckets, 'access', _29 => _29.get, 'call', _30 => _30(keyFor(network, asset)), 'optionalAccess', _31 => _31.total]), () => ( 0n));
2685
+ return _nullishCoalesce(_optionalChain([this, 'access', _18 => _18.buckets, 'access', _19 => _19.get, 'call', _20 => _20(keyFor(network, asset)), 'optionalAccess', _21 => _21.total]), () => ( 0n));
2528
2686
  }
2529
2687
  /**
2530
2688
  * Sum of base-unit amounts for (network, asset) whose record `at` (ISO
@@ -2658,7 +2816,7 @@ var PipRailClient = (_class2 = class {
2658
2816
  safeEmit(event) {
2659
2817
  try {
2660
2818
  this.onEvent(event);
2661
- } catch (e26) {
2819
+ } catch (e27) {
2662
2820
  }
2663
2821
  }
2664
2822
  /** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
@@ -2688,7 +2846,7 @@ var PipRailClient = (_class2 = class {
2688
2846
  * as-is) or a plain object (serialised as JSON).
2689
2847
  */
2690
2848
  post(url, body, init) {
2691
- const headers = new Headers(_optionalChain([init, 'optionalAccess', _32 => _32.headers]));
2849
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _22 => _22.headers]));
2692
2850
  let payload;
2693
2851
  if (body === void 0 || body === null) {
2694
2852
  payload = void 0;
@@ -2719,7 +2877,7 @@ var PipRailClient = (_class2 = class {
2719
2877
  * "0.05 USDC on Base, within budget → pay it." No funds move.
2720
2878
  */
2721
2879
  async quote(url, init) {
2722
- const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _33 => _33.method]), () => ( "GET")) });
2880
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _23 => _23.method]), () => ( "GET")) });
2723
2881
  if (res.status !== 402) return null;
2724
2882
  const { quote } = await this.resolveChallenge(url, res, this.resolveSchemes());
2725
2883
  return quote;
@@ -2738,7 +2896,7 @@ var PipRailClient = (_class2 = class {
2738
2896
  * on Tron, where a USD₮ transfer can cost real TRX.
2739
2897
  */
2740
2898
  async estimateCost(url, init) {
2741
- const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _34 => _34.method]), () => ( "GET")) });
2899
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _24 => _24.method]), () => ( "GET")) });
2742
2900
  if (res.status !== 402) return null;
2743
2901
  const { net, accept, quote } = await this.resolveChallenge(url, res, this.resolveSchemes());
2744
2902
  const cost = await net.estimateCost(accept);
@@ -2761,8 +2919,8 @@ var PipRailClient = (_class2 = class {
2761
2919
  return {
2762
2920
  session: {
2763
2921
  start,
2764
- expiresAt: _optionalChain([view, 'optionalAccess', _35 => _35.expiresAt]) != null ? new Date(view.expiresAt).toISOString() : null,
2765
- secondsRemaining: _nullishCoalesce(_optionalChain([view, 'optionalAccess', _36 => _36.secondsRemaining]), () => ( null))
2922
+ expiresAt: _optionalChain([view, 'optionalAccess', _25 => _25.expiresAt]) != null ? new Date(view.expiresAt).toISOString() : null,
2923
+ secondsRemaining: _nullishCoalesce(_optionalChain([view, 'optionalAccess', _26 => _26.secondsRemaining]), () => ( null))
2766
2924
  },
2767
2925
  byAsset: this.remaining()
2768
2926
  };
@@ -2775,7 +2933,7 @@ var PipRailClient = (_class2 = class {
2775
2933
  * never throws, never sums across tokens (no price oracle). PROCESS-SCOPED.
2776
2934
  */
2777
2935
  remaining() {
2778
- const maxTotal = _optionalChain([this, 'access', _37 => _37.opts, 'access', _38 => _38.policy, 'optionalAccess', _39 => _39.maxTotal]);
2936
+ const maxTotal = _optionalChain([this, 'access', _27 => _27.opts, 'access', _28 => _28.policy, 'optionalAccess', _29 => _29.maxTotal]);
2779
2937
  return this.ledger.assetBuckets().map((b) => {
2780
2938
  const base2 = {
2781
2939
  network: b.network,
@@ -2827,7 +2985,7 @@ var PipRailClient = (_class2 = class {
2827
2985
  * the plan yourself. No funds move.
2828
2986
  */
2829
2987
  async planPayment(url, init) {
2830
- const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _40 => _40.method]), () => ( "GET")) });
2988
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _30 => _30.method]), () => ( "GET")) });
2831
2989
  if (res.status !== 402) return null;
2832
2990
  const challenge = await parseChallenge(res);
2833
2991
  if (!challenge) {
@@ -2874,22 +3032,24 @@ var PipRailClient = (_class2 = class {
2874
3032
  const found = await searchOpenIndexes({
2875
3033
  ...opts.query !== void 0 ? { query: opts.query } : {},
2876
3034
  ...opts.sources ? { sources: opts.sources } : {},
2877
- ...opts.limit !== void 0 ? { limit: opts.limit } : {}
3035
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {},
3036
+ ...opts.maxPrice !== void 0 ? { maxPrice: opts.maxPrice } : {},
3037
+ ...opts.category ? { category: opts.category } : {},
3038
+ ...opts.asset ? { asset: opts.asset } : {},
3039
+ ...opts.minReliability !== void 0 ? { minReliability: opts.minReliability } : {},
3040
+ ...opts.verified !== void 0 ? { verified: opts.verified } : {},
3041
+ ...opts.paymentValid !== void 0 ? { paymentValid: opts.paymentValid } : {},
3042
+ ...opts.sort ? { sort: opts.sort } : {},
3043
+ ...opts.order ? { order: opts.order } : {}
2878
3044
  });
2879
3045
  const scope = _nullishCoalesce(opts.network, () => ( "self"));
2880
- let out = found;
3046
+ if (scope === "any") return found;
2881
3047
  if (scope === "self") {
2882
3048
  const { net } = await this.ensure();
2883
- out = out.filter((r) => r.rails.some((rail) => railOnNetwork(rail, (n) => net.supports(n))));
2884
- } else if (scope !== "any") {
2885
- const target = normalizeNetwork(scope);
2886
- out = out.filter((r) => r.rails.some((rail) => railOnNetwork(rail, (n) => n === target)));
2887
- }
2888
- if (opts.maxPrice !== void 0) {
2889
- const max = opts.maxPrice;
2890
- out = out.filter((r) => r.priceUsd === void 0 || r.priceUsd <= max);
3049
+ return found.filter((r) => r.rails.some((rail) => railOnNetwork(rail, (n) => net.supports(n))));
2891
3050
  }
2892
- return out;
3051
+ const target = normalizeNetwork(scope);
3052
+ return found.filter((r) => r.rails.some((rail) => railOnNetwork(rail, (n) => n === target)));
2893
3053
  }
2894
3054
  /**
2895
3055
  * List a resource you run on the OPEN x402 registries, so agents can find it.
@@ -2930,6 +3090,11 @@ var PipRailClient = (_class2 = class {
2930
3090
  ...opts.asset ? { asset: opts.asset } : {},
2931
3091
  ...networkSlug ? { network: networkSlug } : {},
2932
3092
  ...opts.method ? { method: opts.method } : {},
3093
+ ...opts.category ? { category: opts.category } : {},
3094
+ ...opts.tags ? { tags: opts.tags } : {},
3095
+ ...opts.provider ? { provider: opts.provider } : {},
3096
+ ...opts.contactEmail ? { contactEmail: opts.contactEmail } : {},
3097
+ ...opts.probeBody !== void 0 ? { probeBody: opts.probeBody } : {},
2933
3098
  // Attribution is default-ON; forward an explicit opt-out, else let register402Index default it.
2934
3099
  ...opts.attribution === false ? { attribution: false } : {}
2935
3100
  })
@@ -3001,7 +3166,7 @@ var PipRailClient = (_class2 = class {
3001
3166
  * streams throw `NonReplayableBodyError`.
3002
3167
  */
3003
3168
  async fetch(url, init) {
3004
- const body = _optionalChain([init, 'optionalAccess', _41 => _41.body]);
3169
+ const body = _optionalChain([init, 'optionalAccess', _31 => _31.body]);
3005
3170
  if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
3006
3171
  throw new (0, _chunkJG6KRAW6cjs.NonReplayableBodyError)(
3007
3172
  "fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
@@ -3009,7 +3174,7 @@ var PipRailClient = (_class2 = class {
3009
3174
  }
3010
3175
  const firstResponse = await fetch(url, init);
3011
3176
  if (firstResponse.status !== 402) return firstResponse;
3012
- const schemes = this.resolveSchemes(_optionalChain([init, 'optionalAccess', _42 => _42.schemes]));
3177
+ const schemes = this.resolveSchemes(_optionalChain([init, 'optionalAccess', _32 => _32.schemes]));
3013
3178
  const resolved = await this.resolveChallenge(url, firstResponse, schemes);
3014
3179
  const { net, wallet, challenge } = resolved;
3015
3180
  if (!wallet) {
@@ -3019,7 +3184,7 @@ var PipRailClient = (_class2 = class {
3019
3184
  }
3020
3185
  let accept = resolved.accept;
3021
3186
  let quote = resolved.quote;
3022
- const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _43 => _43.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
3187
+ const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _33 => _33.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
3023
3188
  if (autoRoute) {
3024
3189
  const plan = await this.planFromChallenge(net, wallet, challenge, url, schemes);
3025
3190
  if (!plan.best) {
@@ -3237,13 +3402,13 @@ var PipRailClient = (_class2 = class {
3237
3402
  }
3238
3403
  const amountBase = BigInt(accept.amount);
3239
3404
  const described = net.describeAsset(accept.asset);
3240
- const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _44 => _44.decimals]), () => ( _optionalChain([accept, 'access', _45 => _45.extra, 'optionalAccess', _46 => _46.decimals])));
3405
+ const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _34 => _34.decimals]), () => ( _optionalChain([accept, 'access', _35 => _35.extra, 'optionalAccess', _36 => _36.decimals])));
3241
3406
  if (typeof decimals !== "number" || !Number.isInteger(decimals) || decimals < 0) {
3242
3407
  throw new (0, _chunkJG6KRAW6cjs.InvalidEnvelopeError)(
3243
3408
  `challenge for ${accept.asset} on ${accept.network} states no valid decimals and the SDK doesn't recognise the token \u2014 refusing to price it.`
3244
3409
  );
3245
3410
  }
3246
- const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _47 => _47.symbol]), () => ( _optionalChain([accept, 'access', _48 => _48.extra, 'optionalAccess', _49 => _49.symbol])));
3411
+ const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _37 => _37.symbol]), () => ( _optionalChain([accept, 'access', _38 => _38.extra, 'optionalAccess', _39 => _39.symbol])));
3247
3412
  const amountFormatted = _chunkJG6KRAW6cjs.formatUnits.call(void 0, amountBase, decimals);
3248
3413
  const intent = {
3249
3414
  host: hostOf2(url),
@@ -3275,7 +3440,7 @@ var PipRailClient = (_class2 = class {
3275
3440
  this.ledger.totalFor(accept.network, accept.asset),
3276
3441
  ctx
3277
3442
  );
3278
- const serverSymbol = _optionalChain([accept, 'access', _50 => _50.extra, 'optionalAccess', _51 => _51.symbol]);
3443
+ const serverSymbol = _optionalChain([accept, 'access', _40 => _40.extra, 'optionalAccess', _41 => _41.symbol]);
3279
3444
  const symbolMismatch = intent.recognized && !!serverSymbol && !!symbol && serverSymbol.toUpperCase() !== symbol.toUpperCase();
3280
3445
  return {
3281
3446
  url,
@@ -3351,7 +3516,7 @@ var PipRailClient = (_class2 = class {
3351
3516
  const ref = await net.send(wallet, accept);
3352
3517
  this.safeEmit({ kind: "payment-broadcast", ref });
3353
3518
  try {
3354
- const { height } = await net.confirm(ref, _nullishCoalesce(_optionalChain([accept, 'access', _52 => _52.extra, 'optionalAccess', _53 => _53.minConfirmations]), () => ( 1)));
3519
+ const { height } = await net.confirm(ref, _nullishCoalesce(_optionalChain([accept, 'access', _42 => _42.extra, 'optionalAccess', _43 => _43.minConfirmations]), () => ( 1)));
3355
3520
  this.safeEmit({
3356
3521
  kind: "payment-confirmed",
3357
3522
  ref,
@@ -3371,9 +3536,9 @@ var PipRailClient = (_class2 = class {
3371
3536
  const signature = {
3372
3537
  x402Version: 2,
3373
3538
  accepted: accept,
3374
- payload: { nonce: _optionalChain([accept, 'access', _54 => _54.extra, 'optionalAccess', _55 => _55.nonce]), txHash: ref }
3539
+ payload: { nonce: _optionalChain([accept, 'access', _44 => _44.extra, 'optionalAccess', _45 => _45.nonce]), txHash: ref }
3375
3540
  };
3376
- const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _56 => _56.headers]));
3541
+ const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _46 => _46.headers]));
3377
3542
  headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
3378
3543
  let lastResponse = null;
3379
3544
  let lastReason = null;
@@ -3388,7 +3553,7 @@ var PipRailClient = (_class2 = class {
3388
3553
  () => timeoutController.abort(),
3389
3554
  this.retryTimeoutMs
3390
3555
  );
3391
- const signal = _optionalChain([originalInit, 'optionalAccess', _57 => _57.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
3556
+ const signal = _optionalChain([originalInit, 'optionalAccess', _47 => _47.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
3392
3557
  try {
3393
3558
  lastResponse = await fetch(url, {
3394
3559
  ..._nullishCoalesce(originalInit, () => ( {})),
@@ -3447,9 +3612,9 @@ var PipRailClient = (_class2 = class {
3447
3612
  `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM + Solana today).`
3448
3613
  );
3449
3614
  }
3450
- throwIfAborted(_optionalChain([init, 'optionalAccess', _58 => _58.signal]));
3615
+ throwIfAborted(_optionalChain([init, 'optionalAccess', _48 => _48.signal]));
3451
3616
  const { payload, accepted, payerFrom, nonce } = await net.payExact(wallet, accept);
3452
- const headers = new Headers(_optionalChain([init, 'optionalAccess', _59 => _59.headers]));
3617
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _49 => _49.headers]));
3453
3618
  headers.set(HEADER_SIGNATURE, buildExactSignatureHeader({ accepted, payload }));
3454
3619
  const rejectDefinitive = (why2) => {
3455
3620
  this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})` });
@@ -3466,12 +3631,12 @@ var PipRailClient = (_class2 = class {
3466
3631
  if (Date.now() >= deadline) break;
3467
3632
  await new Promise((r) => setTimeout(r, Math.min(2e3, 400 * 2 ** (attempt - 1))));
3468
3633
  }
3469
- throwIfAborted(_optionalChain([init, 'optionalAccess', _60 => _60.signal]));
3634
+ throwIfAborted(_optionalChain([init, 'optionalAccess', _50 => _50.signal]));
3470
3635
  const budget = Math.min(this.retryTimeoutMs, deadline - Date.now());
3471
3636
  if (budget <= 0) break;
3472
3637
  const timeoutController = new AbortController();
3473
3638
  const timeoutId = setTimeout(() => timeoutController.abort(), budget);
3474
- const signal = _optionalChain([init, 'optionalAccess', _61 => _61.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, init.signal]) : timeoutController.signal;
3639
+ const signal = _optionalChain([init, 'optionalAccess', _51 => _51.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, init.signal]) : timeoutController.signal;
3475
3640
  let response;
3476
3641
  try {
3477
3642
  response = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), headers, signal });
@@ -3492,7 +3657,7 @@ var PipRailClient = (_class2 = class {
3492
3657
  if (response.ok && !(settle && settle.success === false)) {
3493
3658
  const receipt = parseReceipt(response);
3494
3659
  this.safeEmit({ kind: "payment-settled", receipt, ...settle ? { settle } : {} });
3495
- const ref = _optionalChain([settle, 'optionalAccess', _62 => _62.transaction]) || _optionalChain([receipt, 'optionalAccess', _63 => _63.transaction]) || `eip3009-nonce:${nonce}`;
3660
+ const ref = _optionalChain([settle, 'optionalAccess', _52 => _52.transaction]) || _optionalChain([receipt, 'optionalAccess', _53 => _53.transaction]) || `eip3009-nonce:${nonce}`;
3496
3661
  this.recordSpend(quote, ref);
3497
3662
  return response;
3498
3663
  }
@@ -3516,14 +3681,14 @@ var PipRailClient = (_class2 = class {
3516
3681
  }
3517
3682
  }, _class2);
3518
3683
  function throwIfAborted(signal) {
3519
- if (_optionalChain([signal, 'optionalAccess', _64 => _64.aborted])) {
3684
+ if (_optionalChain([signal, 'optionalAccess', _54 => _54.aborted])) {
3520
3685
  throw _nullishCoalesce(signal.reason, () => ( new DOMException("This operation was aborted.", "AbortError")));
3521
3686
  }
3522
3687
  }
3523
3688
  function safeBig(s) {
3524
3689
  try {
3525
3690
  return BigInt(s);
3526
- } catch (e27) {
3691
+ } catch (e28) {
3527
3692
  return 0n;
3528
3693
  }
3529
3694
  }
@@ -3586,10 +3751,10 @@ function buildFundingHint(options, chainLabel) {
3586
3751
  return `Couldn't fully read your wallet on ${chainLabel} (RPC throttled) \u2014 retry; you may already be able to pay ${target.quote.amountFormatted} ${sym}.`;
3587
3752
  }
3588
3753
  const parts = [];
3589
- if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _65 => _65.shortfall, 'optionalAccess', _66 => _66.token])) {
3754
+ if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _55 => _55.shortfall, 'optionalAccess', _56 => _56.token])) {
3590
3755
  parts.push(`top up ${target.shortfall.token} ${sym}`);
3591
3756
  }
3592
- if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _67 => _67.shortfall, 'optionalAccess', _68 => _68.native])) {
3757
+ if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _57 => _57.shortfall, 'optionalAccess', _58 => _58.native])) {
3593
3758
  parts.push(`add ~${target.shortfall.native} ${target.cost.feeSymbol} for gas`);
3594
3759
  }
3595
3760
  return parts.length ? `Can't settle on ${chainLabel}: ${parts.join(" and ")} (to pay ${target.quote.amountFormatted} ${sym}).` : `Can't settle on ${chainLabel} for ${target.quote.amountFormatted} ${sym}.`;
@@ -3603,7 +3768,7 @@ async function planAcross(clients, url, init) {
3603
3768
  const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
3604
3769
  return {
3605
3770
  url,
3606
- network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _69 => _69.accept, 'access', _70 => _70.network]), () => ( live[0].network)),
3771
+ network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _59 => _59.accept, 'access', _60 => _60.network]), () => ( live[0].network)),
3607
3772
  status,
3608
3773
  payable: best !== null,
3609
3774
  best,
@@ -3648,7 +3813,7 @@ function reasonCodeForPolicy(code) {
3648
3813
  function hostOf2(url) {
3649
3814
  try {
3650
3815
  return new URL(url).hostname;
3651
- } catch (e28) {
3816
+ } catch (e29) {
3652
3817
  return url;
3653
3818
  }
3654
3819
  }
@@ -3665,8 +3830,8 @@ function isReplayableBodyInit(value) {
3665
3830
  async function readInvalidReason(response) {
3666
3831
  try {
3667
3832
  const body = await response.clone().json();
3668
- const ext = _optionalChain([body, 'optionalAccess', _71 => _71.extensions]);
3669
- const piprail = _optionalChain([ext, 'optionalAccess', _72 => _72.piprail]);
3833
+ const ext = _optionalChain([body, 'optionalAccess', _61 => _61.extensions]);
3834
+ const piprail = _optionalChain([ext, 'optionalAccess', _62 => _62.piprail]);
3670
3835
  if (piprail && typeof piprail.code === "string") {
3671
3836
  return {
3672
3837
  error: piprail.code,
@@ -3685,10 +3850,10 @@ async function readInvalidReason(response) {
3685
3850
  detail: typeof body.invalidMessage === "string" ? body.invalidMessage : ""
3686
3851
  };
3687
3852
  }
3688
- } catch (e29) {
3853
+ } catch (e30) {
3689
3854
  }
3690
3855
  const settle = parseSettleResponse(response);
3691
- if (_optionalChain([settle, 'optionalAccess', _73 => _73.errorReason])) return { error: settle.errorReason, detail: "" };
3856
+ if (_optionalChain([settle, 'optionalAccess', _63 => _63.errorReason])) return { error: settle.errorReason, detail: "" };
3692
3857
  return null;
3693
3858
  }
3694
3859
 
@@ -3738,7 +3903,7 @@ var MultiChainPayer = class _MultiChainPayer {
3738
3903
  wallet,
3739
3904
  ...opts.policy ? { policy: opts.policy } : {},
3740
3905
  ...opts.schemes ? { schemes: opts.schemes } : {},
3741
- ..._optionalChain([opts, 'access', _74 => _74.rpcUrls, 'optionalAccess', _75 => _75[chain]]) ? { rpcUrl: opts.rpcUrls[chain] } : {},
3906
+ ..._optionalChain([opts, 'access', _64 => _64.rpcUrls, 'optionalAccess', _65 => _65[chain]]) ? { rpcUrl: opts.rpcUrls[chain] } : {},
3742
3907
  ...opts.onBeforePay ? { onBeforePay: opts.onBeforePay } : {},
3743
3908
  ...opts.onEvent ? { onEvent: opts.onEvent } : {},
3744
3909
  ...opts.maxPaymentRetries != null ? { maxPaymentRetries: opts.maxPaymentRetries } : {},
@@ -3796,7 +3961,7 @@ var MultiChainPayer = class _MultiChainPayer {
3796
3961
  * {@link PipRailClient.post}.
3797
3962
  */
3798
3963
  post(url, body, init) {
3799
- const headers = new Headers(_optionalChain([init, 'optionalAccess', _76 => _76.headers]));
3964
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _66 => _66.headers]));
3800
3965
  let payload;
3801
3966
  if (body === void 0 || body === null) {
3802
3967
  payload = void 0;
@@ -3906,6 +4071,7 @@ function buildSelfDescription(input) {
3906
4071
  protocol: "x402",
3907
4072
  version: "2",
3908
4073
  what: WHAT,
4074
+ ...input.endpoint && Object.keys(input.endpoint).length > 0 ? { endpoint: input.endpoint } : {},
3909
4075
  pay: input.accepts.map(railOf),
3910
4076
  sdk: { install: BRAND.sdkInstall, snippet: BRAND.sdkSnippet },
3911
4077
  mcp: { run: BRAND.mcpRun, tool: "piprail_pay_request" },
@@ -3914,6 +4080,19 @@ function buildSelfDescription(input) {
3914
4080
  ...input.instruction ? { instruction: input.instruction } : {}
3915
4081
  };
3916
4082
  }
4083
+ function buildEndpointInfo(input) {
4084
+ const d = input.descriptor;
4085
+ const summary = _nullishCoalesce(_optionalChain([d, 'optionalAccess', _67 => _67.summary]), () => ( input.description));
4086
+ const hasInput = _optionalChain([d, 'optionalAccess', _68 => _68.queryParams]) && Object.keys(d.queryParams).length > 0;
4087
+ const endpoint = {
4088
+ ...summary ? { summary } : {},
4089
+ ..._optionalChain([d, 'optionalAccess', _69 => _69.method]) ? { method: d.method.toUpperCase() } : {},
4090
+ ...input.mimeType ? { mimeType: input.mimeType } : {},
4091
+ ...hasInput ? { input: d.queryParams } : {},
4092
+ ..._optionalChain([d, 'optionalAccess', _70 => _70.output]) ? { output: d.output } : {}
4093
+ };
4094
+ return Object.keys(endpoint).length > 0 ? endpoint : void 0;
4095
+ }
3917
4096
 
3918
4097
  // src/render.ts
3919
4098
  function summarizePlan(plan) {
@@ -4060,7 +4239,7 @@ async function readBody(res) {
4060
4239
  if (!text) return null;
4061
4240
  try {
4062
4241
  return JSON.parse(text);
4063
- } catch (e30) {
4242
+ } catch (e31) {
4064
4243
  return text;
4065
4244
  }
4066
4245
  }
@@ -4095,13 +4274,25 @@ function paymentTools(client) {
4095
4274
  parameters: {
4096
4275
  type: "object",
4097
4276
  properties: {
4098
- query: { type: "string", description: "Free-text topic to search for (optional)." },
4277
+ query: {
4278
+ type: "string",
4279
+ description: 'Free-text topic to search for (optional). Multi-word queries are fanned out per word and results are ranked by relevance, so "crypto price feed" finds the best matches even when no single listing contains that exact phrase.'
4280
+ },
4099
4281
  network: {
4100
4282
  type: "string",
4101
4283
  description: "CAIP-2 id, 'self' (your chain \u2014 default), or 'any' (all chains)."
4102
4284
  },
4285
+ category: { type: "string", description: "Keep ONLY this category, e.g. 'ai', 'finance', 'data' (strict)." },
4286
+ asset: { type: "string", description: "Keep only resources paying in this token symbol, e.g. 'USDC'." },
4103
4287
  maxPrice: { type: "number", description: "Drop results advertised above this USD price." },
4104
- limit: { type: "number", description: "Max results per index (default 20)." }
4288
+ minReliability: { type: "number", description: "Drop results below this health score (0\u2013100); unscored pass." },
4289
+ verified: { type: "boolean", description: "Prefer verified listings (402 Index)." },
4290
+ sort: {
4291
+ type: "string",
4292
+ enum: ["relevance", "reliability", "price", "uptime", "name"],
4293
+ description: "Ordering. Default 'relevance' with a query, else first-seen."
4294
+ },
4295
+ limit: { type: "number", description: "Max results to fetch per index (default 20)." }
4105
4296
  },
4106
4297
  additionalProperties: false
4107
4298
  },
@@ -4110,7 +4301,12 @@ function paymentTools(client) {
4110
4301
  const opts = {};
4111
4302
  if (typeof args.query === "string") opts.query = args.query;
4112
4303
  if (typeof args.network === "string") opts.network = args.network;
4304
+ if (typeof args.category === "string") opts.category = args.category;
4305
+ if (typeof args.asset === "string") opts.asset = args.asset;
4113
4306
  if (typeof args.maxPrice === "number") opts.maxPrice = args.maxPrice;
4307
+ if (typeof args.minReliability === "number") opts.minReliability = args.minReliability;
4308
+ if (typeof args.verified === "boolean") opts.verified = args.verified;
4309
+ if (typeof args.sort === "string") opts.sort = args.sort;
4114
4310
  if (typeof args.limit === "number") opts.limit = args.limit;
4115
4311
  const found = await client.discover(opts);
4116
4312
  return {
@@ -4120,7 +4316,11 @@ function paymentTools(client) {
4120
4316
  name: r.name,
4121
4317
  description: r.description,
4122
4318
  source: r.source,
4319
+ category: r.category,
4123
4320
  priceUsd: r.priceUsd,
4321
+ reliabilityScore: r.reliabilityScore,
4322
+ health: r.health,
4323
+ verified: r.verified,
4124
4324
  networks: [...new Set(r.rails.map((rail) => rail.network))]
4125
4325
  }))
4126
4326
  };
@@ -4302,13 +4502,20 @@ function paymentTools(client) {
4302
4502
  properties: {
4303
4503
  url: { type: "string", description: "Full URL of the resource to list." },
4304
4504
  name: { type: "string", description: "Display name (defaults to the host)." },
4305
- description: { type: "string", description: "What the resource offers." },
4505
+ description: {
4506
+ type: "string",
4507
+ description: "What the resource offers. Pack the words agents will search for INTO this text \u2014 index search is literal, so a keyword that isn't in the name/description won't be found."
4508
+ },
4509
+ category: { type: "string", description: "A category, e.g. 'ai', 'finance', 'data' \u2014 the top findability field (most listings have none)." },
4510
+ tags: { type: "array", items: { type: "string" }, description: "Keywords; folded into the description so they're searchable." },
4306
4511
  priceUsd: { type: "number", description: "Advertised price in USD (metadata)." },
4307
4512
  network: {
4308
4513
  type: "string",
4309
4514
  description: "Network slug to advertise, e.g. 'base' (defaults to the paying chain). Set it when registering from a multi-chain wallet so the listing names the right chain."
4310
4515
  },
4311
- asset: { type: "string", description: "Payment asset symbol, e.g. 'USDC' (metadata)." }
4516
+ asset: { type: "string", description: "Payment asset symbol, e.g. 'USDC' (metadata)." },
4517
+ provider: { type: "string", description: "Who runs the resource (provider/org name)." },
4518
+ contactEmail: { type: "string", description: "Contact email for the listing." }
4312
4519
  },
4313
4520
  required: ["url"],
4314
4521
  additionalProperties: false
@@ -4318,9 +4525,13 @@ function paymentTools(client) {
4318
4525
  const opts = {};
4319
4526
  if (typeof args.name === "string") opts.name = args.name;
4320
4527
  if (typeof args.description === "string") opts.description = args.description;
4528
+ if (typeof args.category === "string") opts.category = args.category;
4529
+ if (Array.isArray(args.tags)) opts.tags = args.tags.filter((t) => typeof t === "string");
4321
4530
  if (typeof args.priceUsd === "number") opts.priceUsd = args.priceUsd;
4322
4531
  if (typeof args.network === "string") opts.network = args.network;
4323
4532
  if (typeof args.asset === "string") opts.asset = args.asset;
4533
+ if (typeof args.provider === "string") opts.provider = args.provider;
4534
+ if (typeof args.contactEmail === "string") opts.contactEmail = args.contactEmail;
4324
4535
  const outcomes = await client.register(String(args.url), opts);
4325
4536
  return { outcomes };
4326
4537
  } catch (err) {
@@ -4421,7 +4632,7 @@ function buildBazaarExtension(descriptor = {}) {
4421
4632
  function pathOf(url) {
4422
4633
  try {
4423
4634
  return new URL(url).pathname || "/";
4424
- } catch (e31) {
4635
+ } catch (e32) {
4425
4636
  return url.startsWith("/") ? url : `/${url}`;
4426
4637
  }
4427
4638
  }
@@ -4530,26 +4741,26 @@ async function fetchFacilitatorFeePayer(url, network, timeoutMs = 8e3) {
4530
4741
  const res = await fetch(`${base2}/supported`, { signal: ctrl.signal });
4531
4742
  if (!res.ok) return void 0;
4532
4743
  const body = await res.json();
4533
- const kinds = Array.isArray(_optionalChain([body, 'optionalAccess', _77 => _77.kinds])) ? body.kinds : [];
4744
+ const kinds = Array.isArray(_optionalChain([body, 'optionalAccess', _71 => _71.kinds])) ? body.kinds : [];
4534
4745
  const want = normalizeNetwork(network);
4535
- const kind = kinds.find((k) => _optionalChain([k, 'optionalAccess', _78 => _78.scheme]) === "exact" && normalizeNetwork(String(_nullishCoalesce(_optionalChain([k, 'optionalAccess', _79 => _79.network]), () => ( "")))) === want);
4536
- const fp = _optionalChain([kind, 'optionalAccess', _80 => _80.extra, 'optionalAccess', _81 => _81.feePayer]);
4746
+ const kind = kinds.find((k) => _optionalChain([k, 'optionalAccess', _72 => _72.scheme]) === "exact" && normalizeNetwork(String(_nullishCoalesce(_optionalChain([k, 'optionalAccess', _73 => _73.network]), () => ( "")))) === want);
4747
+ const fp = _optionalChain([kind, 'optionalAccess', _74 => _74.extra, 'optionalAccess', _75 => _75.feePayer]);
4537
4748
  return typeof fp === "string" ? fp : void 0;
4538
- } catch (e32) {
4749
+ } catch (e33) {
4539
4750
  return void 0;
4540
4751
  } finally {
4541
4752
  clearTimeout(timer);
4542
4753
  }
4543
4754
  }
4544
4755
  function parseFacilitatorSupported(body) {
4545
- const kinds = _optionalChain([body, 'optionalAccess', _82 => _82.kinds]);
4756
+ const kinds = _optionalChain([body, 'optionalAccess', _76 => _76.kinds]);
4546
4757
  if (!Array.isArray(kinds)) return [];
4547
4758
  const out = [];
4548
4759
  for (const k of kinds) {
4549
4760
  if (!k || typeof k !== "object") continue;
4550
4761
  const o = k;
4551
4762
  if (typeof o.scheme !== "string" || typeof o.network !== "string") continue;
4552
- const fp = _optionalChain([o, 'access', _83 => _83.extra, 'optionalAccess', _84 => _84.feePayer]);
4763
+ const fp = _optionalChain([o, 'access', _77 => _77.extra, 'optionalAccess', _78 => _78.feePayer]);
4553
4764
  out.push({ scheme: o.scheme, network: o.network, ...typeof fp === "string" ? { feePayer: fp } : {} });
4554
4765
  }
4555
4766
  return out;
@@ -4562,7 +4773,7 @@ async function facilitatorCoverage(url, timeoutMs = 8e3) {
4562
4773
  const res = await fetch(`${base2}/supported`, { signal: ctrl.signal });
4563
4774
  if (!res.ok) return [];
4564
4775
  return parseFacilitatorSupported(await res.json());
4565
- } catch (e33) {
4776
+ } catch (e34) {
4566
4777
  return [];
4567
4778
  } finally {
4568
4779
  clearTimeout(timer);
@@ -4591,7 +4802,7 @@ async function post(url, body, headers) {
4591
4802
  let json = null;
4592
4803
  try {
4593
4804
  json = await res.json();
4594
- } catch (e34) {
4805
+ } catch (e35) {
4595
4806
  }
4596
4807
  return { status: res.status, json };
4597
4808
  }
@@ -4846,11 +5057,17 @@ function createPaymentGate(options) {
4846
5057
  const nonce = genNonce();
4847
5058
  const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
4848
5059
  const accepts = buildAccepts(specs, nonce);
5060
+ const endpointInfo = buildEndpointInfo({
5061
+ ...options.description ? { description: options.description } : {},
5062
+ ...options.mimeType ? { mimeType: options.mimeType } : {},
5063
+ ...typeof options.discovery === "object" ? { descriptor: options.discovery } : {}
5064
+ });
4849
5065
  const selfDescribe = options.selfDescribe === false ? void 0 : buildSelfDescription({
4850
5066
  accepts,
4851
- instruction: describeChallenge({ x402Version: 2, resource: { url: resourceUrl }, accepts })
5067
+ instruction: describeChallenge({ x402Version: 2, resource: { url: resourceUrl }, accepts }),
5068
+ ...endpointInfo ? { endpoint: endpointInfo } : {}
4852
5069
  });
4853
- const rejectionExt = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _85 => _85.extensions]), () => ( {}));
5070
+ const rejectionExt = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _79 => _79.extensions]), () => ( {}));
4854
5071
  const rejectionPiprail = _nullishCoalesce(rejectionExt.piprail, () => ( {}));
4855
5072
  const bodyPiprail = { ..._nullishCoalesce(selfDescribe, () => ( {})), ...rejectionPiprail };
4856
5073
  const bodyExtensions = {
@@ -4866,10 +5083,11 @@ function createPaymentGate(options) {
4866
5083
  x402Version: 2,
4867
5084
  resource: {
4868
5085
  url: resourceUrl,
4869
- ...options.description ? { description: options.description } : {}
5086
+ ...options.description ? { description: options.description } : {},
5087
+ ...options.mimeType ? { mimeType: options.mimeType } : {}
4870
5088
  },
4871
5089
  accepts,
4872
- ..._optionalChain([opts, 'optionalAccess', _86 => _86.error]) ? { error: opts.error } : {},
5090
+ ..._optionalChain([opts, 'optionalAccess', _80 => _80.error]) ? { error: opts.error } : {},
4873
5091
  ...Object.keys(bodyExtensions).length > 0 ? { extensions: bodyExtensions } : {}
4874
5092
  };
4875
5093
  const headerChallenge = {
@@ -4901,7 +5119,7 @@ function createPaymentGate(options) {
4901
5119
  let amountFormatted = receipt.amount;
4902
5120
  try {
4903
5121
  amountFormatted = _chunkJG6KRAW6cjs.formatUnits.call(void 0, BigInt(receipt.amount), spec.decimals);
4904
- } catch (e35) {
5122
+ } catch (e36) {
4905
5123
  }
4906
5124
  return {
4907
5125
  ...receipt,
@@ -4915,7 +5133,7 @@ function createPaymentGate(options) {
4915
5133
  if (!options.onPaidError) return;
4916
5134
  try {
4917
5135
  options.onPaidError(error, receipt);
4918
- } catch (e36) {
5136
+ } catch (e37) {
4919
5137
  }
4920
5138
  }
4921
5139
  function fireOnPaid(receipt) {
@@ -4956,6 +5174,7 @@ function createPaymentGate(options) {
4956
5174
  return {
4957
5175
  url: resourceUrl,
4958
5176
  ...options.description ? { description: options.description } : {},
5177
+ ...options.mimeType ? { mimeType: options.mimeType } : {},
4959
5178
  accepts
4960
5179
  };
4961
5180
  }
@@ -5012,7 +5231,7 @@ function createPaymentGate(options) {
5012
5231
  if ("transaction" in exact.payload) {
5013
5232
  try {
5014
5233
  nonce = Buffer.from(exact.payload.transaction, "base64").toString("base64");
5015
- } catch (e37) {
5234
+ } catch (e38) {
5016
5235
  nonce = exact.payload.transaction;
5017
5236
  }
5018
5237
  } else if ("permit2Authorization" in exact.payload) {
@@ -5190,7 +5409,7 @@ function isRetryableStatus(status) {
5190
5409
  }
5191
5410
  var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
5192
5411
  async function signBody(secret, body) {
5193
- const subtle = _optionalChain([globalThis, 'access', _87 => _87.crypto, 'optionalAccess', _88 => _88.subtle]);
5412
+ const subtle = _optionalChain([globalThis, 'access', _81 => _81.crypto, 'optionalAccess', _82 => _82.subtle]);
5194
5413
  if (!subtle) return null;
5195
5414
  try {
5196
5415
  const enc = new TextEncoder();
@@ -5200,7 +5419,7 @@ async function signBody(secret, body) {
5200
5419
  const sig = await subtle.sign("HMAC", key, enc.encode(body));
5201
5420
  const hex = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
5202
5421
  return `sha256=${hex}`;
5203
- } catch (e38) {
5422
+ } catch (e39) {
5204
5423
  return null;
5205
5424
  }
5206
5425
  }
@@ -5260,8 +5479,8 @@ async function deliverReceipt(receipt, options) {
5260
5479
  const retryable = status === void 0 ? true : isRetryableStatus(status);
5261
5480
  const willRetry = !ok && retryable && attempt < maxAttempts;
5262
5481
  try {
5263
- _optionalChain([onAttempt, 'optionalCall', _89 => _89({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
5264
- } catch (e39) {
5482
+ _optionalChain([onAttempt, 'optionalCall', _83 => _83({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
5483
+ } catch (e40) {
5265
5484
  }
5266
5485
  if (ok) return { delivered: true, attempts: attempt, status };
5267
5486
  if (!willRetry) {
@@ -5376,4 +5595,8 @@ async function deliverReceipt(receipt, options) {
5376
5595
 
5377
5596
 
5378
5597
 
5379
- exports.BRAND = BRAND; exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkJG6KRAW6cjs.ConfirmationTimeoutError; exports.DIRECTORY_INFO = DIRECTORY_INFO; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkJG6KRAW6cjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkJG6KRAW6cjs.InvalidEnvelopeError; exports.KNOWN_FACILITATORS = KNOWN_FACILITATORS; exports.MaxRetriesExceededError = _chunkJG6KRAW6cjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkJG6KRAW6cjs.MissingDriverError; exports.MultiChainPayer = MultiChainPayer; exports.NoCompatibleAcceptError = _chunkJG6KRAW6cjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkJG6KRAW6cjs.NonReplayableBodyError; exports.PERMIT2_ADDRESS = PERMIT2_ADDRESS; exports.PERMIT2_PROXY_CHAIN_IDS = PERMIT2_PROXY_CHAIN_IDS; exports.PERMIT2_WITNESS_TYPES = PERMIT2_WITNESS_TYPES; exports.PIPRAIL_AGENT_GUIDE = PIPRAIL_AGENT_GUIDE; exports.POWERED_BY = POWERED_BY; exports.PaymentDeclinedError = _chunkJG6KRAW6cjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkJG6KRAW6cjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkJG6KRAW6cjs.PipRailError; exports.REGISTER_ATTRIBUTION = REGISTER_ATTRIBUTION; exports.RecipientNotReadyError = _chunkJG6KRAW6cjs.RecipientNotReadyError; exports.SettlementError = _chunkJG6KRAW6cjs.SettlementError; exports.UnknownTokenError = _chunkJG6KRAW6cjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkJG6KRAW6cjs.UnsupportedNetworkError; exports.UnsupportedSchemeError = _chunkJG6KRAW6cjs.UnsupportedSchemeError; exports.WalletRequiredError = _chunkJG6KRAW6cjs.WalletRequiredError; exports.WrongChainError = _chunkJG6KRAW6cjs.WrongChainError; exports.WrongFamilyError = _chunkJG6KRAW6cjs.WrongFamilyError; exports.X402_EXACT_PERMIT2_PROXY = X402_EXACT_PERMIT2_PROXY; exports.agentGuide = agentGuide; exports.appendAttribution = appendAttribution; exports.buildBazaarExtension = buildBazaarExtension; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildExactSignatureHeader = buildExactSignatureHeader; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSelfDescription = buildSelfDescription; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.classifyChallenge = classifyChallenge; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.deliverReceipt = deliverReceipt; exports.describeChallenge = describeChallenge; exports.discoveryHeaders = discoveryHeaders; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.explainDecline = explainDecline; exports.facilitatorCoverage = facilitatorCoverage; exports.fetchAcross = fetchAcross; exports.firstKeylessFacilitator = firstKeylessFacilitator; exports.formatSpendReport = formatSpendReport; exports.getDirectoryInfo = getDirectoryInfo; exports.isPermit2ProxyChain = isPermit2ProxyChain; exports.knownFacilitatorsFor = knownFacilitatorsFor; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseFacilitatorSupported = parseFacilitatorSupported; exports.parseReceipt = parseReceipt; exports.parseSettleResponse = parseSettleResponse; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.renderLandingPage = renderLandingPage; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.summarizePlan = summarizePlan; exports.toInsufficientFundsError = _chunkJG6KRAW6cjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;
5598
+
5599
+
5600
+
5601
+
5602
+ exports.BRAND = BRAND; exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkJG6KRAW6cjs.ConfirmationTimeoutError; exports.DIRECTORY_INFO = DIRECTORY_INFO; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkJG6KRAW6cjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkJG6KRAW6cjs.InvalidEnvelopeError; exports.KNOWN_FACILITATORS = KNOWN_FACILITATORS; exports.MaxRetriesExceededError = _chunkJG6KRAW6cjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkJG6KRAW6cjs.MissingDriverError; exports.MultiChainPayer = MultiChainPayer; exports.NoCompatibleAcceptError = _chunkJG6KRAW6cjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkJG6KRAW6cjs.NonReplayableBodyError; exports.PERMIT2_ADDRESS = PERMIT2_ADDRESS; exports.PERMIT2_PROXY_CHAIN_IDS = PERMIT2_PROXY_CHAIN_IDS; exports.PERMIT2_WITNESS_TYPES = PERMIT2_WITNESS_TYPES; exports.PIPRAIL_AGENT_GUIDE = PIPRAIL_AGENT_GUIDE; exports.POWERED_BY = POWERED_BY; exports.PaymentDeclinedError = _chunkJG6KRAW6cjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkJG6KRAW6cjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkJG6KRAW6cjs.PipRailError; exports.REGISTER_ATTRIBUTION = REGISTER_ATTRIBUTION; exports.RecipientNotReadyError = _chunkJG6KRAW6cjs.RecipientNotReadyError; exports.SettlementError = _chunkJG6KRAW6cjs.SettlementError; exports.UnknownTokenError = _chunkJG6KRAW6cjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkJG6KRAW6cjs.UnsupportedNetworkError; exports.UnsupportedSchemeError = _chunkJG6KRAW6cjs.UnsupportedSchemeError; exports.WalletRequiredError = _chunkJG6KRAW6cjs.WalletRequiredError; exports.WrongChainError = _chunkJG6KRAW6cjs.WrongChainError; exports.WrongFamilyError = _chunkJG6KRAW6cjs.WrongFamilyError; exports.X402_EXACT_PERMIT2_PROXY = X402_EXACT_PERMIT2_PROXY; exports.agentGuide = agentGuide; exports.appendAttribution = appendAttribution; exports.appendKeywords = appendKeywords; exports.buildBazaarExtension = buildBazaarExtension; exports.buildChallengeHeader = buildChallengeHeader; exports.buildEndpointInfo = buildEndpointInfo; exports.buildExactAuthorization = buildExactAuthorization; exports.buildExactSignatureHeader = buildExactSignatureHeader; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSelfDescription = buildSelfDescription; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.classifyChallenge = classifyChallenge; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.deliverReceipt = deliverReceipt; exports.describeChallenge = describeChallenge; exports.discoveryHeaders = discoveryHeaders; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.explainDecline = explainDecline; exports.facilitatorCoverage = facilitatorCoverage; exports.fetchAcross = fetchAcross; exports.firstKeylessFacilitator = firstKeylessFacilitator; exports.formatSpendReport = formatSpendReport; exports.getDirectoryInfo = getDirectoryInfo; exports.isPermit2ProxyChain = isPermit2ProxyChain; exports.knownFacilitatorsFor = knownFacilitatorsFor; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseFacilitatorSupported = parseFacilitatorSupported; exports.parseReceipt = parseReceipt; exports.parseSettleResponse = parseSettleResponse; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.rankResources = rankResources; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.renderLandingPage = renderLandingPage; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.scoreResource = scoreResource; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.summarizePlan = summarizePlan; exports.toInsufficientFundsError = _chunkJG6KRAW6cjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;