@pafi-dev/issuer 0.7.0 → 0.7.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
@@ -20,12 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AdapterMisconfiguredError: () => AdapterMisconfiguredError,
23
24
  AuthError: () => AuthError,
24
25
  AuthService: () => AuthService,
25
26
  BalanceAggregator: () => BalanceAggregator,
26
27
  BundlerNotConfiguredError: () => BundlerNotConfiguredError,
27
28
  BundlerRejectedError: () => BundlerRejectedError,
28
29
  BurnIndexer: () => BurnIndexer,
30
+ ConfigurationError: () => ConfigurationError,
29
31
  DefaultPolicyEngine: () => DefaultPolicyEngine,
30
32
  FeeManager: () => FeeManager,
31
33
  InMemoryCursorStore: () => InMemoryCursorStore,
@@ -53,6 +55,7 @@ __export(index_exports, {
53
55
  PointIndexer: () => PointIndexer,
54
56
  RelayError: () => RelayError,
55
57
  RelayService: () => RelayService,
58
+ ValidationError: () => ValidationError,
56
59
  authenticateRequest: () => authenticateRequest,
57
60
  createIssuerService: () => createIssuerService,
58
61
  createNativePtQuoter: () => createNativePtQuoter,
@@ -88,6 +91,26 @@ var PafiSdkError = class extends Error {
88
91
  this.name = new.target.name;
89
92
  }
90
93
  };
94
+ var ValidationError = class extends PafiSdkError {
95
+ httpStatus = "unprocessable";
96
+ code;
97
+ details;
98
+ constructor(code, message, details) {
99
+ super(message);
100
+ this.code = code;
101
+ this.details = details;
102
+ }
103
+ };
104
+ var ConfigurationError = class extends PafiSdkError {
105
+ httpStatus = "service_unavailable";
106
+ code;
107
+ details;
108
+ constructor(code, message, details) {
109
+ super(message);
110
+ this.code = code;
111
+ this.details = details;
112
+ }
113
+ };
91
114
 
92
115
  // src/policy/defaultPolicy.ts
93
116
  var DefaultPolicyEngine = class {
@@ -258,12 +281,32 @@ var import_viem2 = require("viem");
258
281
  var import_core = require("@pafi-dev/core");
259
282
 
260
283
  // src/auth/errors.ts
261
- var AuthError = class extends Error {
284
+ function statusForCode(code) {
285
+ switch (code) {
286
+ case "INVALID_MESSAGE":
287
+ case "DOMAIN_MISMATCH":
288
+ case "CHAIN_MISMATCH":
289
+ case "MESSAGE_EXPIRED":
290
+ case "MESSAGE_NOT_YET_VALID":
291
+ case "MALFORMED_TOKEN":
292
+ return "unprocessable";
293
+ case "NONCE_INVALID":
294
+ case "SIGNATURE_INVALID":
295
+ case "MISSING_TOKEN":
296
+ case "TOKEN_INVALID":
297
+ case "TOKEN_EXPIRED":
298
+ return "forbidden";
299
+ case "SESSION_REVOKED":
300
+ return "not_found";
301
+ }
302
+ }
303
+ var AuthError = class extends PafiSdkError {
262
304
  code;
305
+ httpStatus;
263
306
  constructor(code, message) {
264
307
  super(message);
265
- this.name = "AuthError";
266
308
  this.code = code;
309
+ this.httpStatus = statusForCode(code);
267
310
  }
268
311
  };
269
312
 
@@ -460,14 +503,15 @@ async function authenticateRequest(authHeader, authService) {
460
503
  }
461
504
 
462
505
  // src/relay/types.ts
463
- var RelayError = class extends Error {
506
+ var RelayError = class extends PafiSdkError {
507
+ httpStatus = "unprocessable";
464
508
  code;
465
- cause;
466
509
  constructor(code, message, cause) {
467
510
  super(message);
468
- this.name = "RelayError";
469
511
  this.code = code;
470
- if (cause !== void 0) this.cause = cause;
512
+ if (cause !== void 0) {
513
+ this.cause = cause;
514
+ }
471
515
  }
472
516
  };
473
517
 
@@ -1168,13 +1212,16 @@ var IssuerApiHandlers = class {
1168
1212
  /** `POST /auth/login` */
1169
1213
  async handleLogin(body) {
1170
1214
  if (!body || typeof body.message !== "string" || body.message.length === 0 || typeof body.signature !== "string" || body.signature.length <= 2) {
1171
- throw new Error("handleLogin: message and signature are required");
1215
+ throw new ValidationError(
1216
+ "INVALID_LOGIN_BODY",
1217
+ "handleLogin: message and signature are required"
1218
+ );
1172
1219
  }
1173
1220
  if (body.message.length > 4096) {
1174
- throw new Error("message too long");
1221
+ throw new ValidationError("MESSAGE_TOO_LONG", "message too long");
1175
1222
  }
1176
1223
  if (body.signature.length > 260) {
1177
- throw new Error("signature too long");
1224
+ throw new ValidationError("SIGNATURE_TOO_LONG", "signature too long");
1178
1225
  }
1179
1226
  const result = await this.authService.login(body.message, body.signature);
1180
1227
  return {
@@ -1191,11 +1238,15 @@ var IssuerApiHandlers = class {
1191
1238
  */
1192
1239
  async handleConfig(chainId) {
1193
1240
  if (!Number.isInteger(chainId) || chainId <= 0) {
1194
- throw new Error("invalid chainId");
1241
+ throw new ValidationError("INVALID_CHAIN_ID", "invalid chainId", {
1242
+ chainId
1243
+ });
1195
1244
  }
1196
1245
  if (chainId !== this.chainId) {
1197
- throw new Error(
1198
- `handleConfig: unsupported chainId ${chainId}`
1246
+ throw new ValidationError(
1247
+ "UNSUPPORTED_CHAIN_ID",
1248
+ `handleConfig: unsupported chainId ${chainId}`,
1249
+ { requested: chainId, supported: this.chainId }
1199
1250
  );
1200
1251
  }
1201
1252
  const contracts = {
@@ -1212,7 +1263,8 @@ var IssuerApiHandlers = class {
1212
1263
  /** `GET /gas-fee` — quoted in USDT (6-decimal base units). */
1213
1264
  async handleGasFee() {
1214
1265
  if (!this.feeManager) {
1215
- throw new Error(
1266
+ throw new ConfigurationError(
1267
+ "FEE_MANAGER_NOT_CONFIGURED",
1216
1268
  "handleGasFee: feeManager is not configured on this issuer"
1217
1269
  );
1218
1270
  }
@@ -1234,13 +1286,16 @@ var IssuerApiHandlers = class {
1234
1286
  */
1235
1287
  async handlePools(_userAddress, request) {
1236
1288
  if (!this.poolsProvider) {
1237
- throw new Error(
1289
+ throw new ConfigurationError(
1290
+ "POOLS_PROVIDER_NOT_CONFIGURED",
1238
1291
  "handlePools: poolsProvider is not configured on this issuer"
1239
1292
  );
1240
1293
  }
1241
1294
  if (request.chainId !== this.chainId) {
1242
- throw new Error(
1243
- `handlePools: unsupported chainId ${request.chainId}`
1295
+ throw new ValidationError(
1296
+ "UNSUPPORTED_CHAIN_ID",
1297
+ `handlePools: unsupported chainId ${request.chainId}`,
1298
+ { requested: request.chainId, supported: this.chainId }
1244
1299
  );
1245
1300
  }
1246
1301
  return this.poolsProvider(request);
@@ -1254,21 +1309,27 @@ var IssuerApiHandlers = class {
1254
1309
  */
1255
1310
  async handleUser(userAddress, request) {
1256
1311
  if (request.chainId !== this.chainId) {
1257
- throw new Error(
1258
- `handleUser: unsupported chainId ${request.chainId}`
1312
+ throw new ValidationError(
1313
+ "UNSUPPORTED_CHAIN_ID",
1314
+ `handleUser: unsupported chainId ${request.chainId}`,
1315
+ { requested: request.chainId, supported: this.chainId }
1259
1316
  );
1260
1317
  }
1261
1318
  const normalizedAuthed = (0, import_viem6.getAddress)(userAddress);
1262
1319
  const normalizedRequest = (0, import_viem6.getAddress)(request.userAddress);
1263
1320
  if (normalizedAuthed !== normalizedRequest) {
1264
- throw new Error(
1265
- "handleUser: request userAddress must match authenticated user"
1321
+ throw new ValidationError(
1322
+ "USER_ADDRESS_MISMATCH",
1323
+ "handleUser: request userAddress must match authenticated user",
1324
+ { authenticated: normalizedAuthed, requested: normalizedRequest }
1266
1325
  );
1267
1326
  }
1268
1327
  const pointToken = (0, import_viem6.getAddress)(request.pointTokenAddress);
1269
1328
  if (!this.supportedTokens.has(pointToken)) {
1270
- throw new Error(
1271
- `handleUser: unsupported pointToken ${pointToken}`
1329
+ throw new ValidationError(
1330
+ "UNSUPPORTED_POINT_TOKEN",
1331
+ `handleUser: unsupported pointToken ${pointToken}`,
1332
+ { requested: pointToken }
1272
1333
  );
1273
1334
  }
1274
1335
  const [mintRequestNonce, receiverConsentNonce, offChainBalance, onChainBalance, minter] = await Promise.all([
@@ -1464,69 +1525,82 @@ var PTRedeemHandler = class {
1464
1525
  this.redeemLockDurationMs,
1465
1526
  this.pointTokenAddress
1466
1527
  );
1467
- const sponsoredUserOp = await this.relayService.prepareBurn({
1468
- mode: "burnWithSig",
1469
- userAddress: request.userAddress,
1470
- aaNonce: request.aaNonce,
1471
- pointTokenAddress: this.pointTokenAddress,
1472
- batchExecutorAddress: this.batchExecutorAddress,
1473
- burnRequest: sponsoredBurnRequest,
1474
- burnerSignature: sponsoredSig,
1475
- feeAmount: fee,
1476
- feeRecipient
1477
- });
1478
- let fallback = void 0;
1479
- if (fee > 0n) {
1480
- const fallbackBurnRequest = {
1481
- from: request.userAddress,
1482
- amount: request.amount,
1483
- nonce: burnNonce,
1484
- deadline
1485
- };
1486
- let fallbackSig;
1487
- try {
1488
- fallbackSig = (await (0, import_core4.signBurnRequest)(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
1489
- } catch (err) {
1490
- throw new PTRedeemError(
1491
- "SIGNING_FAILED",
1492
- `failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
1493
- );
1494
- }
1495
- const fallbackLockId = await this.ledger.reservePendingCredit(
1496
- request.userAddress,
1497
- request.amount,
1498
- this.redeemLockDurationMs,
1499
- this.pointTokenAddress
1500
- );
1501
- const fallbackUserOp = await this.relayService.prepareBurn({
1528
+ try {
1529
+ const sponsoredUserOp = await this.relayService.prepareBurn({
1502
1530
  mode: "burnWithSig",
1503
1531
  userAddress: request.userAddress,
1504
1532
  aaNonce: request.aaNonce,
1505
1533
  pointTokenAddress: this.pointTokenAddress,
1506
1534
  batchExecutorAddress: this.batchExecutorAddress,
1507
- burnRequest: fallbackBurnRequest,
1508
- burnerSignature: fallbackSig,
1509
- // Explicit 0n — fallback is fee-free regardless of how
1510
- // RelayService is configured. Without this, an
1511
- // auto-quoting RelayService would try to quote a fee here
1512
- // and re-add the PT.transfer we're trying to strip.
1513
- feeAmount: 0n
1535
+ burnRequest: sponsoredBurnRequest,
1536
+ burnerSignature: sponsoredSig,
1537
+ feeAmount: fee,
1538
+ feeRecipient
1514
1539
  });
1515
- fallback = {
1516
- lockId: fallbackLockId,
1517
- userOp: fallbackUserOp,
1518
- netCreditAmount: request.amount
1540
+ let fallback = void 0;
1541
+ if (fee > 0n) {
1542
+ const fallbackBurnRequest = {
1543
+ from: request.userAddress,
1544
+ amount: request.amount,
1545
+ nonce: burnNonce,
1546
+ deadline
1547
+ };
1548
+ let fallbackSig;
1549
+ try {
1550
+ fallbackSig = (await (0, import_core4.signBurnRequest)(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
1551
+ } catch (err) {
1552
+ throw new PTRedeemError(
1553
+ "SIGNING_FAILED",
1554
+ `failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
1555
+ );
1556
+ }
1557
+ const fallbackLockId = await this.ledger.reservePendingCredit(
1558
+ request.userAddress,
1559
+ request.amount,
1560
+ this.redeemLockDurationMs,
1561
+ this.pointTokenAddress
1562
+ );
1563
+ let fallbackUserOp;
1564
+ try {
1565
+ fallbackUserOp = await this.relayService.prepareBurn({
1566
+ mode: "burnWithSig",
1567
+ userAddress: request.userAddress,
1568
+ aaNonce: request.aaNonce,
1569
+ pointTokenAddress: this.pointTokenAddress,
1570
+ batchExecutorAddress: this.batchExecutorAddress,
1571
+ burnRequest: fallbackBurnRequest,
1572
+ burnerSignature: fallbackSig,
1573
+ // Explicit 0n — fallback is fee-free regardless of how
1574
+ // RelayService is configured. Without this, an
1575
+ // auto-quoting RelayService would try to quote a fee here
1576
+ // and re-add the PT.transfer we're trying to strip.
1577
+ feeAmount: 0n
1578
+ });
1579
+ } catch (err) {
1580
+ await this.ledger.releaseLock(fallbackLockId).catch(() => {
1581
+ });
1582
+ throw err;
1583
+ }
1584
+ fallback = {
1585
+ lockId: fallbackLockId,
1586
+ userOp: fallbackUserOp,
1587
+ netCreditAmount: request.amount
1588
+ };
1589
+ }
1590
+ return {
1591
+ lockId: sponsoredLockId,
1592
+ userOp: sponsoredUserOp,
1593
+ netCreditAmount: sponsoredBurnAmount,
1594
+ feeAmount: fee,
1595
+ fallback,
1596
+ expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
1597
+ signatureDeadline: deadline
1519
1598
  };
1599
+ } catch (err) {
1600
+ await this.ledger.releaseLock(sponsoredLockId).catch(() => {
1601
+ });
1602
+ throw err;
1520
1603
  }
1521
- return {
1522
- lockId: sponsoredLockId,
1523
- userOp: sponsoredUserOp,
1524
- netCreditAmount: sponsoredBurnAmount,
1525
- feeAmount: fee,
1526
- fallback,
1527
- expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
1528
- signatureDeadline: deadline
1529
- };
1530
1604
  }
1531
1605
  };
1532
1606
 
@@ -1794,6 +1868,41 @@ async function prepareMobileUserOp(params) {
1794
1868
  };
1795
1869
  }
1796
1870
 
1871
+ // src/pafi-backend/types.ts
1872
+ var PafiBackendError = class extends Error {
1873
+ constructor(code, message, httpStatus, details, opts) {
1874
+ super(message);
1875
+ this.code = code;
1876
+ this.httpStatus = httpStatus;
1877
+ this.details = details;
1878
+ this.name = "PafiBackendError";
1879
+ if (opts?.retryAfter !== void 0) this.retryAfter = opts.retryAfter;
1880
+ if (opts?.safeToRetry !== void 0) this.serverSafeToRetry = opts.safeToRetry;
1881
+ }
1882
+ code;
1883
+ httpStatus;
1884
+ details;
1885
+ retryAfter;
1886
+ serverSafeToRetry;
1887
+ get safeToRetry() {
1888
+ if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
1889
+ switch (this.code) {
1890
+ case "RATE_LIMITER_UNAVAILABLE":
1891
+ case "INTERNAL_ERROR":
1892
+ case "TIMEOUT":
1893
+ case "NETWORK_ERROR":
1894
+ return true;
1895
+ case "RATE_LIMIT_EXCEEDED":
1896
+ case "RATE_LIMIT_EXCEEDED_DAILY":
1897
+ case "RATE_LIMIT_EXCEEDED_PER_USER":
1898
+ case "ISSUER_BUDGET_EXCEEDED":
1899
+ return true;
1900
+ default:
1901
+ return false;
1902
+ }
1903
+ }
1904
+ };
1905
+
1797
1906
  // src/pafi-backend/helpers.ts
1798
1907
  var BundlerNotConfiguredError = class extends PafiSdkError {
1799
1908
  code = "BUNDLER_NOT_CONFIGURED";
@@ -1829,8 +1938,23 @@ async function requestPaymaster(params) {
1829
1938
  });
1830
1939
  } catch (err) {
1831
1940
  const msg = err instanceof Error ? err.message : String(err);
1832
- params.onWarning?.(`Paymaster sponsorship declined: ${msg}`);
1833
- return void 0;
1941
+ if (err instanceof PafiBackendError && isTransientPaymasterError(err.code)) {
1942
+ params.onWarning?.(`Paymaster sponsorship declined (transient): ${msg}`);
1943
+ return void 0;
1944
+ }
1945
+ throw err;
1946
+ }
1947
+ }
1948
+ function isTransientPaymasterError(code) {
1949
+ switch (code) {
1950
+ case "NETWORK_ERROR":
1951
+ case "TIMEOUT":
1952
+ case "PAYMASTER_UNAVAILABLE":
1953
+ case "RATE_LIMITER_UNAVAILABLE":
1954
+ case "INTERNAL_ERROR":
1955
+ return true;
1956
+ default:
1957
+ return false;
1834
1958
  }
1835
1959
  }
1836
1960
  function defaultFunctionForScenario(scenario) {
@@ -2011,39 +2135,19 @@ var PTClaimHandler = class {
2011
2135
  this.cfg.lockDurationMs,
2012
2136
  request.pointTokenAddress
2013
2137
  );
2014
- const signatureDeadline = BigInt(
2015
- Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
2016
- );
2017
- const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
2018
- const domain = {
2019
- name: this.cfg.pointTokenDomainName,
2020
- chainId: request.chainId,
2021
- verifyingContract: request.pointTokenAddress
2022
- };
2023
- let userOp;
2024
2138
  try {
2025
- userOp = await this.cfg.relayService.prepareMint({
2026
- userAddress: request.userAddress,
2027
- aaNonce: request.aaNonce,
2028
- batchExecutorAddress,
2029
- pointTokenAddress: request.pointTokenAddress,
2030
- amount: request.amount,
2031
- issuerSignerWallet: this.cfg.issuerSignerWallet,
2032
- domain,
2033
- mintRequestNonce: request.mintRequestNonce,
2034
- deadline: signatureDeadline
2035
- // No feeAmount/feeRecipient — RelayService auto-resolves.
2036
- });
2037
- } catch (err) {
2038
- throw new PTClaimError(
2039
- "BUILD_FAILED",
2040
- `prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
2139
+ const signatureDeadline = BigInt(
2140
+ Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
2041
2141
  );
2042
- }
2043
- let fallback;
2044
- if (feeAmount > 0n) {
2142
+ const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
2143
+ const domain = {
2144
+ name: this.cfg.pointTokenDomainName,
2145
+ chainId: request.chainId,
2146
+ verifyingContract: request.pointTokenAddress
2147
+ };
2148
+ let userOp;
2045
2149
  try {
2046
- fallback = await this.cfg.relayService.prepareMint({
2150
+ userOp = await this.cfg.relayService.prepareMint({
2047
2151
  userAddress: request.userAddress,
2048
2152
  aaNonce: request.aaNonce,
2049
2153
  batchExecutorAddress,
@@ -2052,28 +2156,54 @@ var PTClaimHandler = class {
2052
2156
  issuerSignerWallet: this.cfg.issuerSignerWallet,
2053
2157
  domain,
2054
2158
  mintRequestNonce: request.mintRequestNonce,
2055
- deadline: signatureDeadline,
2056
- feeAmount: 0n
2159
+ deadline: signatureDeadline
2160
+ // No feeAmount/feeRecipient — RelayService auto-resolves.
2057
2161
  });
2058
2162
  } catch (err) {
2059
2163
  throw new PTClaimError(
2060
2164
  "BUILD_FAILED",
2061
- `prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
2165
+ `prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
2062
2166
  );
2063
2167
  }
2168
+ let fallback;
2169
+ if (feeAmount > 0n) {
2170
+ try {
2171
+ fallback = await this.cfg.relayService.prepareMint({
2172
+ userAddress: request.userAddress,
2173
+ aaNonce: request.aaNonce,
2174
+ batchExecutorAddress,
2175
+ pointTokenAddress: request.pointTokenAddress,
2176
+ amount: request.amount,
2177
+ issuerSignerWallet: this.cfg.issuerSignerWallet,
2178
+ domain,
2179
+ mintRequestNonce: request.mintRequestNonce,
2180
+ deadline: signatureDeadline,
2181
+ feeAmount: 0n
2182
+ });
2183
+ } catch (err) {
2184
+ throw new PTClaimError(
2185
+ "BUILD_FAILED",
2186
+ `prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
2187
+ );
2188
+ }
2189
+ }
2190
+ const calls = (0, import_core8.decodeBatchExecuteCalls)(userOp.callData);
2191
+ const callsFallback = fallback ? (0, import_core8.decodeBatchExecuteCalls)(fallback.callData) : void 0;
2192
+ return {
2193
+ userOp,
2194
+ fallback,
2195
+ lockId,
2196
+ feeAmount,
2197
+ signatureDeadline,
2198
+ expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
2199
+ calls,
2200
+ callsFallback
2201
+ };
2202
+ } catch (err) {
2203
+ await this.cfg.ledger.releaseLock(lockId).catch(() => {
2204
+ });
2205
+ throw err;
2064
2206
  }
2065
- const calls = (0, import_core8.decodeBatchExecuteCalls)(userOp.callData);
2066
- const callsFallback = fallback ? (0, import_core8.decodeBatchExecuteCalls)(fallback.callData) : void 0;
2067
- return {
2068
- userOp,
2069
- fallback,
2070
- lockId,
2071
- feeAmount,
2072
- signatureDeadline,
2073
- expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
2074
- calls,
2075
- callsFallback
2076
- };
2077
2207
  }
2078
2208
  };
2079
2209
 
@@ -2303,9 +2433,45 @@ function createSdkErrorMapper(factories) {
2303
2433
  // src/api/issuerApiAdapter.ts
2304
2434
  var import_viem10 = require("viem");
2305
2435
  var import_core11 = require("@pafi-dev/core");
2436
+ var AdapterMisconfiguredError = class extends Error {
2437
+ code = "ADAPTER_MISCONFIGURED";
2438
+ constructor(message) {
2439
+ super(message);
2440
+ this.name = "AdapterMisconfiguredError";
2441
+ }
2442
+ };
2306
2443
  var IssuerApiAdapter = class {
2307
2444
  cfg;
2308
2445
  constructor(config) {
2446
+ if (config.ptClaimHandler) {
2447
+ if (typeof config.ledger.bindMintUserOpHash !== "function") {
2448
+ throw new AdapterMisconfiguredError(
2449
+ "ledger.bindMintUserOpHash is required when ptClaimHandler is wired (mobile claim flow). Implement it on your IPointLedger or omit ptClaimHandler from IssuerApiAdapter config."
2450
+ );
2451
+ }
2452
+ if (typeof config.ledger.getMintLock !== "function") {
2453
+ throw new AdapterMisconfiguredError(
2454
+ "ledger.getMintLock is required when ptClaimHandler is wired \u2014 claimStatus uses it to look up the lock."
2455
+ );
2456
+ }
2457
+ }
2458
+ if (config.ptRedeemHandler) {
2459
+ if (typeof config.ledger.reservePendingCredit !== "function") {
2460
+ throw new AdapterMisconfiguredError(
2461
+ "ledger.reservePendingCredit is required when ptRedeemHandler is wired (burn/redeem reverse flow). PTRedeemHandler also enforces this at construction; see ledger/types.ts comments."
2462
+ );
2463
+ }
2464
+ if (typeof config.ledger.bindCreditUserOpHash !== "function") {
2465
+ throw new AdapterMisconfiguredError(
2466
+ "ledger.bindCreditUserOpHash is required when ptRedeemHandler is wired (mobile redeem flow)."
2467
+ );
2468
+ }
2469
+ if (typeof config.ledger.getPendingCredit !== "function") {
2470
+ throw new AdapterMisconfiguredError(
2471
+ "ledger.getPendingCredit is required when ptRedeemHandler is wired \u2014 redeemStatus uses it to look up the credit."
2472
+ );
2473
+ }
2474
+ }
2309
2475
  this.cfg = config;
2310
2476
  }
2311
2477
  // ------------------------------ Read endpoints ---------------------------
@@ -2606,6 +2772,11 @@ var IssuerApiAdapter = class {
2606
2772
  /**
2607
2773
  * Build + sign a SponsorAuth payload. Returns `undefined` when no
2608
2774
  * issuer id is configured, so the controller can skip the field.
2775
+ *
2776
+ * v0.7.1 — `scenario` typed as `SponsorshipScenario` (was `string`).
2777
+ * Previously a typo (`"perp_deposit"` vs `"perp-deposit"`) compiled
2778
+ * fine but rejected at L1 by sponsor-relayer's IntentValidator. See
2779
+ * SDK_ISSUER_AUDIT.md N5.
2609
2780
  */
2610
2781
  async buildSponsorAuth(authenticatedAddress, callData, chainId, scenario) {
2611
2782
  if (!this.cfg.pafiIssuerId) return void 0;
@@ -3066,41 +3237,6 @@ var BalanceAggregator = class {
3066
3237
  }
3067
3238
  };
3068
3239
 
3069
- // src/pafi-backend/types.ts
3070
- var PafiBackendError = class extends Error {
3071
- constructor(code, message, httpStatus, details, opts) {
3072
- super(message);
3073
- this.code = code;
3074
- this.httpStatus = httpStatus;
3075
- this.details = details;
3076
- this.name = "PafiBackendError";
3077
- if (opts?.retryAfter !== void 0) this.retryAfter = opts.retryAfter;
3078
- if (opts?.safeToRetry !== void 0) this.serverSafeToRetry = opts.safeToRetry;
3079
- }
3080
- code;
3081
- httpStatus;
3082
- details;
3083
- retryAfter;
3084
- serverSafeToRetry;
3085
- get safeToRetry() {
3086
- if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
3087
- switch (this.code) {
3088
- case "RATE_LIMITER_UNAVAILABLE":
3089
- case "INTERNAL_ERROR":
3090
- case "TIMEOUT":
3091
- case "NETWORK_ERROR":
3092
- return true;
3093
- case "RATE_LIMIT_EXCEEDED":
3094
- case "RATE_LIMIT_EXCEEDED_DAILY":
3095
- case "RATE_LIMIT_EXCEEDED_PER_USER":
3096
- case "ISSUER_BUDGET_EXCEEDED":
3097
- return true;
3098
- default:
3099
- return false;
3100
- }
3101
- }
3102
- };
3103
-
3104
3240
  // src/pafi-backend/client.ts
3105
3241
  function serializeBigInt(_key, value) {
3106
3242
  return typeof value === "bigint" ? value.toString(10) : value;
@@ -3541,15 +3677,17 @@ var IssuerStateValidator = class _IssuerStateValidator {
3541
3677
  };
3542
3678
 
3543
3679
  // src/index.ts
3544
- var PAFI_ISSUER_SDK_VERSION = "0.4.0";
3680
+ var PAFI_ISSUER_SDK_VERSION = true ? "0.7.1" : "dev";
3545
3681
  // Annotate the CommonJS export names for ESM import in node:
3546
3682
  0 && (module.exports = {
3683
+ AdapterMisconfiguredError,
3547
3684
  AuthError,
3548
3685
  AuthService,
3549
3686
  BalanceAggregator,
3550
3687
  BundlerNotConfiguredError,
3551
3688
  BundlerRejectedError,
3552
3689
  BurnIndexer,
3690
+ ConfigurationError,
3553
3691
  DefaultPolicyEngine,
3554
3692
  FeeManager,
3555
3693
  InMemoryCursorStore,
@@ -3577,6 +3715,7 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
3577
3715
  PointIndexer,
3578
3716
  RelayError,
3579
3717
  RelayService,
3718
+ ValidationError,
3580
3719
  authenticateRequest,
3581
3720
  createIssuerService,
3582
3721
  createNativePtQuoter,