uvd-x402-sdk 2.75.0 → 2.76.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.
@@ -1093,6 +1093,118 @@ function decodeX402Header(encoded) {
1093
1093
  var REVIEW_WINDOW_SEC = 7 * 24 * 3600;
1094
1094
  var REFUND_WINDOW_SEC = 7 * 24 * 3600;
1095
1095
 
1096
+ // src/backend/facilitator-error.ts
1097
+ var WRITER_LEASE_REASONS = [
1098
+ "holder_unknown",
1099
+ "forwarding_disabled",
1100
+ "forwarded_but_not_writer",
1101
+ "body_unreadable",
1102
+ "forward_failed"
1103
+ ];
1104
+ var REPLAYABLE_LEASE_REASONS = [
1105
+ "holder_unknown",
1106
+ "forwarding_disabled",
1107
+ "forwarded_but_not_writer",
1108
+ "body_unreadable"
1109
+ ];
1110
+ var AMBIGUOUS_LEASE_REASONS = ["forward_failed"];
1111
+ var MAX_RETRY_AFTER_SECONDS = 15;
1112
+ var DEFAULT_RETRY_AFTER_SECONDS = 5;
1113
+ var DEFAULT_FACILITATOR_RETRIES = 2;
1114
+ function isReplayableLeaseReason(reason) {
1115
+ return REPLAYABLE_LEASE_REASONS.includes(reason);
1116
+ }
1117
+ function isAmbiguousLeaseReason(reason) {
1118
+ return AMBIGUOUS_LEASE_REASONS.includes(reason);
1119
+ }
1120
+ function parseRetryAfterSeconds(response) {
1121
+ let raw;
1122
+ try {
1123
+ raw = response?.headers?.get?.("retry-after");
1124
+ } catch {
1125
+ return void 0;
1126
+ }
1127
+ if (raw === null || raw === void 0 || raw === "") return void 0;
1128
+ const seconds = Number(raw);
1129
+ if (!Number.isFinite(seconds) || seconds < 0) return void 0;
1130
+ return Math.min(seconds, MAX_RETRY_AFTER_SECONDS);
1131
+ }
1132
+ function reasonFrom(body) {
1133
+ try {
1134
+ const parsed = JSON.parse(body);
1135
+ if (parsed && typeof parsed === "object" && typeof parsed.reason === "string") {
1136
+ return parsed.reason;
1137
+ }
1138
+ } catch {
1139
+ }
1140
+ return void 0;
1141
+ }
1142
+ async function readFacilitatorError(response) {
1143
+ let body = "";
1144
+ try {
1145
+ body = await response.text();
1146
+ } catch {
1147
+ body = "";
1148
+ }
1149
+ const status = response.status;
1150
+ const reason = reasonFrom(body);
1151
+ const retryable = status === 429 || status === 502 || status === 503 || status === 504;
1152
+ const retryAfterSeconds = retryable ? parseRetryAfterSeconds(response) ?? DEFAULT_RETRY_AFTER_SECONDS : void 0;
1153
+ const safeToReplay = status === 429 || status === 503 && isReplayableLeaseReason(reason);
1154
+ return {
1155
+ error: `Facilitator error: ${status} - ${body}`,
1156
+ status,
1157
+ reason,
1158
+ retryAfterSeconds,
1159
+ retryable,
1160
+ safeToReplay,
1161
+ body
1162
+ };
1163
+ }
1164
+ function failureFields(info) {
1165
+ return {
1166
+ status: info.status,
1167
+ retryable: info.retryable,
1168
+ safeToReplay: info.safeToReplay,
1169
+ ...info.reason !== void 0 ? { reason: info.reason } : {},
1170
+ ...info.retryAfterSeconds !== void 0 ? { retryAfterSeconds: info.retryAfterSeconds } : {}
1171
+ };
1172
+ }
1173
+ function carryFailureFields(source) {
1174
+ return {
1175
+ ...source.status !== void 0 ? { status: source.status } : {},
1176
+ ...source.reason !== void 0 ? { reason: source.reason } : {},
1177
+ ...source.retryable !== void 0 ? { retryable: source.retryable } : {},
1178
+ ...source.retryAfterSeconds !== void 0 ? { retryAfterSeconds: source.retryAfterSeconds } : {},
1179
+ ...source.safeToReplay !== void 0 ? { safeToReplay: source.safeToReplay } : {}
1180
+ };
1181
+ }
1182
+ var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1183
+ async function facilitatorFetch(url, init, options) {
1184
+ const retries = options.retries ?? DEFAULT_FACILITATOR_RETRIES;
1185
+ const canReplay = options.canReplay ?? ((info) => info.safeToReplay);
1186
+ const doFetch = options.fetchImpl ?? fetch;
1187
+ const sleep = options.sleepImpl ?? defaultSleep;
1188
+ let attempt = 0;
1189
+ for (; ; ) {
1190
+ const controller = new AbortController();
1191
+ const timeoutId = setTimeout(() => controller.abort(), options.timeoutMs);
1192
+ let response;
1193
+ try {
1194
+ response = await doFetch(url, { ...init, signal: controller.signal });
1195
+ } finally {
1196
+ clearTimeout(timeoutId);
1197
+ }
1198
+ if (response.ok) return { response };
1199
+ const error = await readFacilitatorError(response);
1200
+ if (attempt >= retries || !error.retryable || !canReplay(error)) {
1201
+ return { response, error };
1202
+ }
1203
+ attempt += 1;
1204
+ await sleep((error.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS) * 1e3);
1205
+ }
1206
+ }
1207
+
1096
1208
  // src/backend/index.ts
1097
1209
  function parsePaymentHeader(headerValue) {
1098
1210
  if (!headerValue) {
@@ -1199,10 +1311,12 @@ var FacilitatorClient = class {
1199
1311
  baseUrl;
1200
1312
  timeout;
1201
1313
  explicitTimeout;
1314
+ retries;
1202
1315
  constructor(options = {}) {
1203
1316
  this.baseUrl = options.baseUrl || "https://facilitator.ultravioletadao.xyz";
1204
1317
  this.explicitTimeout = options.timeout !== void 0;
1205
1318
  this.timeout = options.timeout || 3e4;
1319
+ this.retries = options.retries;
1206
1320
  }
1207
1321
  /**
1208
1322
  * Get timeout for a specific network, using per-chain defaults when no explicit timeout was set.
@@ -1229,29 +1343,31 @@ var FacilitatorClient = class {
1229
1343
  */
1230
1344
  async verify(paymentHeader, requirements) {
1231
1345
  const body = buildVerifyRequest(paymentHeader, requirements);
1232
- const controller = new AbortController();
1233
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1234
1346
  try {
1235
- const response = await fetch(`${this.baseUrl}/verify`, {
1236
- method: "POST",
1237
- headers: { "Content-Type": "application/json" },
1238
- body: JSON.stringify(body),
1239
- signal: controller.signal
1240
- });
1241
- clearTimeout(timeoutId);
1242
- if (!response.ok) {
1243
- const errorText = await response.text();
1347
+ const { response, error } = await facilitatorFetch(
1348
+ `${this.baseUrl}/verify`,
1349
+ {
1350
+ method: "POST",
1351
+ headers: { "Content-Type": "application/json" },
1352
+ body: JSON.stringify(body)
1353
+ },
1354
+ { timeoutMs: this.timeout, retries: this.retries }
1355
+ );
1356
+ if (error) {
1244
1357
  return {
1245
1358
  isValid: false,
1246
- invalidReason: `Facilitator error: ${response.status} - ${errorText}`
1359
+ invalidReason: error.error,
1360
+ ...failureFields(error)
1247
1361
  };
1248
1362
  }
1249
1363
  return await response.json();
1250
1364
  } catch (error) {
1251
- clearTimeout(timeoutId);
1252
1365
  return {
1253
1366
  isValid: false,
1254
- invalidReason: error instanceof Error ? error.message : "Unknown error"
1367
+ invalidReason: error instanceof Error ? error.message : "Unknown error",
1368
+ retryable: true,
1369
+ safeToReplay: false,
1370
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
1255
1371
  };
1256
1372
  }
1257
1373
  }
@@ -1267,21 +1383,21 @@ var FacilitatorClient = class {
1267
1383
  async settle(paymentHeader, requirements) {
1268
1384
  const body = buildSettleRequest(paymentHeader, requirements);
1269
1385
  const settleTimeout = this.getTimeout(requirements.network);
1270
- const controller = new AbortController();
1271
- const timeoutId = setTimeout(() => controller.abort(), settleTimeout);
1272
1386
  try {
1273
- const response = await fetch(`${this.baseUrl}/settle`, {
1274
- method: "POST",
1275
- headers: { "Content-Type": "application/json" },
1276
- body: JSON.stringify(body),
1277
- signal: controller.signal
1278
- });
1279
- clearTimeout(timeoutId);
1280
- if (!response.ok) {
1281
- const errorText = await response.text();
1387
+ const { response, error } = await facilitatorFetch(
1388
+ `${this.baseUrl}/settle`,
1389
+ {
1390
+ method: "POST",
1391
+ headers: { "Content-Type": "application/json" },
1392
+ body: JSON.stringify(body)
1393
+ },
1394
+ { timeoutMs: settleTimeout, retries: this.retries }
1395
+ );
1396
+ if (error) {
1282
1397
  return {
1283
1398
  success: false,
1284
- error: `Facilitator error: ${response.status} - ${errorText}`
1399
+ error: error.error,
1400
+ ...failureFields(error)
1285
1401
  };
1286
1402
  }
1287
1403
  const result = await response.json();
@@ -1322,10 +1438,12 @@ var FacilitatorClient = class {
1322
1438
  payer: result.payer
1323
1439
  };
1324
1440
  } catch (error) {
1325
- clearTimeout(timeoutId);
1326
1441
  return {
1327
1442
  success: false,
1328
- error: error instanceof Error ? error.message : "Unknown error"
1443
+ error: error instanceof Error ? error.message : "Unknown error",
1444
+ retryable: true,
1445
+ safeToReplay: false,
1446
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
1329
1447
  };
1330
1448
  }
1331
1449
  }
@@ -1345,7 +1463,8 @@ var FacilitatorClient = class {
1345
1463
  return {
1346
1464
  verified: false,
1347
1465
  settled: false,
1348
- error: verifyResult.invalidReason
1466
+ error: verifyResult.invalidReason,
1467
+ ...carryFailureFields(verifyResult)
1349
1468
  };
1350
1469
  }
1351
1470
  const settleResult = await this.settle(paymentHeader, requirements);
@@ -1353,7 +1472,8 @@ var FacilitatorClient = class {
1353
1472
  verified: true,
1354
1473
  settled: settleResult.success,
1355
1474
  transactionHash: settleResult.transactionHash,
1356
- error: settleResult.error
1475
+ error: settleResult.error,
1476
+ ...carryFailureFields(settleResult)
1357
1477
  };
1358
1478
  }
1359
1479
  /**
@@ -1755,10 +1875,29 @@ function createVerifiedPaymentState(client, payment, requirements, verifyResult)
1755
1875
  }
1756
1876
  };
1757
1877
  }
1878
+ function respondUnavailable(res, message, failure) {
1879
+ const seconds = Math.max(1, Math.ceil(failure.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS));
1880
+ const body = {
1881
+ error: message,
1882
+ reason: failure.reason ?? failure.invalidReason ?? failure.error,
1883
+ retryable: true,
1884
+ retryAfterSeconds: seconds,
1885
+ // False for `forward_failed` and for a bare timeout: the write may already
1886
+ // have landed, so the caller must reconcile before resending.
1887
+ safeToReplay: failure.safeToReplay === true
1888
+ };
1889
+ const staged = res.status(503);
1890
+ if (typeof staged.set === "function") {
1891
+ staged.set({ "Retry-After": String(seconds) }).json(body);
1892
+ return;
1893
+ }
1894
+ staged.json(body);
1895
+ }
1758
1896
  function createPaymentMiddleware(getRequirements, options = {}) {
1759
1897
  const client = new FacilitatorClient({
1760
1898
  baseUrl: options.facilitatorUrl || options.baseUrl,
1761
- timeout: options.timeout
1899
+ timeout: options.timeout,
1900
+ retries: options.retries
1762
1901
  });
1763
1902
  const settlementStrategy = options.settlementStrategy || "before-handler";
1764
1903
  return async (req, res, next) => {
@@ -1773,6 +1912,10 @@ function createPaymentMiddleware(getRequirements, options = {}) {
1773
1912
  const requirements = buildPaymentRequirements(reqOptions);
1774
1913
  const verifyResult = await client.verify(payment, requirements);
1775
1914
  if (!verifyResult.isValid) {
1915
+ if (verifyResult.retryable) {
1916
+ respondUnavailable(res, "Payment verification unavailable", verifyResult);
1917
+ return;
1918
+ }
1776
1919
  res.status(402).json({
1777
1920
  error: "Payment verification failed",
1778
1921
  reason: verifyResult.invalidReason
@@ -1783,6 +1926,10 @@ function createPaymentMiddleware(getRequirements, options = {}) {
1783
1926
  if (settlementStrategy === "before-handler") {
1784
1927
  const settleResult = await req.x402.settle();
1785
1928
  if (!settleResult.success) {
1929
+ if (settleResult.retryable) {
1930
+ respondUnavailable(res, "Payment settlement unavailable", settleResult);
1931
+ return;
1932
+ }
1786
1933
  res.status(500).json({
1787
1934
  error: "Payment settlement failed",
1788
1935
  reason: settleResult.error || "Unknown settlement error"
@@ -1793,10 +1940,25 @@ function createPaymentMiddleware(getRequirements, options = {}) {
1793
1940
  next();
1794
1941
  };
1795
1942
  }
1943
+ function honoUnavailable(c, message, failure) {
1944
+ const seconds = Math.max(1, Math.ceil(failure.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS));
1945
+ c.header?.("Retry-After", String(seconds));
1946
+ return c.json(
1947
+ {
1948
+ error: message,
1949
+ reason: failure.reason ?? failure.invalidReason ?? failure.error,
1950
+ retryable: true,
1951
+ retryAfterSeconds: seconds,
1952
+ safeToReplay: failure.safeToReplay === true
1953
+ },
1954
+ 503
1955
+ );
1956
+ }
1796
1957
  function createHonoMiddleware(options) {
1797
1958
  const client = new FacilitatorClient({
1798
1959
  baseUrl: options.facilitatorUrl || options.baseUrl,
1799
- timeout: options.timeout
1960
+ timeout: options.timeout,
1961
+ retries: options.retries
1800
1962
  });
1801
1963
  const settlementStrategy = options.settlementStrategy || "before-handler";
1802
1964
  if (!options.accepts[0]) {
@@ -1836,6 +1998,9 @@ function createHonoMiddleware(options) {
1836
1998
  }
1837
1999
  const verifyResult = await client.verify(parsed, requirement);
1838
2000
  if (!verifyResult.isValid) {
2001
+ if (verifyResult.retryable) {
2002
+ return honoUnavailable(c, "Payment verification unavailable", verifyResult);
2003
+ }
1839
2004
  return c.json({
1840
2005
  error: "Payment verification failed",
1841
2006
  reason: verifyResult.invalidReason
@@ -1846,6 +2011,9 @@ function createHonoMiddleware(options) {
1846
2011
  if (settlementStrategy === "before-handler") {
1847
2012
  const settleResult = await verifiedPayment.settle();
1848
2013
  if (!settleResult.success) {
2014
+ if (settleResult.retryable) {
2015
+ return honoUnavailable(c, "Payment settlement unavailable", settleResult);
2016
+ }
1849
2017
  return c.json({
1850
2018
  error: "Payment settlement failed",
1851
2019
  reason: settleResult.error || "Unknown error"
@@ -2627,19 +2795,65 @@ var Erc8004LookupError = class extends Error {
2627
2795
  status;
2628
2796
  /** Raw response body, for debugging */
2629
2797
  body;
2630
- constructor(message, status, body) {
2798
+ /**
2799
+ * `Retry-After`, already clamped, when the facilitator sent one.
2800
+ *
2801
+ * Optional so every existing three-argument construction keeps compiling; it
2802
+ * falls back to the default wait rather than to zero, because a caller that
2803
+ * retries instantly on a 503 is the load that caused it.
2804
+ */
2805
+ retryAfterHint;
2806
+ constructor(message, status, body, retryAfterSeconds) {
2631
2807
  super(message);
2632
2808
  this.name = "Erc8004LookupError";
2633
2809
  this.status = status;
2634
2810
  this.body = body;
2811
+ this.retryAfterHint = retryAfterSeconds;
2635
2812
  }
2636
2813
  /** The address genuinely owns no agent on this network. */
2637
2814
  get notFound() {
2638
2815
  return this.status === 404;
2639
2816
  }
2640
- /** The lookup reached no verdict. Retry; never read as "owns nothing". */
2817
+ /**
2818
+ * The lookup reached no verdict. Retry; never read as "owns nothing".
2819
+ *
2820
+ * `502` and `504` join `503` and `429` here: a gateway that answered on the
2821
+ * facilitator's behalf is exactly as silent about the agent's existence, and
2822
+ * reading either as absence has the same consequence -- a duplicate mint.
2823
+ */
2641
2824
  get retryable() {
2642
- return this.status === 503;
2825
+ return this.status === 429 || this.status === 502 || this.status === 503 || this.status === 504;
2826
+ }
2827
+ /**
2828
+ * The facilitator's own `reason`, when the body carried one.
2829
+ *
2830
+ * On a WRITE route this is the writer-lease reason and it decides whether the
2831
+ * request may be re-sent; see {@link isReplayableLeaseReason}.
2832
+ */
2833
+ get reason() {
2834
+ try {
2835
+ const parsed = JSON.parse(this.body);
2836
+ if (parsed && typeof parsed === "object" && typeof parsed.reason === "string") {
2837
+ return parsed.reason;
2838
+ }
2839
+ } catch {
2840
+ }
2841
+ return void 0;
2842
+ }
2843
+ /**
2844
+ * The facilitator NAMED a reason proving it executed nothing.
2845
+ *
2846
+ * False for `forward_failed` and for every unattributed 5xx: "something
2847
+ * answered" is not evidence that nothing ran. On `/register`, replaying when
2848
+ * this is false is the sequence that minted five duplicate agents.
2849
+ */
2850
+ get safeToReplay() {
2851
+ return this.status === 429 || this.status === 503 && isReplayableLeaseReason(this.reason);
2852
+ }
2853
+ /** Seconds to wait before retrying, clamped. Absent when not retryable. */
2854
+ get retryAfterSeconds() {
2855
+ if (!this.retryable) return void 0;
2856
+ return this.retryAfterHint ?? DEFAULT_RETRY_AFTER_SECONDS;
2643
2857
  }
2644
2858
  };
2645
2859
  function isRegisterJobTerminal(job) {
@@ -2676,9 +2890,38 @@ function jobToRegisterResponse(job, network) {
2676
2890
  var Erc8004Client = class {
2677
2891
  baseUrl;
2678
2892
  timeout;
2893
+ retries;
2679
2894
  constructor(options = {}) {
2680
2895
  this.baseUrl = options.baseUrl || "https://facilitator.ultravioletadao.xyz";
2681
2896
  this.timeout = options.timeout || 3e4;
2897
+ this.retries = options.retries;
2898
+ }
2899
+ /**
2900
+ * POST a write route, keeping a refusal readable.
2901
+ *
2902
+ * Every ERC-8004 write goes through the facilitator's EVM writer lease, so
2903
+ * every one of them can answer `503` + `reason`. Flattened to a string, those
2904
+ * are indistinguishable from "the registry rejected your feedback" — and on
2905
+ * `/register` the wrong reading re-POSTs a mint that may already have landed,
2906
+ * which is precisely how five duplicate agents were once created.
2907
+ *
2908
+ * A refusal the facilitator proved it did not execute is replayed
2909
+ * automatically (`safeToReplay`); `forward_failed` never is.
2910
+ */
2911
+ async writeJson(url, body, extraHeaders = {}) {
2912
+ return facilitatorFetch(
2913
+ url,
2914
+ {
2915
+ method: "POST",
2916
+ headers: {
2917
+ "Content-Type": "application/json",
2918
+ Accept: "application/json",
2919
+ ...extraHeaders
2920
+ },
2921
+ body: JSON.stringify(body)
2922
+ },
2923
+ { timeoutMs: this.timeout, retries: this.retries }
2924
+ );
2682
2925
  }
2683
2926
  /**
2684
2927
  * Get agent identity from the Identity Registry
@@ -2727,26 +2970,21 @@ var Erc8004Client = class {
2727
2970
  const url = `${this.baseUrl}/identity/${wireNetwork(network)}/owner/${address}`;
2728
2971
  const controller = new AbortController();
2729
2972
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2730
- try {
2731
- const response = await fetch(url, {
2732
- method: "GET",
2733
- headers: { "Accept": "application/json" },
2734
- signal: controller.signal
2735
- });
2736
- clearTimeout(timeoutId);
2737
- if (!response.ok) {
2738
- const errorText = await response.text();
2739
- throw new Erc8004LookupError(
2740
- `ERC-8004 API error: ${response.status} - ${errorText}`,
2741
- response.status,
2742
- errorText
2743
- );
2744
- }
2745
- return await response.json();
2746
- } catch (error) {
2747
- clearTimeout(timeoutId);
2748
- throw error;
2973
+ const response = await fetch(url, {
2974
+ method: "GET",
2975
+ headers: { Accept: "application/json" },
2976
+ signal: controller.signal
2977
+ }).finally(() => clearTimeout(timeoutId));
2978
+ if (!response.ok) {
2979
+ const info = await readFacilitatorError(response);
2980
+ throw new Erc8004LookupError(
2981
+ `ERC-8004 API error: ${info.status} - ${info.body}`,
2982
+ info.status,
2983
+ info.body,
2984
+ info.retryAfterSeconds
2985
+ );
2749
2986
  }
2987
+ return await response.json();
2750
2988
  }
2751
2989
  /**
2752
2990
  * Resolve agent registration file from agentURI
@@ -2855,34 +3093,28 @@ var Erc8004Client = class {
2855
3093
  */
2856
3094
  async submitFeedback(request) {
2857
3095
  const url = `${this.baseUrl}/feedback`;
2858
- const controller = new AbortController();
2859
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2860
3096
  try {
2861
- const response = await fetch(url, {
2862
- method: "POST",
2863
- headers: {
2864
- "Content-Type": "application/json",
2865
- "Accept": "application/json"
2866
- },
2867
- body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
2868
- signal: controller.signal
3097
+ const { response, error } = await this.writeJson(url, {
3098
+ ...request,
3099
+ network: wireNetwork(request.network)
2869
3100
  });
2870
- clearTimeout(timeoutId);
2871
- if (!response.ok) {
2872
- const errorText = await response.text();
3101
+ if (error) {
2873
3102
  return {
2874
3103
  success: false,
2875
- error: `Facilitator error: ${response.status} - ${errorText}`,
2876
- network: request.network
3104
+ error: error.error,
3105
+ network: request.network,
3106
+ ...failureFields(error)
2877
3107
  };
2878
3108
  }
2879
3109
  return await response.json();
2880
3110
  } catch (error) {
2881
- clearTimeout(timeoutId);
2882
3111
  return {
2883
3112
  success: false,
2884
3113
  error: error instanceof Error ? error.message : "Unknown error",
2885
- network: request.network
3114
+ network: request.network,
3115
+ retryable: true,
3116
+ safeToReplay: false,
3117
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
2886
3118
  };
2887
3119
  }
2888
3120
  }
@@ -2991,34 +3223,28 @@ var Erc8004Client = class {
2991
3223
  */
2992
3224
  async submitRelayedFeedback(request) {
2993
3225
  const url = `${this.baseUrl}/feedback/evm/submit`;
2994
- const controller = new AbortController();
2995
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2996
3226
  try {
2997
- const response = await fetch(url, {
2998
- method: "POST",
2999
- headers: {
3000
- "Content-Type": "application/json",
3001
- "Accept": "application/json"
3002
- },
3003
- body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
3004
- signal: controller.signal
3227
+ const { response, error } = await this.writeJson(url, {
3228
+ ...request,
3229
+ network: wireNetwork(request.network)
3005
3230
  });
3006
- clearTimeout(timeoutId);
3007
- if (!response.ok) {
3008
- const errorText = await response.text();
3231
+ if (error) {
3009
3232
  return {
3010
3233
  success: false,
3011
- error: `Facilitator error: ${response.status} - ${errorText}`,
3012
- network: request.network
3234
+ error: error.error,
3235
+ network: request.network,
3236
+ ...failureFields(error)
3013
3237
  };
3014
3238
  }
3015
3239
  return await response.json();
3016
3240
  } catch (error) {
3017
- clearTimeout(timeoutId);
3018
3241
  return {
3019
3242
  success: false,
3020
3243
  error: error instanceof Error ? error.message : "Unknown error",
3021
- network: request.network
3244
+ network: request.network,
3245
+ retryable: true,
3246
+ safeToReplay: false,
3247
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
3022
3248
  };
3023
3249
  }
3024
3250
  }
@@ -3034,8 +3260,6 @@ var Erc8004Client = class {
3034
3260
  */
3035
3261
  async revokeFeedback(network, agentId, feedbackIndex, options) {
3036
3262
  const url = `${this.baseUrl}/feedback/revoke`;
3037
- const controller = new AbortController();
3038
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3039
3263
  const payload = {
3040
3264
  x402Version: 1,
3041
3265
  network: wireNetwork(network),
@@ -3048,31 +3272,24 @@ var Erc8004Client = class {
3048
3272
  payload.originalFeedback = options.originalFeedback;
3049
3273
  }
3050
3274
  try {
3051
- const response = await fetch(url, {
3052
- method: "POST",
3053
- headers: {
3054
- "Content-Type": "application/json",
3055
- "Accept": "application/json"
3056
- },
3057
- body: JSON.stringify(payload),
3058
- signal: controller.signal
3059
- });
3060
- clearTimeout(timeoutId);
3061
- if (!response.ok) {
3062
- const errorText = await response.text();
3275
+ const { response, error } = await this.writeJson(url, payload);
3276
+ if (error) {
3063
3277
  return {
3064
3278
  success: false,
3065
- error: `Facilitator error: ${response.status} - ${errorText}`,
3066
- network
3279
+ error: error.error,
3280
+ network,
3281
+ ...failureFields(error)
3067
3282
  };
3068
3283
  }
3069
3284
  return await response.json();
3070
3285
  } catch (error) {
3071
- clearTimeout(timeoutId);
3072
3286
  return {
3073
3287
  success: false,
3074
3288
  error: error instanceof Error ? error.message : "Unknown error",
3075
- network
3289
+ network,
3290
+ retryable: true,
3291
+ safeToReplay: false,
3292
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
3076
3293
  };
3077
3294
  }
3078
3295
  }
@@ -3162,24 +3379,23 @@ var Erc8004Client = class {
3162
3379
  }
3163
3380
  /** Shared POST for the relay routes: a refusal is data, never a throw. */
3164
3381
  async postRelay(path, request, onError) {
3165
- const controller = new AbortController();
3166
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3167
3382
  try {
3168
- const response = await fetch(`${this.baseUrl}${path}`, {
3169
- method: "POST",
3170
- headers: { "Content-Type": "application/json", "Accept": "application/json" },
3171
- body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
3172
- signal: controller.signal
3383
+ const { response, error } = await this.writeJson(`${this.baseUrl}${path}`, {
3384
+ ...request,
3385
+ network: wireNetwork(request.network)
3173
3386
  });
3174
- clearTimeout(timeoutId);
3175
- if (!response.ok) {
3176
- const errorText = await response.text();
3177
- return { ...onError, error: `Facilitator error: ${response.status} - ${errorText}` };
3387
+ if (error) {
3388
+ return { ...onError, error: error.error, ...failureFields(error) };
3178
3389
  }
3179
3390
  return await response.json();
3180
3391
  } catch (error) {
3181
- clearTimeout(timeoutId);
3182
- return { ...onError, error: error instanceof Error ? error.message : "Unknown error" };
3392
+ return {
3393
+ ...onError,
3394
+ error: error instanceof Error ? error.message : "Unknown error",
3395
+ retryable: true,
3396
+ safeToReplay: false,
3397
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
3398
+ };
3183
3399
  }
3184
3400
  }
3185
3401
  /**
@@ -3216,8 +3432,6 @@ var Erc8004Client = class {
3216
3432
  */
3217
3433
  async appendResponse(network, agentId, feedbackIndex, response, options) {
3218
3434
  const url = `${this.baseUrl}/feedback/response`;
3219
- const controller = new AbortController();
3220
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3221
3435
  const payload = {
3222
3436
  x402Version: 1,
3223
3437
  network: wireNetwork(network),
@@ -3232,31 +3446,24 @@ var Erc8004Client = class {
3232
3446
  payload.sealHash = options.sealHash;
3233
3447
  }
3234
3448
  try {
3235
- const fetchResponse = await fetch(url, {
3236
- method: "POST",
3237
- headers: {
3238
- "Content-Type": "application/json",
3239
- "Accept": "application/json"
3240
- },
3241
- body: JSON.stringify(payload),
3242
- signal: controller.signal
3243
- });
3244
- clearTimeout(timeoutId);
3245
- if (!fetchResponse.ok) {
3246
- const errorText = await fetchResponse.text();
3449
+ const { response: fetchResponse, error } = await this.writeJson(url, payload);
3450
+ if (error) {
3247
3451
  return {
3248
3452
  success: false,
3249
- error: `Facilitator error: ${fetchResponse.status} - ${errorText}`,
3250
- network
3453
+ error: error.error,
3454
+ network,
3455
+ ...failureFields(error)
3251
3456
  };
3252
3457
  }
3253
3458
  return await fetchResponse.json();
3254
3459
  } catch (error) {
3255
- clearTimeout(timeoutId);
3256
3460
  return {
3257
3461
  success: false,
3258
3462
  error: error instanceof Error ? error.message : "Unknown error",
3259
- network
3463
+ network,
3464
+ retryable: true,
3465
+ safeToReplay: false,
3466
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
3260
3467
  };
3261
3468
  }
3262
3469
  }
@@ -3300,47 +3507,42 @@ var Erc8004Client = class {
3300
3507
  return jobToRegisterResponse(terminal, request.network);
3301
3508
  }
3302
3509
  const url = `${this.baseUrl}/register`;
3303
- const controller = new AbortController();
3304
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3305
3510
  try {
3306
- const response = await fetch(url, {
3307
- method: "POST",
3308
- headers: {
3309
- "Content-Type": "application/json",
3310
- "Accept": "application/json"
3311
- },
3312
- body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
3313
- signal: controller.signal
3511
+ const { response, error } = await this.writeJson(url, {
3512
+ ...request,
3513
+ network: wireNetwork(request.network)
3314
3514
  });
3315
- clearTimeout(timeoutId);
3316
- if (!response.ok) {
3317
- const errorText = await response.text();
3515
+ if (error) {
3318
3516
  try {
3319
- const parsed = JSON.parse(errorText);
3517
+ const parsed = JSON.parse(error.body);
3320
3518
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3321
3519
  return {
3322
3520
  ...parsed,
3323
- // Never let a 4xx body claim success, whatever it says.
3521
+ // Never let a non-2xx body claim success, whatever it says.
3324
3522
  success: false,
3325
- error: parsed.error ?? `Facilitator error: ${response.status}`,
3326
- network: parsed.network ?? request.network
3523
+ error: parsed.error ?? `Facilitator error: ${error.status}`,
3524
+ network: parsed.network ?? request.network,
3525
+ ...failureFields(error)
3327
3526
  };
3328
3527
  }
3329
3528
  } catch {
3330
3529
  }
3331
3530
  return {
3332
3531
  success: false,
3333
- error: `Facilitator error: ${response.status} - ${errorText}`,
3334
- network: request.network
3532
+ error: error.error,
3533
+ network: request.network,
3534
+ ...failureFields(error)
3335
3535
  };
3336
3536
  }
3337
3537
  return await response.json();
3338
3538
  } catch (error) {
3339
- clearTimeout(timeoutId);
3340
3539
  return {
3341
3540
  success: false,
3342
3541
  error: error instanceof Error ? error.message : "Unknown error",
3343
- network: request.network
3542
+ network: request.network,
3543
+ retryable: true,
3544
+ safeToReplay: false,
3545
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
3344
3546
  };
3345
3547
  }
3346
3548
  }
@@ -3358,33 +3560,20 @@ var Erc8004Client = class {
3358
3560
  */
3359
3561
  async registerAgentAsync(request) {
3360
3562
  const url = `${this.baseUrl}/register`;
3361
- const controller = new AbortController();
3362
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3363
- try {
3364
- const response = await fetch(url, {
3365
- method: "POST",
3366
- headers: {
3367
- "Content-Type": "application/json",
3368
- "Accept": "application/json",
3369
- "Prefer": "respond-async"
3370
- },
3371
- body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
3372
- signal: controller.signal
3373
- });
3374
- clearTimeout(timeoutId);
3375
- if (!response.ok) {
3376
- const errorText = await response.text();
3377
- throw new Erc8004LookupError(
3378
- `ERC-8004 API error: ${response.status} - ${errorText}`,
3379
- response.status,
3380
- errorText
3381
- );
3382
- }
3383
- return await response.json();
3384
- } catch (error) {
3385
- clearTimeout(timeoutId);
3386
- throw error;
3563
+ const { response, error } = await this.writeJson(
3564
+ url,
3565
+ { ...request, network: wireNetwork(request.network) },
3566
+ { Prefer: "respond-async" }
3567
+ );
3568
+ if (error) {
3569
+ throw new Erc8004LookupError(
3570
+ `ERC-8004 API error: ${error.status} - ${error.body}`,
3571
+ error.status,
3572
+ error.body,
3573
+ error.retryAfterSeconds
3574
+ );
3387
3575
  }
3576
+ return await response.json();
3388
3577
  }
3389
3578
  /**
3390
3579
  * Read the current state of an asynchronous registration.
@@ -3396,26 +3585,21 @@ var Erc8004Client = class {
3396
3585
  const url = `${this.baseUrl}/register/status/${encodeURIComponent(jobId)}`;
3397
3586
  const controller = new AbortController();
3398
3587
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3399
- try {
3400
- const response = await fetch(url, {
3401
- method: "GET",
3402
- headers: { "Accept": "application/json" },
3403
- signal: controller.signal
3404
- });
3405
- clearTimeout(timeoutId);
3406
- if (!response.ok) {
3407
- const errorText = await response.text();
3408
- throw new Erc8004LookupError(
3409
- `ERC-8004 API error: ${response.status} - ${errorText}`,
3410
- response.status,
3411
- errorText
3412
- );
3413
- }
3414
- return await response.json();
3415
- } catch (error) {
3416
- clearTimeout(timeoutId);
3417
- throw error;
3588
+ const response = await fetch(url, {
3589
+ method: "GET",
3590
+ headers: { Accept: "application/json" },
3591
+ signal: controller.signal
3592
+ }).finally(() => clearTimeout(timeoutId));
3593
+ if (!response.ok) {
3594
+ const info = await readFacilitatorError(response);
3595
+ throw new Erc8004LookupError(
3596
+ `ERC-8004 API error: ${info.status} - ${info.body}`,
3597
+ info.status,
3598
+ info.body,
3599
+ info.retryAfterSeconds
3600
+ );
3418
3601
  }
3602
+ return await response.json();
3419
3603
  }
3420
3604
  /**
3421
3605
  * Poll an asynchronous registration until it finishes.
@@ -3716,6 +3900,7 @@ var AdvancedEscrowClient = class {
3716
3900
  chainId;
3717
3901
  gasLimit;
3718
3902
  timeout;
3903
+ retries;
3719
3904
  contracts;
3720
3905
  signer;
3721
3906
  // ethers.Signer (legacy mode)
@@ -3752,6 +3937,7 @@ var AdvancedEscrowClient = class {
3752
3937
  this.chainId = options.chainId || 8453;
3753
3938
  this.gasLimit = options.gasLimit || 3e5;
3754
3939
  this.timeout = options.timeout || ESCROW_TIMEOUT_MS[this.chainId] || DEFAULT_ESCROW_TIMEOUT_MS;
3940
+ this.retries = options.retries;
3755
3941
  if (this.walletAdapter && !this.rpcUrl) {
3756
3942
  throw new Error(
3757
3943
  "AdvancedEscrowClient: rpcUrl is required when using a SigningWalletAdapter. The adapter signs transactions offline; an RPC provider is needed to build and broadcast them."
@@ -4124,16 +4310,19 @@ var AdvancedEscrowClient = class {
4124
4310
  }
4125
4311
  }
4126
4312
  };
4127
- const controller = new AbortController();
4128
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
4129
4313
  try {
4130
- const response = await fetch(`${this.facilitatorUrl}/settle`, {
4131
- method: "POST",
4132
- headers: { "Content-Type": "application/json" },
4133
- body: JSON.stringify(payload),
4134
- signal: controller.signal
4135
- });
4136
- clearTimeout(timeoutId);
4314
+ const { response, error } = await facilitatorFetch(
4315
+ `${this.facilitatorUrl}/settle`,
4316
+ {
4317
+ method: "POST",
4318
+ headers: { "Content-Type": "application/json" },
4319
+ body: JSON.stringify(payload)
4320
+ },
4321
+ { timeoutMs: this.timeout, retries: this.retries }
4322
+ );
4323
+ if (error) {
4324
+ return { success: false, error: error.error, ...failureFields(error) };
4325
+ }
4137
4326
  const result = await response.json();
4138
4327
  if (result.success) {
4139
4328
  return {
@@ -4146,7 +4335,6 @@ var AdvancedEscrowClient = class {
4146
4335
  error: result.errorReason || result.error || `Release refused with no reason (HTTP ${response.status}, body keys: ${Object.keys(result ?? {}).sort().join(", ") || "none"})`
4147
4336
  };
4148
4337
  } catch (fetchErr) {
4149
- clearTimeout(timeoutId);
4150
4338
  if (fetchErr.name === "AbortError") {
4151
4339
  try {
4152
4340
  const state = await this.queryEscrowState(paymentInfo);
@@ -4164,23 +4352,53 @@ var AdvancedEscrowClient = class {
4164
4352
  }
4165
4353
  }
4166
4354
  /**
4167
- * GASLESS REFUND: Refund escrowed funds via the facilitator.
4355
+ * GASLESS REFUND: return escrowed funds to the payer via the facilitator.
4168
4356
  *
4169
- * Instead of calling the PaymentOperator contract directly (which requires
4170
- * gas), this sends a refundInEscrow request to the facilitator, which
4171
- * submits the transaction on your behalf.
4357
+ * Sends `action: "refundInEscrow"` to `POST /settle`; the facilitator's
4358
+ * PaymentOperator calls `AuthCaptureEscrow.partialVoid`.
4359
+ *
4360
+ * # This is how an EXPIRED escrow is recovered
4361
+ *
4362
+ * A widely repeated claim — including in this SDK's own comments until now —
4363
+ * says that once `authorizationExpiry` passes, only the payer's `reclaim()`
4364
+ * can move the funds. **That is false, and believing it has left real money
4365
+ * stranded.**
4366
+ *
4367
+ * Read the contract (`AuthCaptureEscrow.sol`):
4368
+ *
4369
+ * - `partialVoid` is `onlySender(paymentInfo.operator)` — the operator is the
4370
+ * FACILITATOR, not the payer — it sends the tokens **to the payer**, and it
4371
+ * **does not check `authorizationExpiry` at all**. It works before expiry
4372
+ * and after it, and the payer never has to appear.
4373
+ * - `reclaim` is `onlySender(paymentInfo.payer)` and only after expiry. It is
4374
+ * a payer's self-service escape hatch, which is why this facilitator does
4375
+ * not expose it — **not** the only way out.
4376
+ *
4377
+ * So a release that reverted with `AfterAuthorizationExpiry` is recoverable
4378
+ * from here, with no gas and no cooperation from the payer. Get the amount
4379
+ * from {@link queryEscrowState}'s `capturableAmount`.
4380
+ *
4381
+ * # A refusal that is not a refusal
4382
+ *
4383
+ * Check `retryable` before writing an escrow off. A `503` means the
4384
+ * facilitator never reached the chain — the escrow is untouched and the same
4385
+ * request should be sent again.
4172
4386
  *
4173
4387
  * @param paymentInfo - PaymentInfo from the authorize step
4174
- * @param amount - Amount to refund in atomic units (defaults to maxAmount)
4388
+ * @param amount - Amount to refund in atomic units (defaults to maxAmount).
4389
+ * For a stuck escrow pass `capturableAmount` from {@link queryEscrowState}.
4175
4390
  * @returns Transaction result from the facilitator
4176
4391
  *
4177
- * @example
4392
+ * @example Recovering an escrow whose release window already closed
4178
4393
  * ```typescript
4179
- * const pi = client.buildPaymentInfo('0xWorker...', '5000000', 'standard');
4180
- * await client.authorize(pi);
4181
- * // Task cancelled...
4182
- * const result = await client.refundViaFacilitator(pi);
4183
- * console.log(result.transactionHash);
4394
+ * const state = await client.queryEscrowState(pi);
4395
+ * if (state.capturableAmount !== '0') {
4396
+ * // No payer needed, no gas, and expiry is irrelevant to partialVoid.
4397
+ * const result = await client.refundViaFacilitator(pi, state.capturableAmount);
4398
+ * if (!result.success && result.retryable) {
4399
+ * // No verdict was reached. The funds are still there; send it again.
4400
+ * }
4401
+ * }
4184
4402
  * ```
4185
4403
  */
4186
4404
  async refundViaFacilitator(paymentInfo, amount) {
@@ -4217,16 +4435,19 @@ var AdvancedEscrowClient = class {
4217
4435
  }
4218
4436
  }
4219
4437
  };
4220
- const controller = new AbortController();
4221
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
4222
4438
  try {
4223
- const response = await fetch(`${this.facilitatorUrl}/settle`, {
4224
- method: "POST",
4225
- headers: { "Content-Type": "application/json" },
4226
- body: JSON.stringify(payload),
4227
- signal: controller.signal
4228
- });
4229
- clearTimeout(timeoutId);
4439
+ const { response, error } = await facilitatorFetch(
4440
+ `${this.facilitatorUrl}/settle`,
4441
+ {
4442
+ method: "POST",
4443
+ headers: { "Content-Type": "application/json" },
4444
+ body: JSON.stringify(payload)
4445
+ },
4446
+ { timeoutMs: this.timeout, retries: this.retries }
4447
+ );
4448
+ if (error) {
4449
+ return { success: false, error: error.error, ...failureFields(error) };
4450
+ }
4230
4451
  const result = await response.json();
4231
4452
  if (result.success) {
4232
4453
  return {
@@ -4234,9 +4455,11 @@ var AdvancedEscrowClient = class {
4234
4455
  transactionHash: result.transaction || result.transactionHash || result.transaction_hash
4235
4456
  };
4236
4457
  }
4237
- return { success: false, error: result.errorReason || result.error || "Refund failed" };
4458
+ return {
4459
+ success: false,
4460
+ error: result.errorReason || result.error || `Refund refused with no reason (HTTP ${response.status}, body keys: ${Object.keys(result ?? {}).sort().join(", ") || "none"})`
4461
+ };
4238
4462
  } catch (fetchErr) {
4239
- clearTimeout(timeoutId);
4240
4463
  if (fetchErr.name === "AbortError") {
4241
4464
  try {
4242
4465
  const state = await this.queryEscrowState(paymentInfo);
@@ -4462,9 +4685,12 @@ var AdvancedEscrowClient = class {
4462
4685
  }
4463
4686
  };
4464
4687
 
4688
+ exports.AMBIGUOUS_LEASE_REASONS = AMBIGUOUS_LEASE_REASONS;
4465
4689
  exports.AdvancedEscrowClient = AdvancedEscrowClient;
4466
4690
  exports.BASE_MAINNET_CONTRACTS = BASE_MAINNET_CONTRACTS;
4467
4691
  exports.BazaarClient = BazaarClient;
4692
+ exports.DEFAULT_FACILITATOR_RETRIES = DEFAULT_FACILITATOR_RETRIES;
4693
+ exports.DEFAULT_RETRY_AFTER_SECONDS = DEFAULT_RETRY_AFTER_SECONDS;
4468
4694
  exports.DEPOSIT_LIMIT_USDC = DEPOSIT_LIMIT_USDC;
4469
4695
  exports.ERC8004_CONTRACTS = ERC8004_CONTRACTS;
4470
4696
  exports.ERC8004_EXTENSION_ID = ERC8004_EXTENSION_ID;
@@ -4475,15 +4701,18 @@ exports.Erc8004LookupError = Erc8004LookupError;
4475
4701
  exports.EscrowClient = EscrowClient;
4476
4702
  exports.FacilitatorClient = FacilitatorClient;
4477
4703
  exports.HEALTH_FILTERS = HEALTH_FILTERS;
4704
+ exports.MAX_RETRY_AFTER_SECONDS = MAX_RETRY_AFTER_SECONDS;
4478
4705
  exports.MAX_SEARCH_LEN = MAX_SEARCH_LEN;
4479
4706
  exports.OPERATOR_ABI = OPERATOR_ABI;
4480
4707
  exports.OPERATOR_ABI_CREATE3 = OPERATOR_ABI_CREATE3;
4481
4708
  exports.PAYMENT_INFO_TYPEHASH = PAYMENT_INFO_TYPEHASH;
4482
4709
  exports.RELAYED_FEEDBACK_NETWORKS = RELAYED_FEEDBACK_NETWORKS;
4710
+ exports.REPLAYABLE_LEASE_REASONS = REPLAYABLE_LEASE_REASONS;
4483
4711
  exports.RegistrationPendingError = RegistrationPendingError;
4484
4712
  exports.TIER_FILTERS = TIER_FILTERS;
4485
4713
  exports.TIER_TIMINGS = TIER_TIMINGS;
4486
4714
  exports.USDC_DOMAIN_NAME = USDC_DOMAIN_NAME;
4715
+ exports.WRITER_LEASE_REASONS = WRITER_LEASE_REASONS;
4487
4716
  exports.X402_CORS_HEADERS = X402_CORS_HEADERS;
4488
4717
  exports.X402_HEADER_NAMES = X402_HEADER_NAMES;
4489
4718
  exports.ZERO_ADDRESS = ZERO_ADDRESS;
@@ -4495,20 +4724,26 @@ exports.buildVerifyRequest = buildVerifyRequest;
4495
4724
  exports.buildVerifyRequestV2 = buildVerifyRequestV2;
4496
4725
  exports.canRefundEscrow = canRefundEscrow;
4497
4726
  exports.canReleaseEscrow = canReleaseEscrow;
4727
+ exports.carryFailureFields = carryFailureFields;
4498
4728
  exports.create402Response = create402Response;
4499
4729
  exports.createHonoMiddleware = createHonoMiddleware;
4500
4730
  exports.createPaymentMiddleware = createPaymentMiddleware;
4501
4731
  exports.epochToDate = epochToDate;
4502
4732
  exports.escrowTimeRemaining = escrowTimeRemaining;
4503
4733
  exports.extractPaymentFromHeaders = extractPaymentFromHeaders;
4734
+ exports.facilitatorFetch = facilitatorFetch;
4504
4735
  exports.getCorsHeaders = getCorsHeaders;
4505
4736
  exports.getEscrowContractsByChainId = getEscrowContractsByChainId;
4506
4737
  exports.getEscrowSupportedChainIds = getEscrowSupportedChainIds;
4507
4738
  exports.isAlive = isAlive;
4739
+ exports.isAmbiguousLeaseReason = isAmbiguousLeaseReason;
4508
4740
  exports.isEscrowExpired = isEscrowExpired;
4509
4741
  exports.isEscrowSupportedOnChain = isEscrowSupportedOnChain;
4510
4742
  exports.isRegisterJobTerminal = isRegisterJobTerminal;
4743
+ exports.isReplayableLeaseReason = isReplayableLeaseReason;
4511
4744
  exports.parsePaymentHeader = parsePaymentHeader;
4745
+ exports.parseRetryAfterSeconds = parseRetryAfterSeconds;
4746
+ exports.readFacilitatorError = readFacilitatorError;
4512
4747
  exports.supportsRelayedFeedback = supportsRelayedFeedback;
4513
4748
  exports.wireNetwork = wireNetwork;
4514
4749
  //# sourceMappingURL=index.js.map