@pafi-dev/issuer 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1551,17 +1551,8 @@ interface SettlementClientConfig {
1551
1551
  /**
1552
1552
  * chainId — used to derive the issuer-api base URL via
1553
1553
  * `getPafiServiceUrls(chainId).issuerApi`. SDK ships with the URL
1554
- * per chainId; bump SDK version to retarget — OR pass `baseUrl`
1555
- * to override per-deployment.
1556
1554
  */
1557
1555
  chainId: number;
1558
- /**
1559
- * Optional override for the issuer-api base URL. Audit PACI5-17 —
1560
- * production issuer backends should set this from an env var
1561
- * (e.g. `PAFI_ISSUER_API_URL`) so the deployed binary doesn't
1562
- * depend on the SDK ship-default that may target dev infrastructure.
1563
- * Undefined / empty → use the ship-default for `chainId`.
1564
- */
1565
1556
  baseUrl?: string;
1566
1557
  /** PAFI-assigned issuer id used in `X-Issuer-Id` header. */
1567
1558
  issuerId: string;
@@ -1575,33 +1566,7 @@ interface SettlementClientConfig {
1575
1566
  interface PolicyProviderConfig extends SettlementClientConfig {
1576
1567
  /** Cache TTL in milliseconds. Default 5 * 60 * 1000 (5min). */
1577
1568
  cacheTtlMs?: number;
1578
- /**
1579
- * Behavior khi settlement-api fetch fail (network blip, 5xx, timeout).
1580
- *
1581
- * Audit PACI5-17 — the pre-flight redeem limit is the SOLE gate
1582
- * before the issuer signer mints a BurnRequest. Silently degrading
1583
- * to a permissive default during settlement outages let users
1584
- * exceed their configured limit until the outage cleared.
1585
- *
1586
- * - `'fail-closed'` (DEFAULT, recommended): throw
1587
- * `PolicyProviderUnavailableError`. Caller maps to HTTP 503 so
1588
- * the FE can retry; redemptions are blocked until policy fetch
1589
- * succeeds.
1590
- *
1591
- * - `'permissive-default'`: return `defaultPolicyFor(issuerId)` and
1592
- * fire `onWarning`. Pre-fix behavior. Operators who genuinely
1593
- * prefer availability over enforcement (e.g. test issuers, low-
1594
- * risk PT) MUST opt in explicitly AND wire `onWarning` to a
1595
- * pager / Slack / Sentry alert. Silent permissive fallback is no
1596
- * longer the default.
1597
- */
1598
1569
  onFetchFailure?: "fail-closed" | "permissive-default";
1599
- /**
1600
- * Observability hook for non-fatal events: permissive-default
1601
- * fallbacks (when explicitly opted in). Wire to your logger /
1602
- * Sentry / Datadog so the `policy_provider_fallback` event reaches
1603
- * the on-call dashboard.
1604
- */
1605
1570
  onWarning?: (msg: string, ctx: Record<string, unknown>) => void;
1606
1571
  /**
1607
1572
  * Optional clock for testability. Returns unix milliseconds.
@@ -2078,17 +2043,8 @@ interface PafiBackendConfig {
2078
2043
  /**
2079
2044
  * chainId — used to derive the sponsor-relayer base URL via
2080
2045
  * `getPafiServiceUrls(chainId).sponsorRelayer`. SDK ships with the
2081
- * URL per chainId; bump SDK version to retarget — OR pass
2082
- * `baseUrl` to override per-deployment.
2083
2046
  */
2084
2047
  chainId: number;
2085
- /**
2086
- * Optional override for the sponsor-relayer base URL. Audit
2087
- * PACI5-17 — production issuer backends should set this from an env
2088
- * var (e.g. `PAFI_SPONSOR_RELAYER_URL`) so the binary doesn't depend
2089
- * on the SDK ship-default that may target dev infrastructure.
2090
- * Undefined / empty → use the ship-default for `chainId`.
2091
- */
2092
2048
  baseUrl?: string;
2093
2049
  issuerId: string;
2094
2050
  apiKey: string;
@@ -2246,12 +2202,31 @@ interface MintStatusParams {
2246
2202
  * - lock.status === "PENDING"
2247
2203
  * - lock.userOpHash is bound (set by `/claim/submit`)
2248
2204
  *
2249
- * If the bundler reports the UserOp confirmed, the handler updates
2205
+ * If the bundler reports the UserOp confirmed AND the receipt block
2206
+ * is past the configured `confirmations` depth, the handler updates
2250
2207
  * the ledger lock + returns `MINTED` immediately, bypassing
2251
2208
  * `PointIndexer`'s amount-based race (multiple PENDING locks with
2252
2209
  * the same amount can be matched to the wrong tx_hash).
2253
2210
  */
2254
2211
  pafiBackendClient?: PafiBackendClient | null;
2212
+ /**
2213
+ * Guard for the bundler-receipt fallback. The bundler returns success at zero
2214
+ * confs, but `PointIndexer` enforces a 3-block reorg window;
2215
+ * crediting / debiting off-chain at 0 confs while the indexer waits
2216
+ * for finality leaves an unbacked durable mutation if the tx is
2217
+ * reorged out. Pass the SAME PublicClient that the indexer uses so
2218
+ * both paths see consistent chain head. Optional only for legacy
2219
+ * callers that don't supply `pafiBackendClient`; required whenever
2220
+ * the receipt-fallback path can run.
2221
+ */
2222
+ provider?: PublicClient;
2223
+ /**
2224
+ * Confirmation depth required before the receipt
2225
+ * fallback applies the credit / debit. MUST match
2226
+ * `PointIndexer.confirmations` (default 3). Operators who reduce
2227
+ * the indexer depth must set this to the same value.
2228
+ */
2229
+ confirmations?: number;
2255
2230
  /** Optional logger for "ledger update failed" warnings. */
2256
2231
  onWarning?: (msg: string) => void;
2257
2232
  }
@@ -2260,6 +2235,20 @@ interface BurnStatusParams {
2260
2235
  userAddress: Address;
2261
2236
  ledger: IPointLedger;
2262
2237
  pafiBackendClient?: PafiBackendClient | null;
2238
+ /**
2239
+ * BurnStatusParams.provider` for full
2240
+ * rationale. The receipt-fallback path applies a spendable
2241
+ * off-chain credit; without a confirmation-depth gate a reorg
2242
+ * before `BurnIndexer.confirmations` leaves durable unbacked
2243
+ * credit with no reversal mechanism.
2244
+ */
2245
+ provider?: PublicClient;
2246
+ /**
2247
+ * Confirmation depth required before the receipt
2248
+ * fallback applies the credit. MUST match
2249
+ * `BurnIndexer.confirmations` (default 3).
2250
+ */
2251
+ confirmations?: number;
2263
2252
  onWarning?: (msg: string) => void;
2264
2253
  }
2265
2254
  declare class LockNotFoundError extends PafiSdkError {
@@ -3235,7 +3224,6 @@ interface IssuerServiceConfig {
3235
3224
  historyStore: IRedemptionHistoryStore;
3236
3225
  /**
3237
3226
  * Optional override for the PAFI issuer-api base URL. Audit
3238
- * PACI5-17 — production issuer backends should set this from an
3239
3227
  * env var (e.g. `PAFI_ISSUER_API_URL`) so policy fetch hits the
3240
3228
  * canonical environment for the deploy. Undefined → SDK
3241
3229
  * ship-default per chainId.
@@ -3243,9 +3231,6 @@ interface IssuerServiceConfig {
3243
3231
  baseUrl?: string;
3244
3232
  /**
3245
3233
  * Behavior khi settlement-api fetch fail. Default `'fail-closed'`
3246
- * (audit PACI5-17 — pre-flight redeem limit is the sole gate; do
3247
- * not silently degrade to a permissive default).
3248
- *
3249
3234
  * Opt in to `'permissive-default'` ONLY when paired with an alert
3250
3235
  * on the `policy_provider_fallback` event surfaced via
3251
3236
  * `onPolicyWarning`.
@@ -3965,9 +3950,12 @@ declare class IssuerStateError extends PafiSdkError {
3965
3950
  *
3966
3951
  * Caching:
3967
3952
  * - `PointToken.issuer()` — memoized for the process lifetime (immutable)
3968
- * - Full state (registry + totalSupply) — 30s TTL per PointToken
3953
+ * - Full state (registry + totalSupply) — 10s TTL per PointToken
3954
+ * (was 30s pre-audit PACI5-3; see `ISSUER_RECORD_TTL_MS` comment)
3969
3955
  * - Burst calls while a fetch is in-flight share the same Promise
3970
3956
  * (thundering-herd protection)
3957
+ * - Operators can call `invalidate()` after admin txs land to bust
3958
+ * the cache immediately instead of waiting up to TTL.
3971
3959
  *
3972
3960
  * Usage in NestJS: wrap this in an `@Injectable()` service; pass
3973
3961
  * `PublicClient` and `registryAddress` from your DI container.
@@ -3986,7 +3974,9 @@ declare class IssuerStateValidator {
3986
3974
  static forChain(provider: PublicClient, chainId: number): IssuerStateValidator;
3987
3975
  /**
3988
3976
  * Invalidate cached state for one PointToken, or everything if omitted.
3989
- * Call after admin txs that change registry or cap settings.
3977
+ * Call after admin txs that change registry or cap settings — closes
3978
+ * the split-brain window described in audit PACI5-3 ahead of the
3979
+ * passive TTL. Idempotent: safe to call when no entry exists.
3990
3980
  */
3991
3981
  invalidate(pointToken?: Address): void;
3992
3982
  /**
package/dist/index.d.ts CHANGED
@@ -1551,17 +1551,8 @@ interface SettlementClientConfig {
1551
1551
  /**
1552
1552
  * chainId — used to derive the issuer-api base URL via
1553
1553
  * `getPafiServiceUrls(chainId).issuerApi`. SDK ships with the URL
1554
- * per chainId; bump SDK version to retarget — OR pass `baseUrl`
1555
- * to override per-deployment.
1556
1554
  */
1557
1555
  chainId: number;
1558
- /**
1559
- * Optional override for the issuer-api base URL. Audit PACI5-17 —
1560
- * production issuer backends should set this from an env var
1561
- * (e.g. `PAFI_ISSUER_API_URL`) so the deployed binary doesn't
1562
- * depend on the SDK ship-default that may target dev infrastructure.
1563
- * Undefined / empty → use the ship-default for `chainId`.
1564
- */
1565
1556
  baseUrl?: string;
1566
1557
  /** PAFI-assigned issuer id used in `X-Issuer-Id` header. */
1567
1558
  issuerId: string;
@@ -1575,33 +1566,7 @@ interface SettlementClientConfig {
1575
1566
  interface PolicyProviderConfig extends SettlementClientConfig {
1576
1567
  /** Cache TTL in milliseconds. Default 5 * 60 * 1000 (5min). */
1577
1568
  cacheTtlMs?: number;
1578
- /**
1579
- * Behavior khi settlement-api fetch fail (network blip, 5xx, timeout).
1580
- *
1581
- * Audit PACI5-17 — the pre-flight redeem limit is the SOLE gate
1582
- * before the issuer signer mints a BurnRequest. Silently degrading
1583
- * to a permissive default during settlement outages let users
1584
- * exceed their configured limit until the outage cleared.
1585
- *
1586
- * - `'fail-closed'` (DEFAULT, recommended): throw
1587
- * `PolicyProviderUnavailableError`. Caller maps to HTTP 503 so
1588
- * the FE can retry; redemptions are blocked until policy fetch
1589
- * succeeds.
1590
- *
1591
- * - `'permissive-default'`: return `defaultPolicyFor(issuerId)` and
1592
- * fire `onWarning`. Pre-fix behavior. Operators who genuinely
1593
- * prefer availability over enforcement (e.g. test issuers, low-
1594
- * risk PT) MUST opt in explicitly AND wire `onWarning` to a
1595
- * pager / Slack / Sentry alert. Silent permissive fallback is no
1596
- * longer the default.
1597
- */
1598
1569
  onFetchFailure?: "fail-closed" | "permissive-default";
1599
- /**
1600
- * Observability hook for non-fatal events: permissive-default
1601
- * fallbacks (when explicitly opted in). Wire to your logger /
1602
- * Sentry / Datadog so the `policy_provider_fallback` event reaches
1603
- * the on-call dashboard.
1604
- */
1605
1570
  onWarning?: (msg: string, ctx: Record<string, unknown>) => void;
1606
1571
  /**
1607
1572
  * Optional clock for testability. Returns unix milliseconds.
@@ -2078,17 +2043,8 @@ interface PafiBackendConfig {
2078
2043
  /**
2079
2044
  * chainId — used to derive the sponsor-relayer base URL via
2080
2045
  * `getPafiServiceUrls(chainId).sponsorRelayer`. SDK ships with the
2081
- * URL per chainId; bump SDK version to retarget — OR pass
2082
- * `baseUrl` to override per-deployment.
2083
2046
  */
2084
2047
  chainId: number;
2085
- /**
2086
- * Optional override for the sponsor-relayer base URL. Audit
2087
- * PACI5-17 — production issuer backends should set this from an env
2088
- * var (e.g. `PAFI_SPONSOR_RELAYER_URL`) so the binary doesn't depend
2089
- * on the SDK ship-default that may target dev infrastructure.
2090
- * Undefined / empty → use the ship-default for `chainId`.
2091
- */
2092
2048
  baseUrl?: string;
2093
2049
  issuerId: string;
2094
2050
  apiKey: string;
@@ -2246,12 +2202,31 @@ interface MintStatusParams {
2246
2202
  * - lock.status === "PENDING"
2247
2203
  * - lock.userOpHash is bound (set by `/claim/submit`)
2248
2204
  *
2249
- * If the bundler reports the UserOp confirmed, the handler updates
2205
+ * If the bundler reports the UserOp confirmed AND the receipt block
2206
+ * is past the configured `confirmations` depth, the handler updates
2250
2207
  * the ledger lock + returns `MINTED` immediately, bypassing
2251
2208
  * `PointIndexer`'s amount-based race (multiple PENDING locks with
2252
2209
  * the same amount can be matched to the wrong tx_hash).
2253
2210
  */
2254
2211
  pafiBackendClient?: PafiBackendClient | null;
2212
+ /**
2213
+ * Guard for the bundler-receipt fallback. The bundler returns success at zero
2214
+ * confs, but `PointIndexer` enforces a 3-block reorg window;
2215
+ * crediting / debiting off-chain at 0 confs while the indexer waits
2216
+ * for finality leaves an unbacked durable mutation if the tx is
2217
+ * reorged out. Pass the SAME PublicClient that the indexer uses so
2218
+ * both paths see consistent chain head. Optional only for legacy
2219
+ * callers that don't supply `pafiBackendClient`; required whenever
2220
+ * the receipt-fallback path can run.
2221
+ */
2222
+ provider?: PublicClient;
2223
+ /**
2224
+ * Confirmation depth required before the receipt
2225
+ * fallback applies the credit / debit. MUST match
2226
+ * `PointIndexer.confirmations` (default 3). Operators who reduce
2227
+ * the indexer depth must set this to the same value.
2228
+ */
2229
+ confirmations?: number;
2255
2230
  /** Optional logger for "ledger update failed" warnings. */
2256
2231
  onWarning?: (msg: string) => void;
2257
2232
  }
@@ -2260,6 +2235,20 @@ interface BurnStatusParams {
2260
2235
  userAddress: Address;
2261
2236
  ledger: IPointLedger;
2262
2237
  pafiBackendClient?: PafiBackendClient | null;
2238
+ /**
2239
+ * BurnStatusParams.provider` for full
2240
+ * rationale. The receipt-fallback path applies a spendable
2241
+ * off-chain credit; without a confirmation-depth gate a reorg
2242
+ * before `BurnIndexer.confirmations` leaves durable unbacked
2243
+ * credit with no reversal mechanism.
2244
+ */
2245
+ provider?: PublicClient;
2246
+ /**
2247
+ * Confirmation depth required before the receipt
2248
+ * fallback applies the credit. MUST match
2249
+ * `BurnIndexer.confirmations` (default 3).
2250
+ */
2251
+ confirmations?: number;
2263
2252
  onWarning?: (msg: string) => void;
2264
2253
  }
2265
2254
  declare class LockNotFoundError extends PafiSdkError {
@@ -3235,7 +3224,6 @@ interface IssuerServiceConfig {
3235
3224
  historyStore: IRedemptionHistoryStore;
3236
3225
  /**
3237
3226
  * Optional override for the PAFI issuer-api base URL. Audit
3238
- * PACI5-17 — production issuer backends should set this from an
3239
3227
  * env var (e.g. `PAFI_ISSUER_API_URL`) so policy fetch hits the
3240
3228
  * canonical environment for the deploy. Undefined → SDK
3241
3229
  * ship-default per chainId.
@@ -3243,9 +3231,6 @@ interface IssuerServiceConfig {
3243
3231
  baseUrl?: string;
3244
3232
  /**
3245
3233
  * Behavior khi settlement-api fetch fail. Default `'fail-closed'`
3246
- * (audit PACI5-17 — pre-flight redeem limit is the sole gate; do
3247
- * not silently degrade to a permissive default).
3248
- *
3249
3234
  * Opt in to `'permissive-default'` ONLY when paired with an alert
3250
3235
  * on the `policy_provider_fallback` event surfaced via
3251
3236
  * `onPolicyWarning`.
@@ -3965,9 +3950,12 @@ declare class IssuerStateError extends PafiSdkError {
3965
3950
  *
3966
3951
  * Caching:
3967
3952
  * - `PointToken.issuer()` — memoized for the process lifetime (immutable)
3968
- * - Full state (registry + totalSupply) — 30s TTL per PointToken
3953
+ * - Full state (registry + totalSupply) — 10s TTL per PointToken
3954
+ * (was 30s pre-audit PACI5-3; see `ISSUER_RECORD_TTL_MS` comment)
3969
3955
  * - Burst calls while a fetch is in-flight share the same Promise
3970
3956
  * (thundering-herd protection)
3957
+ * - Operators can call `invalidate()` after admin txs land to bust
3958
+ * the cache immediately instead of waiting up to TTL.
3971
3959
  *
3972
3960
  * Usage in NestJS: wrap this in an `@Injectable()` service; pass
3973
3961
  * `PublicClient` and `registryAddress` from your DI container.
@@ -3986,7 +3974,9 @@ declare class IssuerStateValidator {
3986
3974
  static forChain(provider: PublicClient, chainId: number): IssuerStateValidator;
3987
3975
  /**
3988
3976
  * Invalidate cached state for one PointToken, or everything if omitted.
3989
- * Call after admin txs that change registry or cap settings.
3977
+ * Call after admin txs that change registry or cap settings — closes
3978
+ * the split-brain window described in audit PACI5-3 ahead of the
3979
+ * passive TTL. Idempotent: safe to call when no entry exists.
3990
3980
  */
3991
3981
  invalidate(pointToken?: Address): void;
3992
3982
  /**
package/dist/index.js CHANGED
@@ -2422,6 +2422,45 @@ var PTRedeemHandler = class {
2422
2422
  };
2423
2423
 
2424
2424
  // src/api/statusHandlers.ts
2425
+ var DEFAULT_STATUS_CONFIRMATIONS = 3;
2426
+ async function isReceiptPastConfirmations(receipt, provider, confirmations, onWarning, handlerName) {
2427
+ if (!provider) {
2428
+ onWarning?.(
2429
+ `${handlerName}: provider missing \u2014 cannot enforce confirmation depth; deferring receipt fallback to on-chain indexer.`
2430
+ );
2431
+ return false;
2432
+ }
2433
+ if (!receipt.blockNumber) {
2434
+ onWarning?.(
2435
+ `${handlerName}: receipt has no blockNumber \u2014 cannot enforce confirmation depth; deferring to indexer.`
2436
+ );
2437
+ return false;
2438
+ }
2439
+ const requiredConfs = BigInt(confirmations ?? DEFAULT_STATUS_CONFIRMATIONS);
2440
+ let receiptBlock;
2441
+ try {
2442
+ receiptBlock = BigInt(receipt.blockNumber);
2443
+ } catch {
2444
+ onWarning?.(
2445
+ `${handlerName}: malformed receipt blockNumber (${receipt.blockNumber}) \u2014 deferring to indexer.`
2446
+ );
2447
+ return false;
2448
+ }
2449
+ let head;
2450
+ try {
2451
+ head = await provider.getBlockNumber();
2452
+ } catch (err) {
2453
+ onWarning?.(
2454
+ `${handlerName}: getBlockNumber failed (${err instanceof Error ? err.message : String(err)}) \u2014 deferring to indexer.`
2455
+ );
2456
+ return false;
2457
+ }
2458
+ const depth = head - receiptBlock;
2459
+ if (depth < requiredConfs) {
2460
+ return false;
2461
+ }
2462
+ return true;
2463
+ }
2425
2464
  var LockNotFoundError = class extends PafiSdkError {
2426
2465
  code = "LOCK_NOT_FOUND";
2427
2466
  httpStatus = "not_found";
@@ -2450,6 +2489,23 @@ async function handleClaimStatus(params) {
2450
2489
  lock.userOpHash
2451
2490
  );
2452
2491
  if (receipt) {
2492
+ const passesConfirmationDepth = await isReceiptPastConfirmations(
2493
+ receipt,
2494
+ params.provider,
2495
+ params.confirmations,
2496
+ params.onWarning,
2497
+ "handleClaimStatus"
2498
+ );
2499
+ if (!passesConfirmationDepth) {
2500
+ return {
2501
+ lockId: lock.lockId,
2502
+ status: "PENDING",
2503
+ txHash: lock.txHash ?? null,
2504
+ amount: lock.amount.toString(),
2505
+ createdAt: new Date(lock.createdAt).toISOString(),
2506
+ expiresAt: new Date(lock.expiresAt).toISOString()
2507
+ };
2508
+ }
2453
2509
  if (receipt.success && receipt.txHash) {
2454
2510
  if (!lock.tokenAddress) {
2455
2511
  params.onWarning?.(
@@ -2524,14 +2580,23 @@ async function handleRedeemStatus(params) {
2524
2580
  credit.userOpHash
2525
2581
  );
2526
2582
  if (receipt && receipt.success) {
2527
- status = "RESOLVED";
2528
- txHash = receipt.txHash;
2529
- if (params.ledger.resolveCreditByBurnTx) {
2530
- await params.ledger.resolveCreditByBurnTx(credit.lockId, receipt.txHash).catch((err) => {
2531
- params.onWarning?.(
2532
- `handleRedeemStatus: resolveCreditByBurnTx failed for lock ${credit.lockId}: ${err}`
2533
- );
2534
- });
2583
+ const passesConfirmationDepth = await isReceiptPastConfirmations(
2584
+ receipt,
2585
+ params.provider,
2586
+ params.confirmations,
2587
+ params.onWarning,
2588
+ "handleRedeemStatus"
2589
+ );
2590
+ if (passesConfirmationDepth) {
2591
+ status = "RESOLVED";
2592
+ txHash = receipt.txHash;
2593
+ if (params.ledger.resolveCreditByBurnTx) {
2594
+ await params.ledger.resolveCreditByBurnTx(credit.lockId, receipt.txHash).catch((err) => {
2595
+ params.onWarning?.(
2596
+ `handleRedeemStatus: resolveCreditByBurnTx failed for lock ${credit.lockId}: ${err}`
2597
+ );
2598
+ });
2599
+ }
2535
2600
  }
2536
2601
  }
2537
2602
  } catch (err) {
@@ -3729,6 +3794,7 @@ var IssuerApiAdapter = class {
3729
3794
  userAddress: authenticatedAddress,
3730
3795
  ledger: this.cfg.ledger,
3731
3796
  pafiBackendClient: this.cfg.pafiBackendClient,
3797
+ provider: this.cfg.provider,
3732
3798
  onWarning: this.cfg.onWarning
3733
3799
  });
3734
3800
  }
@@ -3738,6 +3804,7 @@ var IssuerApiAdapter = class {
3738
3804
  userAddress: authenticatedAddress,
3739
3805
  ledger: this.cfg.ledger,
3740
3806
  pafiBackendClient: this.cfg.pafiBackendClient,
3807
+ provider: this.cfg.provider,
3741
3808
  onWarning: this.cfg.onWarning
3742
3809
  });
3743
3810
  }
@@ -4554,9 +4621,6 @@ var SettlementClient = class {
4554
4621
  if (!config.issuerId) throw new Error("SettlementClient: issuerId is required");
4555
4622
  if (!config.apiKey) throw new Error("SettlementClient: apiKey is required");
4556
4623
  this.config = {
4557
- // Audit PACI5-17 — honor optional baseUrl override wired from
4558
- // an env var (e.g. PAFI_ISSUER_API_URL). Empty / undefined →
4559
- // ship-default for chainId.
4560
4624
  baseUrl: getPafiServiceUrls2(config.chainId, {
4561
4625
  issuerApi: config.baseUrl
4562
4626
  }).issuerApi.replace(/\/+$/, ""),
@@ -4959,7 +5023,7 @@ import {
4959
5023
  issuerRegistryAbi,
4960
5024
  getContractAddresses as getContractAddresses8
4961
5025
  } from "@pafi-dev/core";
4962
- var ISSUER_RECORD_TTL_MS = 3e4;
5026
+ var ISSUER_RECORD_TTL_MS = 1e4;
4963
5027
  var IssuerStateValidator = class _IssuerStateValidator {
4964
5028
  constructor(provider, registryAddress) {
4965
5029
  this.provider = provider;
@@ -4980,7 +5044,9 @@ var IssuerStateValidator = class _IssuerStateValidator {
4980
5044
  }
4981
5045
  /**
4982
5046
  * Invalidate cached state for one PointToken, or everything if omitted.
4983
- * Call after admin txs that change registry or cap settings.
5047
+ * Call after admin txs that change registry or cap settings — closes
5048
+ * the split-brain window described in audit PACI5-3 ahead of the
5049
+ * passive TTL. Idempotent: safe to call when no entry exists.
4984
5050
  */
4985
5051
  invalidate(pointToken) {
4986
5052
  if (pointToken) {
@@ -5153,7 +5219,7 @@ var MemoryRedemptionHistoryStore = class {
5153
5219
  };
5154
5220
 
5155
5221
  // src/index.ts
5156
- var PAFI_ISSUER_SDK_VERSION = true ? "0.32.0" : "dev";
5222
+ var PAFI_ISSUER_SDK_VERSION = true ? "0.34.0" : "dev";
5157
5223
  export {
5158
5224
  AdapterMisconfiguredError,
5159
5225
  AuthError,