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