@pooflabs/core 0.0.42 → 0.0.43
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/client/operations.d.ts +1 -0
- package/dist/index.js +375 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +361 -19
- package/dist/index.mjs.map +1 -1
- package/dist/utils/api.d.ts +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -8,24 +8,279 @@ var BN = require('bn.js');
|
|
|
8
8
|
var ReconnectingWebSocket = require('reconnecting-websocket');
|
|
9
9
|
|
|
10
10
|
function _interopNamespaceDefault(e) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
var anchor__namespace = /*#__PURE__*/_interopNamespaceDefault(anchor);
|
|
28
28
|
|
|
29
|
+
function getDefaultExportFromCjs (x) {
|
|
30
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var isRetryAllowed$1;
|
|
34
|
+
var hasRequiredIsRetryAllowed;
|
|
35
|
+
|
|
36
|
+
function requireIsRetryAllowed () {
|
|
37
|
+
if (hasRequiredIsRetryAllowed) return isRetryAllowed$1;
|
|
38
|
+
hasRequiredIsRetryAllowed = 1;
|
|
39
|
+
|
|
40
|
+
const denyList = new Set([
|
|
41
|
+
'ENOTFOUND',
|
|
42
|
+
'ENETUNREACH',
|
|
43
|
+
|
|
44
|
+
// SSL errors from https://github.com/nodejs/node/blob/fc8e3e2cdc521978351de257030db0076d79e0ab/src/crypto/crypto_common.cc#L301-L328
|
|
45
|
+
'UNABLE_TO_GET_ISSUER_CERT',
|
|
46
|
+
'UNABLE_TO_GET_CRL',
|
|
47
|
+
'UNABLE_TO_DECRYPT_CERT_SIGNATURE',
|
|
48
|
+
'UNABLE_TO_DECRYPT_CRL_SIGNATURE',
|
|
49
|
+
'UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY',
|
|
50
|
+
'CERT_SIGNATURE_FAILURE',
|
|
51
|
+
'CRL_SIGNATURE_FAILURE',
|
|
52
|
+
'CERT_NOT_YET_VALID',
|
|
53
|
+
'CERT_HAS_EXPIRED',
|
|
54
|
+
'CRL_NOT_YET_VALID',
|
|
55
|
+
'CRL_HAS_EXPIRED',
|
|
56
|
+
'ERROR_IN_CERT_NOT_BEFORE_FIELD',
|
|
57
|
+
'ERROR_IN_CERT_NOT_AFTER_FIELD',
|
|
58
|
+
'ERROR_IN_CRL_LAST_UPDATE_FIELD',
|
|
59
|
+
'ERROR_IN_CRL_NEXT_UPDATE_FIELD',
|
|
60
|
+
'OUT_OF_MEM',
|
|
61
|
+
'DEPTH_ZERO_SELF_SIGNED_CERT',
|
|
62
|
+
'SELF_SIGNED_CERT_IN_CHAIN',
|
|
63
|
+
'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
|
|
64
|
+
'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
|
|
65
|
+
'CERT_CHAIN_TOO_LONG',
|
|
66
|
+
'CERT_REVOKED',
|
|
67
|
+
'INVALID_CA',
|
|
68
|
+
'PATH_LENGTH_EXCEEDED',
|
|
69
|
+
'INVALID_PURPOSE',
|
|
70
|
+
'CERT_UNTRUSTED',
|
|
71
|
+
'CERT_REJECTED',
|
|
72
|
+
'HOSTNAME_MISMATCH'
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
// TODO: Use `error?.code` when targeting Node.js 14
|
|
76
|
+
isRetryAllowed$1 = error => !denyList.has(error && error.code);
|
|
77
|
+
return isRetryAllowed$1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var isRetryAllowedExports = requireIsRetryAllowed();
|
|
81
|
+
var isRetryAllowed = /*@__PURE__*/getDefaultExportFromCjs(isRetryAllowedExports);
|
|
82
|
+
|
|
83
|
+
const namespace = 'axios-retry';
|
|
84
|
+
function isNetworkError(error) {
|
|
85
|
+
const CODE_EXCLUDE_LIST = ['ERR_CANCELED', 'ECONNABORTED'];
|
|
86
|
+
if (error.response) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (!error.code) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
// Prevents retrying timed out & cancelled requests
|
|
93
|
+
if (CODE_EXCLUDE_LIST.includes(error.code)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
// Prevents retrying unsafe errors
|
|
97
|
+
return isRetryAllowed(error);
|
|
98
|
+
}
|
|
99
|
+
const SAFE_HTTP_METHODS = ['get', 'head', 'options'];
|
|
100
|
+
const IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);
|
|
101
|
+
function isRetryableError(error) {
|
|
102
|
+
return (error.code !== 'ECONNABORTED' &&
|
|
103
|
+
(!error.response ||
|
|
104
|
+
error.response.status === 429 ||
|
|
105
|
+
(error.response.status >= 500 && error.response.status <= 599)));
|
|
106
|
+
}
|
|
107
|
+
function isSafeRequestError(error) {
|
|
108
|
+
if (!error.config?.method) {
|
|
109
|
+
// Cannot determine if the request can be retried
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error.config.method) !== -1;
|
|
113
|
+
}
|
|
114
|
+
function isIdempotentRequestError(error) {
|
|
115
|
+
if (!error.config?.method) {
|
|
116
|
+
// Cannot determine if the request can be retried
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return isRetryableError(error) && IDEMPOTENT_HTTP_METHODS.indexOf(error.config.method) !== -1;
|
|
120
|
+
}
|
|
121
|
+
function isNetworkOrIdempotentRequestError(error) {
|
|
122
|
+
return isNetworkError(error) || isIdempotentRequestError(error);
|
|
123
|
+
}
|
|
124
|
+
function retryAfter(error = undefined) {
|
|
125
|
+
const retryAfterHeader = error?.response?.headers['retry-after'];
|
|
126
|
+
if (!retryAfterHeader) {
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
// if the retry after header is a number, convert it to milliseconds
|
|
130
|
+
let retryAfterMs = (Number(retryAfterHeader) || 0) * 1000;
|
|
131
|
+
// If the retry after header is a date, get the number of milliseconds until that date
|
|
132
|
+
if (retryAfterMs === 0) {
|
|
133
|
+
retryAfterMs = (new Date(retryAfterHeader).valueOf() || 0) - Date.now();
|
|
134
|
+
}
|
|
135
|
+
return Math.max(0, retryAfterMs);
|
|
136
|
+
}
|
|
137
|
+
function noDelay(_retryNumber = 0, error = undefined) {
|
|
138
|
+
return Math.max(0, retryAfter(error));
|
|
139
|
+
}
|
|
140
|
+
function exponentialDelay(retryNumber = 0, error = undefined, delayFactor = 100) {
|
|
141
|
+
const calculatedDelay = 2 ** retryNumber * delayFactor;
|
|
142
|
+
const delay = Math.max(calculatedDelay, retryAfter(error));
|
|
143
|
+
const randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
|
|
144
|
+
return delay + randomSum;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Linear delay
|
|
148
|
+
* @param {number | undefined} delayFactor - delay factor in milliseconds (default: 100)
|
|
149
|
+
* @returns {function} (retryNumber: number, error: AxiosError | undefined) => number
|
|
150
|
+
*/
|
|
151
|
+
function linearDelay(delayFactor = 100) {
|
|
152
|
+
return (retryNumber = 0, error = undefined) => {
|
|
153
|
+
const delay = retryNumber * delayFactor;
|
|
154
|
+
return Math.max(delay, retryAfter(error));
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const DEFAULT_OPTIONS = {
|
|
158
|
+
retries: 3,
|
|
159
|
+
retryCondition: isNetworkOrIdempotentRequestError,
|
|
160
|
+
retryDelay: noDelay,
|
|
161
|
+
shouldResetTimeout: false,
|
|
162
|
+
onRetry: () => { },
|
|
163
|
+
onMaxRetryTimesExceeded: () => { },
|
|
164
|
+
validateResponse: null
|
|
165
|
+
};
|
|
166
|
+
function getRequestOptions(config, defaultOptions) {
|
|
167
|
+
return { ...DEFAULT_OPTIONS, ...defaultOptions, ...config[namespace] };
|
|
168
|
+
}
|
|
169
|
+
function setCurrentState(config, defaultOptions, resetLastRequestTime = false) {
|
|
170
|
+
const currentState = getRequestOptions(config, defaultOptions || {});
|
|
171
|
+
currentState.retryCount = currentState.retryCount || 0;
|
|
172
|
+
if (!currentState.lastRequestTime || resetLastRequestTime) {
|
|
173
|
+
currentState.lastRequestTime = Date.now();
|
|
174
|
+
}
|
|
175
|
+
config[namespace] = currentState;
|
|
176
|
+
return currentState;
|
|
177
|
+
}
|
|
178
|
+
function fixConfig(axiosInstance, config) {
|
|
179
|
+
// @ts-ignore
|
|
180
|
+
if (axiosInstance.defaults.agent === config.agent) {
|
|
181
|
+
// @ts-ignore
|
|
182
|
+
delete config.agent;
|
|
183
|
+
}
|
|
184
|
+
if (axiosInstance.defaults.httpAgent === config.httpAgent) {
|
|
185
|
+
delete config.httpAgent;
|
|
186
|
+
}
|
|
187
|
+
if (axiosInstance.defaults.httpsAgent === config.httpsAgent) {
|
|
188
|
+
delete config.httpsAgent;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function shouldRetry(currentState, error) {
|
|
192
|
+
const { retries, retryCondition } = currentState;
|
|
193
|
+
const shouldRetryOrPromise = (currentState.retryCount || 0) < retries && retryCondition(error);
|
|
194
|
+
// This could be a promise
|
|
195
|
+
if (typeof shouldRetryOrPromise === 'object') {
|
|
196
|
+
try {
|
|
197
|
+
const shouldRetryPromiseResult = await shouldRetryOrPromise;
|
|
198
|
+
// keep return true unless shouldRetryPromiseResult return false for compatibility
|
|
199
|
+
return shouldRetryPromiseResult !== false;
|
|
200
|
+
}
|
|
201
|
+
catch (_err) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return shouldRetryOrPromise;
|
|
206
|
+
}
|
|
207
|
+
async function handleRetry(axiosInstance, currentState, error, config) {
|
|
208
|
+
currentState.retryCount += 1;
|
|
209
|
+
const { retryDelay, shouldResetTimeout, onRetry } = currentState;
|
|
210
|
+
const delay = retryDelay(currentState.retryCount, error);
|
|
211
|
+
// Axios fails merging this configuration to the default configuration because it has an issue
|
|
212
|
+
// with circular structures: https://github.com/mzabriskie/axios/issues/370
|
|
213
|
+
fixConfig(axiosInstance, config);
|
|
214
|
+
if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) {
|
|
215
|
+
const lastRequestDuration = Date.now() - currentState.lastRequestTime;
|
|
216
|
+
const timeout = config.timeout - lastRequestDuration - delay;
|
|
217
|
+
if (timeout <= 0) {
|
|
218
|
+
return Promise.reject(error);
|
|
219
|
+
}
|
|
220
|
+
config.timeout = timeout;
|
|
221
|
+
}
|
|
222
|
+
config.transformRequest = [(data) => data];
|
|
223
|
+
await onRetry(currentState.retryCount, error, config);
|
|
224
|
+
if (config.signal?.aborted) {
|
|
225
|
+
return Promise.resolve(axiosInstance(config));
|
|
226
|
+
}
|
|
227
|
+
return new Promise((resolve) => {
|
|
228
|
+
const abortListener = () => {
|
|
229
|
+
clearTimeout(timeout);
|
|
230
|
+
resolve(axiosInstance(config));
|
|
231
|
+
};
|
|
232
|
+
const timeout = setTimeout(() => {
|
|
233
|
+
resolve(axiosInstance(config));
|
|
234
|
+
if (config.signal?.removeEventListener) {
|
|
235
|
+
config.signal.removeEventListener('abort', abortListener);
|
|
236
|
+
}
|
|
237
|
+
}, delay);
|
|
238
|
+
if (config.signal?.addEventListener) {
|
|
239
|
+
config.signal.addEventListener('abort', abortListener, { once: true });
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async function handleMaxRetryTimesExceeded(currentState, error) {
|
|
244
|
+
if (currentState.retryCount >= currentState.retries)
|
|
245
|
+
await currentState.onMaxRetryTimesExceeded(error, currentState.retryCount);
|
|
246
|
+
}
|
|
247
|
+
const axiosRetry = (axiosInstance, defaultOptions) => {
|
|
248
|
+
const requestInterceptorId = axiosInstance.interceptors.request.use((config) => {
|
|
249
|
+
setCurrentState(config, defaultOptions, true);
|
|
250
|
+
if (config[namespace]?.validateResponse) {
|
|
251
|
+
// by setting this, all HTTP responses will be go through the error interceptor first
|
|
252
|
+
config.validateStatus = () => false;
|
|
253
|
+
}
|
|
254
|
+
return config;
|
|
255
|
+
});
|
|
256
|
+
const responseInterceptorId = axiosInstance.interceptors.response.use(null, async (error) => {
|
|
257
|
+
const { config } = error;
|
|
258
|
+
// If we have no information to retry the request
|
|
259
|
+
if (!config) {
|
|
260
|
+
return Promise.reject(error);
|
|
261
|
+
}
|
|
262
|
+
const currentState = setCurrentState(config, defaultOptions);
|
|
263
|
+
if (error.response && currentState.validateResponse?.(error.response)) {
|
|
264
|
+
// no issue with response
|
|
265
|
+
return error.response;
|
|
266
|
+
}
|
|
267
|
+
if (await shouldRetry(currentState, error)) {
|
|
268
|
+
return handleRetry(axiosInstance, currentState, error, config);
|
|
269
|
+
}
|
|
270
|
+
await handleMaxRetryTimesExceeded(currentState, error);
|
|
271
|
+
return Promise.reject(error);
|
|
272
|
+
});
|
|
273
|
+
return { requestInterceptorId, responseInterceptorId };
|
|
274
|
+
};
|
|
275
|
+
// Compatibility with CommonJS
|
|
276
|
+
axiosRetry.isNetworkError = isNetworkError;
|
|
277
|
+
axiosRetry.isSafeRequestError = isSafeRequestError;
|
|
278
|
+
axiosRetry.isIdempotentRequestError = isIdempotentRequestError;
|
|
279
|
+
axiosRetry.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
|
|
280
|
+
axiosRetry.exponentialDelay = exponentialDelay;
|
|
281
|
+
axiosRetry.linearDelay = linearDelay;
|
|
282
|
+
axiosRetry.isRetryableError = isRetryableError;
|
|
283
|
+
|
|
29
284
|
let axiosClient;
|
|
30
285
|
async function getAxiosAuthClient() {
|
|
31
286
|
if (!axiosClient) {
|
|
@@ -35,6 +290,7 @@ async function getAxiosAuthClient() {
|
|
|
35
290
|
headers: {
|
|
36
291
|
'Content-Type': 'application/json',
|
|
37
292
|
},
|
|
293
|
+
timeout: 30000, // 30s timeout, matching makeApiRequest
|
|
38
294
|
});
|
|
39
295
|
}
|
|
40
296
|
return axiosClient;
|
|
@@ -81,15 +337,41 @@ async function createSessionWithPrivy(authToken, address, privyIdToken) {
|
|
|
81
337
|
});
|
|
82
338
|
return response.data;
|
|
83
339
|
}
|
|
340
|
+
// Deduplicate concurrent refreshSession calls to prevent multiple code paths
|
|
341
|
+
// (WebSocket reconnection, periodic refresh, API 401 retry) from all hitting
|
|
342
|
+
// /session/refresh simultaneously.
|
|
343
|
+
// Note: module-level state is shared across requests in SSR/Node — acceptable
|
|
344
|
+
// since there is only one active session per server instance (same pattern as
|
|
345
|
+
// refreshInFlight in api.ts).
|
|
346
|
+
let refreshInFlight$1 = null;
|
|
347
|
+
let refreshInFlightToken = null;
|
|
84
348
|
async function refreshSession(refreshToken) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
349
|
+
if (refreshInFlight$1 && refreshInFlightToken === refreshToken) {
|
|
350
|
+
return refreshInFlight$1;
|
|
351
|
+
}
|
|
352
|
+
refreshInFlightToken = refreshToken;
|
|
353
|
+
let currentFlight;
|
|
354
|
+
currentFlight = refreshInFlight$1 = (async () => {
|
|
355
|
+
try {
|
|
356
|
+
const client = await getAxiosAuthClient();
|
|
357
|
+
const config = await getConfig();
|
|
358
|
+
const appId = config.appId;
|
|
359
|
+
const response = await client.post('/session/refresh', {
|
|
360
|
+
refreshToken,
|
|
361
|
+
appId
|
|
362
|
+
});
|
|
363
|
+
return response.data;
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
// Only clear if we're still the active in-flight request.
|
|
367
|
+
// A second call with a different token may have replaced us.
|
|
368
|
+
if (refreshInFlight$1 === currentFlight) {
|
|
369
|
+
refreshInFlight$1 = null;
|
|
370
|
+
refreshInFlightToken = null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
})();
|
|
374
|
+
return refreshInFlight$1;
|
|
93
375
|
}
|
|
94
376
|
async function signSessionCreateMessage(_signMessageFunction) {
|
|
95
377
|
}
|
|
@@ -227,14 +509,10 @@ class WebSessionManager {
|
|
|
227
509
|
WebSessionManager.TAROBASE_SESSION_STORAGE_KEY = "tarobase_session_storage";
|
|
228
510
|
|
|
229
511
|
var webSessionManager = /*#__PURE__*/Object.freeze({
|
|
230
|
-
|
|
231
|
-
|
|
512
|
+
__proto__: null,
|
|
513
|
+
WebSessionManager: WebSessionManager
|
|
232
514
|
});
|
|
233
515
|
|
|
234
|
-
function getDefaultExportFromCjs (x) {
|
|
235
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
516
|
var buffer = {};
|
|
239
517
|
|
|
240
518
|
var base64Js = {};
|
|
@@ -3031,7 +3309,19 @@ async function buildSetDocumentsTransaction(connection, idl, anchorProvider, pay
|
|
|
3031
3309
|
}
|
|
3032
3310
|
}
|
|
3033
3311
|
else if (lutKey != null) {
|
|
3034
|
-
|
|
3312
|
+
// The LUT may have just been created server-side and the client's RPC node
|
|
3313
|
+
// may not have indexed it yet (load-balancer split). Retry with exponential
|
|
3314
|
+
// back-off; first retry at 100 ms almost always resolves it.
|
|
3315
|
+
let table = null;
|
|
3316
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
3317
|
+
const { value } = await connection.getAddressLookupTable(new web3_js.PublicKey(lutKey));
|
|
3318
|
+
if (value) {
|
|
3319
|
+
table = value;
|
|
3320
|
+
break;
|
|
3321
|
+
}
|
|
3322
|
+
if (attempt < 4)
|
|
3323
|
+
await new Promise(r => setTimeout(r, 100 * Math.pow(2, attempt)));
|
|
3324
|
+
}
|
|
3035
3325
|
if (!table)
|
|
3036
3326
|
throw new Error('LUT not found after creation/extend');
|
|
3037
3327
|
lookupTables.push(table);
|
|
@@ -3166,8 +3456,8 @@ class ServerSessionManager {
|
|
|
3166
3456
|
ServerSessionManager.instance = new ServerSessionManager();
|
|
3167
3457
|
|
|
3168
3458
|
var serverSessionManager = /*#__PURE__*/Object.freeze({
|
|
3169
|
-
|
|
3170
|
-
|
|
3459
|
+
__proto__: null,
|
|
3460
|
+
ServerSessionManager: ServerSessionManager
|
|
3171
3461
|
});
|
|
3172
3462
|
|
|
3173
3463
|
/**
|
|
@@ -3266,6 +3556,23 @@ async function updateIdTokenAndAccessToken(idToken, accessToken, isServer = fals
|
|
|
3266
3556
|
await WebSessionManager.updateIdTokenAndAccessToken(idToken, accessToken);
|
|
3267
3557
|
}
|
|
3268
3558
|
|
|
3559
|
+
const apiClient = axios.create();
|
|
3560
|
+
axiosRetry(apiClient, {
|
|
3561
|
+
retries: 2,
|
|
3562
|
+
retryCondition: (error) => {
|
|
3563
|
+
var _a, _b;
|
|
3564
|
+
// Only retry GET requests on network errors (ECONNRESET, ETIMEDOUT, etc.)
|
|
3565
|
+
// Writes (POST/PUT) are not retried — the server may have processed
|
|
3566
|
+
// the request before the connection was reset.
|
|
3567
|
+
return axiosRetry.isNetworkError(error) && ((_b = (_a = error.config) === null || _a === void 0 ? void 0 : _a.method) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'get';
|
|
3568
|
+
},
|
|
3569
|
+
retryDelay: axiosRetry.exponentialDelay,
|
|
3570
|
+
shouldResetTimeout: true,
|
|
3571
|
+
onRetry: (retryCount, error, requestConfig) => {
|
|
3572
|
+
var _a;
|
|
3573
|
+
console.warn(`[tarobase-sdk] retry ${retryCount} for ${(_a = requestConfig.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()} ${requestConfig.url} — ${error.code || error.message}`);
|
|
3574
|
+
},
|
|
3575
|
+
});
|
|
3269
3576
|
const refreshInFlight = new Map();
|
|
3270
3577
|
async function refreshAuthSessionOnce(appId, isServer) {
|
|
3271
3578
|
const key = `${isServer ? "server" : "web"}:${appId}`;
|
|
@@ -3312,6 +3619,7 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
|
|
|
3312
3619
|
ServerSessionManager.instance.clearSession();
|
|
3313
3620
|
};
|
|
3314
3621
|
async function executeRequest() {
|
|
3622
|
+
var _a;
|
|
3315
3623
|
// When _getAuthHeaders is provided (wallet client), use it as the sole auth source.
|
|
3316
3624
|
// Otherwise use the global createAuthHeader (default path).
|
|
3317
3625
|
const authHeader = (_overrides === null || _overrides === void 0 ? void 0 : _overrides._getAuthHeaders)
|
|
@@ -3333,11 +3641,12 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
|
|
|
3333
3641
|
method,
|
|
3334
3642
|
url: `${config.apiUrl}${urlPath.startsWith("/") ? urlPath : `/${urlPath}`}`,
|
|
3335
3643
|
headers,
|
|
3644
|
+
timeout: (_a = _overrides === null || _overrides === void 0 ? void 0 : _overrides.timeout) !== null && _a !== void 0 ? _a : 30000,
|
|
3336
3645
|
};
|
|
3337
3646
|
if (method !== "GET" && method !== "get") {
|
|
3338
3647
|
requestConfig.data = data ? JSON.stringify(data) : {};
|
|
3339
3648
|
}
|
|
3340
|
-
const response = await
|
|
3649
|
+
const response = await apiClient(requestConfig);
|
|
3341
3650
|
return { data: response.data, status: response.status, headers: response.headers };
|
|
3342
3651
|
}
|
|
3343
3652
|
try {
|
|
@@ -4273,6 +4582,7 @@ function scheduleTokenRefresh(connection, isServer) {
|
|
|
4273
4582
|
// This replaces the old single setTimeout approach which was unreliable for long
|
|
4274
4583
|
// delays (browsers throttle/suspend timers in background tabs).
|
|
4275
4584
|
connection.tokenRefreshTimer = setInterval(async () => {
|
|
4585
|
+
var _a, _b;
|
|
4276
4586
|
try {
|
|
4277
4587
|
const currentToken = await getIdToken(isServer);
|
|
4278
4588
|
if (!currentToken)
|
|
@@ -4303,6 +4613,17 @@ function scheduleTokenRefresh(connection, isServer) {
|
|
|
4303
4613
|
}
|
|
4304
4614
|
}
|
|
4305
4615
|
catch (refreshError) {
|
|
4616
|
+
// If the refresh token itself is invalid (401/403), stop retrying —
|
|
4617
|
+
// the token won't magically become valid next interval, and continuing
|
|
4618
|
+
// to hammer /session/refresh causes 429 rate-limit storms.
|
|
4619
|
+
if (((_a = refreshError === null || refreshError === void 0 ? void 0 : refreshError.response) === null || _a === void 0 ? void 0 : _a.status) === 401 || ((_b = refreshError === null || refreshError === void 0 ? void 0 : refreshError.response) === null || _b === void 0 ? void 0 : _b.status) === 403) {
|
|
4620
|
+
console.warn('[WS v2] Refresh token rejected (401/403), stopping periodic refresh');
|
|
4621
|
+
if (connection.tokenRefreshTimer) {
|
|
4622
|
+
clearInterval(connection.tokenRefreshTimer);
|
|
4623
|
+
connection.tokenRefreshTimer = null;
|
|
4624
|
+
}
|
|
4625
|
+
return;
|
|
4626
|
+
}
|
|
4306
4627
|
console.warn('[WS v2] Proactive token refresh failed, will retry next interval:', refreshError);
|
|
4307
4628
|
}
|
|
4308
4629
|
}
|
|
@@ -4313,6 +4634,7 @@ function scheduleTokenRefresh(connection, isServer) {
|
|
|
4313
4634
|
}, TOKEN_CHECK_INTERVAL);
|
|
4314
4635
|
}
|
|
4315
4636
|
async function getFreshAuthToken(isServer) {
|
|
4637
|
+
var _a, _b;
|
|
4316
4638
|
const currentToken = await getIdToken(isServer);
|
|
4317
4639
|
if (!currentToken) {
|
|
4318
4640
|
return null;
|
|
@@ -4335,6 +4657,17 @@ async function getFreshAuthToken(isServer) {
|
|
|
4335
4657
|
}
|
|
4336
4658
|
catch (error) {
|
|
4337
4659
|
console.error('[WS v2] Error refreshing token:', error);
|
|
4660
|
+
// If the refresh token is permanently invalid (401/403), clear the stale
|
|
4661
|
+
// session from storage so future attempts don't keep retrying with it.
|
|
4662
|
+
if (!isServer && (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) === 401 || ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.status) === 403)) {
|
|
4663
|
+
try {
|
|
4664
|
+
const { WebSessionManager } = await Promise.resolve().then(function () { return webSessionManager; });
|
|
4665
|
+
WebSessionManager.clearSession();
|
|
4666
|
+
}
|
|
4667
|
+
catch (clearError) {
|
|
4668
|
+
console.warn('[WS v2] Failed to clear stale session:', clearError);
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4338
4671
|
}
|
|
4339
4672
|
// Return null instead of the expired token to prevent infinite 401 reconnect storms.
|
|
4340
4673
|
// The server accepts unauthenticated connections; auth-required subscriptions will
|
|
@@ -4455,7 +4788,16 @@ async function getOrCreateConnection(appId, isServer) {
|
|
|
4455
4788
|
ws.addEventListener('open', () => {
|
|
4456
4789
|
connection.isConnecting = false;
|
|
4457
4790
|
connection.isConnected = true;
|
|
4458
|
-
|
|
4791
|
+
// NOTE: Do NOT reset consecutiveAuthFailures here. It is reset when a
|
|
4792
|
+
// fresh auth token is actually obtained (in urlProvider, line ~389) or on
|
|
4793
|
+
// an explicit auth change (reconnectWithNewAuthV2, line ~854). Resetting
|
|
4794
|
+
// on every 'open' event created an infinite loop: auth fails 5x → connect
|
|
4795
|
+
// without auth → open resets counter → disconnect → auth fails 5x again →
|
|
4796
|
+
// repeat forever, hammering /session/refresh and causing 429s.
|
|
4797
|
+
//
|
|
4798
|
+
// An elevated counter is safe for anonymous/guest sessions: when there's no
|
|
4799
|
+
// token at all (getIdToken returns null), the counter is never checked —
|
|
4800
|
+
// urlProvider skips straight to unauthenticated connection.
|
|
4459
4801
|
// Schedule periodic token freshness checks
|
|
4460
4802
|
scheduleTokenRefresh(connection, isServer);
|
|
4461
4803
|
// Re-subscribe to all existing subscriptions after reconnect
|