@lidofinance/rpc 0.58.0 → 0.60.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/README.md +22 -0
- package/dist/index.cjs +25 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +25 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,3 +42,25 @@ export const cachedFetchRpcFactory = (timeout: number): CachedFetchRPC => {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
|
+
|
|
46
|
+
### iterateUrls fallback callback
|
|
47
|
+
|
|
48
|
+
`iterateUrls(urls, callback, onError?)` iterates provider URLs until one succeeds. The optional `onError` handler fires when an attempt fails — either the callback threw, or it returned a non-ok `Response`. The second argument carries context so you can log structured fallback transitions.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { iterateUrls } from '@lidofinance/rpc'
|
|
52
|
+
|
|
53
|
+
await iterateUrls(
|
|
54
|
+
providers,
|
|
55
|
+
(url) => fetch(url),
|
|
56
|
+
(error, { failedUrl, nextUrl, attempt, response }) => {
|
|
57
|
+
if (nextUrl) {
|
|
58
|
+
logger.warn(`RPC ${failedUrl} failed (attempt ${attempt}), switching to ${nextUrl}`)
|
|
59
|
+
} else {
|
|
60
|
+
logger.error(`All RPC providers failed, last one was ${failedUrl}`)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Handlers with a single-argument signature (`(error) => ...`) keep working — the extra context argument is simply ignored.
|
package/dist/index.cjs
CHANGED
|
@@ -46,15 +46,31 @@ class $f5c96785547d6405$export$544290ca59c30f2b extends Error {
|
|
|
46
46
|
const $f5c96785547d6405$export$874e79e4fbe19379 = async (urls, callback, onError)=>{
|
|
47
47
|
let lastResponse;
|
|
48
48
|
let lastError;
|
|
49
|
-
for
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
for(let i = 0; i < urls.length; i++){
|
|
50
|
+
const url = urls[i];
|
|
51
|
+
const nextUrl = urls[i + 1];
|
|
52
|
+
try {
|
|
53
|
+
const response = await callback(url);
|
|
54
|
+
lastResponse = response;
|
|
55
|
+
// We want to return first succeeded response
|
|
56
|
+
if (typeof Response !== "undefined" && response instanceof Response && !response.ok) {
|
|
57
|
+
if (onError) onError(new Error(`Non-ok response: ${response.status}`), {
|
|
58
|
+
failedUrl: url,
|
|
59
|
+
nextUrl: nextUrl,
|
|
60
|
+
attempt: i + 1,
|
|
61
|
+
response: response
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
return response;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (onError) onError(error, {
|
|
68
|
+
failedUrl: url,
|
|
69
|
+
nextUrl: nextUrl,
|
|
70
|
+
attempt: i + 1
|
|
71
|
+
});
|
|
72
|
+
lastError = error;
|
|
73
|
+
}
|
|
58
74
|
}
|
|
59
75
|
// If there are no succeeded responses, return last not thrown
|
|
60
76
|
if (lastResponse != null) return lastResponse;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;ACoBO,MAAM,4CAAqB,CAAC,KAAK,OACtC,MAAM,KAAK;QACT,GAAG,IAAI;QACP,QAAQ;QACR,SAAS;YACP,GAAG,KAAK,OAAO;YACf,gBAAgB;QAClB;QACA,MAAM,KAAK,UAAU,KAAK;IAC5B;;;;;;;AC7BK,MAAM,kDAAgC;IAC3C,YAAY,OAAgB,CAAE;QAC5B,KAAK,CAAC,WAAW;IACnB;AACF;
|
|
1
|
+
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;ACoBO,MAAM,4CAAqB,CAAC,KAAK,OACtC,MAAM,KAAK;QACT,GAAG,IAAI;QACP,QAAQ;QACR,SAAS;YACP,GAAG,KAAK,OAAO;YACf,gBAAgB;QAClB;QACA,MAAM,KAAK,UAAU,KAAK;IAC5B;;;;;;;AC7BK,MAAM,kDAAgC;IAC3C,YAAY,OAAgB,CAAE;QAC5B,KAAK,CAAC,WAAW;IACnB;AACF;AASO,MAAM,4CAAc,OACzB,MACA,UACA;IAEA,IAAI;IACJ,IAAI;IAEJ,IAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAK;QACpC,MAAM,MAAM,IAAI,CAAC,EAAE;QACnB,MAAM,UAAU,IAAI,CAAC,IAAI,EAAE;QAC3B,IAAI;YACF,MAAM,WAAW,MAAM,SAAS;YAChC,eAAe;YAEf,6CAA6C;YAC7C,IAAI,OAAO,aAAa,eAAe,oBAAoB,YAAY,CAAC,SAAS,IAAI;gBACnF,IAAI,SACF,QAAQ,IAAI,MAAM,CAAC,iBAAiB,EAAE,SAAS,OAAO,CAAC,GAAG;oBACxD,WAAW;6BACX;oBACA,SAAS,IAAI;8BACb;gBACF;gBAEF;YACF;YAEA,OAAO;QACT,EAAE,OAAO,OAAO;YACd,IAAI,SACF,QAAQ,OAAO;gBAAE,WAAW;yBAAK;gBAAS,SAAS,IAAI;YAAE;YAE3D,YAAY;QACd;IACF;IAEA,8DAA8D;IAC9D,IAAI,gBAAgB,MAClB,OAAO;IAET,qDAAqD;IACrD,IAAI,aAAa,MACf,MAAM;IAER,+BAA+B;IAC/B,MAAM,IAAI;AACZ;;","sources":["packages/core/rpc/src/index.ts","packages/core/rpc/src/fetchRpc.ts","packages/core/rpc/src/iterateUrls.ts"],"sourcesContent":["import 'isomorphic-fetch'\n\nexport * from './fetchRpc'\nexport * from './iterateUrls'\n","export type FetchRpcInitBody = {\n jsonrpc: '1.0' | '2.0' | string\n method: string\n params?: unknown\n id?: string | number | null\n}\n\n// eslint-disable-next-line no-undef\nexport type FetchRpcInit = Omit<RequestInit, 'body' | 'method'> & {\n method?: 'POST'\n body: FetchRpcInitBody | FetchRpcInitBody[]\n}\n\n// Need Extension type so we can extend fetchRPC with metrics tracking or caching\nexport type FetchRpc<Extension extends Record<string | number, unknown> | void = void> = (\n url: string,\n init: FetchRpcInit,\n extension: Extension,\n) => Promise<Response>\n\nexport const fetchRpc: FetchRpc = (url, init) =>\n fetch(url, {\n ...init,\n method: 'POST',\n headers: {\n ...init.headers,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(init.body),\n })\n","export class ExhaustedIterationError extends Error {\n constructor(message?: string) {\n super(message ?? 'Iteration ended without success')\n }\n}\n\nexport type IterateUrlsErrorContext = {\n failedUrl: string\n nextUrl: string | undefined\n attempt: number\n response?: Response\n}\n\nexport const iterateUrls = async <T>(\n urls: [string, ...string[]],\n callback: (url: string) => T | Promise<T>,\n onError?: (error: unknown, context: IterateUrlsErrorContext) => unknown,\n): Promise<T> => {\n let lastResponse: T | undefined\n let lastError: unknown | undefined\n\n for (let i = 0; i < urls.length; i++) {\n const url = urls[i]\n const nextUrl = urls[i + 1]\n try {\n const response = await callback(url)\n lastResponse = response\n\n // We want to return first succeeded response\n if (typeof Response !== 'undefined' && response instanceof Response && !response.ok) {\n if (onError) {\n onError(new Error(`Non-ok response: ${response.status}`), {\n failedUrl: url,\n nextUrl,\n attempt: i + 1,\n response,\n })\n }\n continue\n }\n\n return response\n } catch (error) {\n if (onError) {\n onError(error, { failedUrl: url, nextUrl, attempt: i + 1 })\n }\n lastError = error\n }\n }\n\n // If there are no succeeded responses, return last not thrown\n if (lastResponse != null) {\n return lastResponse\n }\n // If there are no responses at all, throw last error\n if (lastError != null) {\n throw lastError\n }\n // This should not be reachable\n throw new ExhaustedIterationError()\n}\n"],"names":[],"version":3,"file":"index.cjs.map"}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,12 @@ export const fetchRpc: FetchRpc;
|
|
|
13
13
|
export class ExhaustedIterationError extends Error {
|
|
14
14
|
constructor(message?: string);
|
|
15
15
|
}
|
|
16
|
-
export
|
|
16
|
+
export type IterateUrlsErrorContext = {
|
|
17
|
+
failedUrl: string;
|
|
18
|
+
nextUrl: string | undefined;
|
|
19
|
+
attempt: number;
|
|
20
|
+
response?: Response;
|
|
21
|
+
};
|
|
22
|
+
export const iterateUrls: <T>(urls: [string, ...string[]], callback: (url: string) => T | Promise<T>, onError?: ((error: unknown, context: IterateUrlsErrorContext) => unknown) | undefined) => Promise<T>;
|
|
17
23
|
|
|
18
24
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA,+BAA+B;IAC7B,OAAO,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAC5B,CAAA;AAGD,2BAA2B,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAA;CAC5C,CAAA;AAGD,qBAAqB,SAAS,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,IAAI,CACvF,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,SAAS,KACjB,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEtB,OAAO,MAAM,UAAU,QASnB,CAAA;AC7BJ,oCAAqC,SAAQ,KAAK;gBACpC,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED,OAAO,MAAM,uBACL,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,kBACX,MAAM,wCACJ,OAAO,KAAK,OAAO,
|
|
1
|
+
{"mappings":"AAAA,+BAA+B;IAC7B,OAAO,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAC5B,CAAA;AAGD,2BAA2B,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAA;CAC5C,CAAA;AAGD,qBAAqB,SAAS,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,IAAI,CACvF,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,SAAS,KACjB,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEtB,OAAO,MAAM,UAAU,QASnB,CAAA;AC7BJ,oCAAqC,SAAQ,KAAK;gBACpC,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED,sCAAsC;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB,CAAA;AAED,OAAO,MAAM,uBACL,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,kBACX,MAAM,wCACJ,OAAO,WAAW,uBAAuB,KAAK,OAAO,4BA4CxE,CAAA","sources":["packages/core/rpc/src/src/fetchRpc.ts","packages/core/rpc/src/src/iterateUrls.ts","packages/core/rpc/src/src/index.ts","packages/core/rpc/src/index.ts"],"sourcesContent":[null,null,null,"import 'isomorphic-fetch'\n\nexport * from './fetchRpc'\nexport * from './iterateUrls'\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
package/dist/index.mjs
CHANGED
|
@@ -30,15 +30,31 @@ class $83a6df06ccf0d0e9$export$544290ca59c30f2b extends Error {
|
|
|
30
30
|
const $83a6df06ccf0d0e9$export$874e79e4fbe19379 = async (urls, callback, onError)=>{
|
|
31
31
|
let lastResponse;
|
|
32
32
|
let lastError;
|
|
33
|
-
for
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
for(let i = 0; i < urls.length; i++){
|
|
34
|
+
const url = urls[i];
|
|
35
|
+
const nextUrl = urls[i + 1];
|
|
36
|
+
try {
|
|
37
|
+
const response = await callback(url);
|
|
38
|
+
lastResponse = response;
|
|
39
|
+
// We want to return first succeeded response
|
|
40
|
+
if (typeof Response !== "undefined" && response instanceof Response && !response.ok) {
|
|
41
|
+
if (onError) onError(new Error(`Non-ok response: ${response.status}`), {
|
|
42
|
+
failedUrl: url,
|
|
43
|
+
nextUrl: nextUrl,
|
|
44
|
+
attempt: i + 1,
|
|
45
|
+
response: response
|
|
46
|
+
});
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
return response;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (onError) onError(error, {
|
|
52
|
+
failedUrl: url,
|
|
53
|
+
nextUrl: nextUrl,
|
|
54
|
+
attempt: i + 1
|
|
55
|
+
});
|
|
56
|
+
lastError = error;
|
|
57
|
+
}
|
|
42
58
|
}
|
|
43
59
|
// If there are no succeeded responses, return last not thrown
|
|
44
60
|
if (lastResponse != null) return lastResponse;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;ACoBO,MAAM,4CAAqB,CAAC,KAAK,OACtC,MAAM,KAAK;QACT,GAAG,IAAI;QACP,QAAQ;QACR,SAAS;YACP,GAAG,KAAK,OAAO;YACf,gBAAgB;QAClB;QACA,MAAM,KAAK,UAAU,KAAK;IAC5B;;;;;;;AC7BK,MAAM,kDAAgC;IAC3C,YAAY,OAAgB,CAAE;QAC5B,KAAK,CAAC,WAAW;IACnB;AACF;
|
|
1
|
+
{"mappings":";;;;;;;;;ACoBO,MAAM,4CAAqB,CAAC,KAAK,OACtC,MAAM,KAAK;QACT,GAAG,IAAI;QACP,QAAQ;QACR,SAAS;YACP,GAAG,KAAK,OAAO;YACf,gBAAgB;QAClB;QACA,MAAM,KAAK,UAAU,KAAK;IAC5B;;;;;;;AC7BK,MAAM,kDAAgC;IAC3C,YAAY,OAAgB,CAAE;QAC5B,KAAK,CAAC,WAAW;IACnB;AACF;AASO,MAAM,4CAAc,OACzB,MACA,UACA;IAEA,IAAI;IACJ,IAAI;IAEJ,IAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAK;QACpC,MAAM,MAAM,IAAI,CAAC,EAAE;QACnB,MAAM,UAAU,IAAI,CAAC,IAAI,EAAE;QAC3B,IAAI;YACF,MAAM,WAAW,MAAM,SAAS;YAChC,eAAe;YAEf,6CAA6C;YAC7C,IAAI,OAAO,aAAa,eAAe,oBAAoB,YAAY,CAAC,SAAS,IAAI;gBACnF,IAAI,SACF,QAAQ,IAAI,MAAM,CAAC,iBAAiB,EAAE,SAAS,OAAO,CAAC,GAAG;oBACxD,WAAW;6BACX;oBACA,SAAS,IAAI;8BACb;gBACF;gBAEF;YACF;YAEA,OAAO;QACT,EAAE,OAAO,OAAO;YACd,IAAI,SACF,QAAQ,OAAO;gBAAE,WAAW;yBAAK;gBAAS,SAAS,IAAI;YAAE;YAE3D,YAAY;QACd;IACF;IAEA,8DAA8D;IAC9D,IAAI,gBAAgB,MAClB,OAAO;IAET,qDAAqD;IACrD,IAAI,aAAa,MACf,MAAM;IAER,+BAA+B;IAC/B,MAAM,IAAI;AACZ;;","sources":["packages/core/rpc/src/index.ts","packages/core/rpc/src/fetchRpc.ts","packages/core/rpc/src/iterateUrls.ts"],"sourcesContent":["import 'isomorphic-fetch'\n\nexport * from './fetchRpc'\nexport * from './iterateUrls'\n","export type FetchRpcInitBody = {\n jsonrpc: '1.0' | '2.0' | string\n method: string\n params?: unknown\n id?: string | number | null\n}\n\n// eslint-disable-next-line no-undef\nexport type FetchRpcInit = Omit<RequestInit, 'body' | 'method'> & {\n method?: 'POST'\n body: FetchRpcInitBody | FetchRpcInitBody[]\n}\n\n// Need Extension type so we can extend fetchRPC with metrics tracking or caching\nexport type FetchRpc<Extension extends Record<string | number, unknown> | void = void> = (\n url: string,\n init: FetchRpcInit,\n extension: Extension,\n) => Promise<Response>\n\nexport const fetchRpc: FetchRpc = (url, init) =>\n fetch(url, {\n ...init,\n method: 'POST',\n headers: {\n ...init.headers,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(init.body),\n })\n","export class ExhaustedIterationError extends Error {\n constructor(message?: string) {\n super(message ?? 'Iteration ended without success')\n }\n}\n\nexport type IterateUrlsErrorContext = {\n failedUrl: string\n nextUrl: string | undefined\n attempt: number\n response?: Response\n}\n\nexport const iterateUrls = async <T>(\n urls: [string, ...string[]],\n callback: (url: string) => T | Promise<T>,\n onError?: (error: unknown, context: IterateUrlsErrorContext) => unknown,\n): Promise<T> => {\n let lastResponse: T | undefined\n let lastError: unknown | undefined\n\n for (let i = 0; i < urls.length; i++) {\n const url = urls[i]\n const nextUrl = urls[i + 1]\n try {\n const response = await callback(url)\n lastResponse = response\n\n // We want to return first succeeded response\n if (typeof Response !== 'undefined' && response instanceof Response && !response.ok) {\n if (onError) {\n onError(new Error(`Non-ok response: ${response.status}`), {\n failedUrl: url,\n nextUrl,\n attempt: i + 1,\n response,\n })\n }\n continue\n }\n\n return response\n } catch (error) {\n if (onError) {\n onError(error, { failedUrl: url, nextUrl, attempt: i + 1 })\n }\n lastError = error\n }\n }\n\n // If there are no succeeded responses, return last not thrown\n if (lastResponse != null) {\n return lastResponse\n }\n // If there are no responses at all, throw last error\n if (lastError != null) {\n throw lastError\n }\n // This should not be reachable\n throw new ExhaustedIterationError()\n}\n"],"names":[],"version":3,"file":"index.mjs.map"}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://github.com/lidofinance/warehouse/issues"
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.60.0",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist"
|
|
13
13
|
],
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test": "jest"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@lidofinance/config-prettier": "~0.
|
|
36
|
+
"@lidofinance/config-prettier": "~0.60.0",
|
|
37
37
|
"@types/jest": "^29.2.4",
|
|
38
38
|
"jest": "^29.3.1",
|
|
39
39
|
"ts-jest": "^29.0.3",
|