@pafi-dev/issuer 0.3.0-beta.8 → 0.3.0-beta.9

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.js CHANGED
@@ -1807,37 +1807,16 @@ var PafiBackendError = class extends Error {
1807
1807
  code;
1808
1808
  httpStatus;
1809
1809
  details;
1810
- /**
1811
- * Seconds to wait before retry. Populated from the server body
1812
- * (e.g. rate limit returns the number of seconds until UTC midnight).
1813
- */
1814
1810
  retryAfter;
1815
- /**
1816
- * `safeToRetry` as reported by the server body. Prefer this over the
1817
- * code-based heuristic when available — the server knows more about
1818
- * whether the same request will succeed on retry.
1819
- */
1820
1811
  serverSafeToRetry;
1821
- /**
1822
- * Whether the caller can safely retry the same request.
1823
- *
1824
- * If the server provided `safeToRetry` in the body, trust that.
1825
- * Otherwise fall back to a code-based heuristic.
1826
- */
1827
1812
  get safeToRetry() {
1828
1813
  if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
1829
1814
  switch (this.code) {
1830
- // Transient infra
1831
- case "PAYMASTER_UNAVAILABLE":
1832
- case "PAYMASTER_TIMEOUT":
1833
1815
  case "RATE_LIMITER_UNAVAILABLE":
1834
- case "KMS_UNAVAILABLE":
1835
- case "SPONSOR_AUTH_SIGNING_FAILED":
1836
1816
  case "INTERNAL_ERROR":
1837
1817
  case "TIMEOUT":
1838
1818
  case "NETWORK_ERROR":
1839
1819
  return true;
1840
- // Rate-limited — safe to retry after retryAfter window
1841
1820
  case "RATE_LIMIT_EXCEEDED":
1842
1821
  case "RATE_LIMIT_EXCEEDED_DAILY":
1843
1822
  case "RATE_LIMIT_EXCEEDED_PER_USER":
@@ -1849,195 +1828,6 @@ var PafiBackendError = class extends Error {
1849
1828
  }
1850
1829
  };
1851
1830
 
1852
- // src/pafi-backend/pafiBackendClient.ts
1853
- var DEFAULT_TIMEOUT_MS = 1e4;
1854
- var RETRY_DEFAULTS = {
1855
- maxAttempts: 1,
1856
- initialDelayMs: 500,
1857
- maxDelayMs: 1e4,
1858
- maxRetryAfterMs: 3e4
1859
- };
1860
- var PafiBackendClient = class {
1861
- url;
1862
- issuerId;
1863
- apiKey;
1864
- fetchImpl;
1865
- timeoutMs;
1866
- retry;
1867
- constructor(config) {
1868
- if (!config.url) {
1869
- throw new Error("PafiBackendClient: url is required");
1870
- }
1871
- if (!config.issuerId) {
1872
- throw new Error("PafiBackendClient: issuerId is required");
1873
- }
1874
- if (!config.apiKey) {
1875
- throw new Error("PafiBackendClient: apiKey is required");
1876
- }
1877
- this.url = config.url.replace(/\/+$/, "");
1878
- this.issuerId = config.issuerId;
1879
- this.apiKey = config.apiKey;
1880
- this.fetchImpl = config.fetchImpl ?? globalThis.fetch;
1881
- this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1882
- this.retry = { ...RETRY_DEFAULTS, ...config.retry ?? {} };
1883
- if (!this.fetchImpl) {
1884
- throw new Error(
1885
- "PafiBackendClient: no fetch implementation available \u2014 pass `fetchImpl` or run on Node 18+"
1886
- );
1887
- }
1888
- if (this.retry.maxAttempts < 1) {
1889
- throw new Error("PafiBackendClient: retry.maxAttempts must be >= 1");
1890
- }
1891
- }
1892
- /**
1893
- * Request a SponsorAuth signature from PAFI sponsor-relayer (beta.8+).
1894
- *
1895
- * The relayer:
1896
- * 1. Authenticates user (JWT) + issuer (API key)
1897
- * 2. Per-(user, scenario) rate limit + per-issuer daily budget
1898
- * 3. Scenario-specific intent validation (mint cap, KYC, etc.)
1899
- * 4. Allocates nonce + signs SponsorAuth payload via KMS PAFI key
1900
- * 5. Returns `{ sponsorAuth, payload }` for the FE to forward to
1901
- * Privy's `signUserOperation({ sponsorAuth, payload })`.
1902
- *
1903
- * Retries on transient failures (5xx, timeouts, KMS unavailable,
1904
- * rate-limit-with-retryAfter). 4xx that are not `safeToRetry` fail fast.
1905
- *
1906
- * See `pafi-backend/docs/SPONSOR_AUTH_DESIGN.md` for the full spec.
1907
- *
1908
- * @throws PafiBackendError on final failure after exhausting retries
1909
- */
1910
- async requestSponsorAuth(req) {
1911
- return this.postWithRetry(
1912
- "/sponsor-auth",
1913
- req
1914
- );
1915
- }
1916
- /**
1917
- * @deprecated Coinbase paymaster path — replaced by `requestSponsorAuth`
1918
- * in beta.8. Will be removed in 1.0. Migrate by:
1919
- * 1. Switch to `requestSponsorAuth` returning `{ sponsorAuth, payload }`
1920
- * 2. Pass both to Privy `signUserOperation` instead of merging
1921
- * paymasterData into the UserOp callData
1922
- */
1923
- async requestSponsorship(req) {
1924
- return this.postWithRetry(
1925
- "/paymaster/sponsor",
1926
- req
1927
- );
1928
- }
1929
- // -------------------------------------------------------------------------
1930
- // Internals
1931
- // -------------------------------------------------------------------------
1932
- async postWithRetry(path, body) {
1933
- let lastError;
1934
- for (let attempt = 1; attempt <= this.retry.maxAttempts; attempt++) {
1935
- try {
1936
- return await this.post(path, body);
1937
- } catch (err) {
1938
- if (!(err instanceof PafiBackendError)) throw err;
1939
- lastError = err;
1940
- const isLastAttempt = attempt >= this.retry.maxAttempts;
1941
- if (isLastAttempt || !err.safeToRetry) throw err;
1942
- const delay = this.computeBackoff(attempt, err.retryAfter);
1943
- if (delay === null) throw err;
1944
- await this.sleep(delay);
1945
- }
1946
- }
1947
- throw lastError;
1948
- }
1949
- /**
1950
- * Pick the delay before the next retry.
1951
- * - If the server sent `retryAfter` (seconds), honor it (capped by
1952
- * `maxRetryAfterMs`) — returns null if the server wait exceeds the
1953
- * cap, signalling the caller should give up.
1954
- * - Otherwise: exponential backoff with ±20% jitter, capped at
1955
- * `maxDelayMs`.
1956
- */
1957
- computeBackoff(attempt, retryAfter) {
1958
- if (retryAfter !== void 0) {
1959
- const serverMs = retryAfter * 1e3;
1960
- if (serverMs > this.retry.maxRetryAfterMs) return null;
1961
- return serverMs;
1962
- }
1963
- const exp = this.retry.initialDelayMs * 2 ** (attempt - 1);
1964
- const capped = Math.min(exp, this.retry.maxDelayMs);
1965
- const jitter = capped * (0.8 + Math.random() * 0.4);
1966
- return Math.round(jitter);
1967
- }
1968
- sleep(ms) {
1969
- return new Promise((resolve) => setTimeout(resolve, ms));
1970
- }
1971
- async post(path, body) {
1972
- const controller = new AbortController();
1973
- const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
1974
- let response;
1975
- try {
1976
- response = await this.fetchImpl(`${this.url}${path}`, {
1977
- method: "POST",
1978
- headers: {
1979
- "Content-Type": "application/json",
1980
- "Authorization": `Bearer ${this.apiKey}`,
1981
- "X-Issuer-Id": this.issuerId
1982
- },
1983
- body: JSON.stringify(body, this.bigintReplacer),
1984
- signal: controller.signal
1985
- });
1986
- } catch (err) {
1987
- if (err.name === "AbortError") {
1988
- throw new PafiBackendError(
1989
- "TIMEOUT",
1990
- `PAFI Backend request timed out after ${this.timeoutMs}ms`,
1991
- 0
1992
- );
1993
- }
1994
- throw new PafiBackendError(
1995
- "NETWORK_ERROR",
1996
- `PAFI Backend unreachable: ${err.message}`,
1997
- 0
1998
- );
1999
- } finally {
2000
- clearTimeout(timeoutId);
2001
- }
2002
- const text = await response.text();
2003
- if (!response.ok) {
2004
- let code = "INTERNAL_ERROR";
2005
- let message = text || response.statusText;
2006
- let details;
2007
- let retryAfter;
2008
- let serverSafeToRetry;
2009
- try {
2010
- const parsed = JSON.parse(text);
2011
- code = parsed.code ?? code;
2012
- message = parsed.message ?? message;
2013
- details = parsed.details;
2014
- if (typeof parsed.retryAfter === "number") retryAfter = parsed.retryAfter;
2015
- if (typeof parsed.safeToRetry === "boolean") serverSafeToRetry = parsed.safeToRetry;
2016
- } catch {
2017
- }
2018
- throw new PafiBackendError(code, message, response.status, details, {
2019
- ...retryAfter !== void 0 ? { retryAfter } : {},
2020
- ...serverSafeToRetry !== void 0 ? { safeToRetry: serverSafeToRetry } : {}
2021
- });
2022
- }
2023
- return JSON.parse(text, this.bigintReviver);
2024
- }
2025
- /** JSON replacer that stringifies bigints. Paired with bigintReviver. */
2026
- bigintReplacer = (_key, value) => {
2027
- return typeof value === "bigint" ? value.toString() : value;
2028
- };
2029
- /**
2030
- * JSON reviver that coerces specific numeric-string fields back to
2031
- * bigint. The server must send these fields as decimal strings.
2032
- */
2033
- bigintReviver = (key, value) => {
2034
- if (typeof value === "string" && (key.endsWith("GasLimit") || key === "nonce" || key === "callGasLimit" || key === "verificationGasLimit" || key === "preVerificationGas" || key === "maxFeePerGas" || key === "maxPriorityFeePerGas" || key === "paymasterVerificationGasLimit" || key === "paymasterPostOpGasLimit") && /^\d+$/.test(value)) {
2035
- return BigInt(value);
2036
- }
2037
- return value;
2038
- };
2039
- };
2040
-
2041
1831
  // src/config.ts
2042
1832
  import { getAddress as getAddress9 } from "viem";
2043
1833
  function createIssuerService(config) {
@@ -2149,7 +1939,6 @@ export {
2149
1939
  PAFI_ISSUER_SDK_VERSION,
2150
1940
  PTRedeemError,
2151
1941
  PTRedeemHandler,
2152
- PafiBackendClient,
2153
1942
  PafiBackendError,
2154
1943
  PointIndexer,
2155
1944
  PrivateKeySigner,