@lidofinance/next-pages 0.0.3
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 +80 -0
- package/dist/index.cjs +118 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +100 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @lidofinance/next-pages
|
|
2
|
+
|
|
3
|
+
Common next pages.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`yarn add @lidofinance/next-pages`.
|
|
8
|
+
|
|
9
|
+
## Getting started
|
|
10
|
+
|
|
11
|
+
### health
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { health } from '@lidofinance/next-pages';
|
|
15
|
+
|
|
16
|
+
export default health;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### metrics
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { registry } from 'utilsApi/metrics';
|
|
23
|
+
import { metricsFactory } from '@lidofinance/next-pages';
|
|
24
|
+
|
|
25
|
+
const metrics = metricsFactory({
|
|
26
|
+
registry,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default metrics;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### rpc
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import getConfig from 'next/config';
|
|
36
|
+
import { registry } from 'utilsApi/metrics';
|
|
37
|
+
import { rpcFactory } from '@lidofinance/api-pages';
|
|
38
|
+
import { METRICS_PREFIX } from '../../config';
|
|
39
|
+
import { fetchRPC, serverLogger } from 'utilsApi';
|
|
40
|
+
|
|
41
|
+
const { publicRuntimeConfig, serverRuntimeConfig } = getConfig();
|
|
42
|
+
const { defaultChain } = publicRuntimeConfig;
|
|
43
|
+
const { infuraApiKey, alchemyApiKey } = serverRuntimeConfig;
|
|
44
|
+
|
|
45
|
+
// Should be a separate file
|
|
46
|
+
export const enum CHAINS {
|
|
47
|
+
Mainnet = 1,
|
|
48
|
+
Goerli = 5,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Should be a separate file
|
|
52
|
+
export const providers: Record<CHAINS, [string, ...string[]]> = {
|
|
53
|
+
[CHAINS.Mainnet]: [
|
|
54
|
+
`https://mainnet.infura.io/v3/${infuraApiKey}`,
|
|
55
|
+
`https://eth-mainnet.alchemyapi.io/v2/${alchemyApiKey}`,
|
|
56
|
+
],
|
|
57
|
+
[CHAINS.Goerli]: [
|
|
58
|
+
`https://goerli.infura.io/v3/${infuraApiKey}`,
|
|
59
|
+
`https://eth-goerli.alchemyapi.io/v2/${alchemyApiKey}`,
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const rpc = rpcFactory({
|
|
64
|
+
fetchRPC,
|
|
65
|
+
serverLogger,
|
|
66
|
+
metrics: {
|
|
67
|
+
prefix: METRICS_PREFIX,
|
|
68
|
+
registry,
|
|
69
|
+
},
|
|
70
|
+
allowedRPCMethods: [
|
|
71
|
+
'eth_call',
|
|
72
|
+
'eth_gasPrice',
|
|
73
|
+
// ...
|
|
74
|
+
],
|
|
75
|
+
defaultChain,
|
|
76
|
+
providers,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export default rpc;
|
|
80
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var $3HXpq$promclient = require("prom-client");
|
|
2
|
+
var $3HXpq$lidofinancerpc = require("@lidofinance/rpc");
|
|
3
|
+
|
|
4
|
+
function $parcel$exportWildcard(dest, source) {
|
|
5
|
+
Object.keys(source).forEach(function(key) {
|
|
6
|
+
if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
Object.defineProperty(dest, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function get() {
|
|
13
|
+
return source[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return dest;
|
|
19
|
+
}
|
|
20
|
+
function $parcel$export(e, n, v, s) {
|
|
21
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
22
|
+
}
|
|
23
|
+
var $c081037d441fc5cd$exports = {};
|
|
24
|
+
|
|
25
|
+
$parcel$export($c081037d441fc5cd$exports, "health", function () { return $c081037d441fc5cd$export$f0784a54fb0af903; });
|
|
26
|
+
const $c081037d441fc5cd$export$f0784a54fb0af903 = (_req, res)=>{
|
|
27
|
+
res.status(200).send({
|
|
28
|
+
status: "ok"
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
var $a46a7fda392c6f12$exports = {};
|
|
34
|
+
|
|
35
|
+
$parcel$export($a46a7fda392c6f12$exports, "metricsFactory", function () { return $a46a7fda392c6f12$export$fc20b1372f40c2c5; });
|
|
36
|
+
const $a46a7fda392c6f12$export$fc20b1372f40c2c5 = ({ registry: registry })=>async (_req, res)=>{
|
|
37
|
+
const collectedMetrics = await registry.metrics();
|
|
38
|
+
res.send(collectedMetrics);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
var $f61917c2527290c5$exports = {};
|
|
43
|
+
|
|
44
|
+
$parcel$export($f61917c2527290c5$exports, "DEFAULT_API_ERROR_MESSAGE", function () { return $f61917c2527290c5$export$c982278a0ddc4dbe; });
|
|
45
|
+
$parcel$export($f61917c2527290c5$exports, "HEALTHY_RPC_SERVICES_ARE_OVER", function () { return $f61917c2527290c5$export$56a189db5508cdcb; });
|
|
46
|
+
$parcel$export($f61917c2527290c5$exports, "UnsupportedChainIdError", function () { return $f61917c2527290c5$export$fc97cac2ba066ec7; });
|
|
47
|
+
$parcel$export($f61917c2527290c5$exports, "UnsupportedHTTPMethodError", function () { return $f61917c2527290c5$export$2dfa2d8949b43fdc; });
|
|
48
|
+
$parcel$export($f61917c2527290c5$exports, "rpcFactory", function () { return $f61917c2527290c5$export$9bfcc39f106ad871; });
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
const $f61917c2527290c5$export$c982278a0ddc4dbe = "Something went wrong. Sorry, try again later :(";
|
|
52
|
+
const $f61917c2527290c5$export$56a189db5508cdcb = "Healthy RPC services are over!";
|
|
53
|
+
class $f61917c2527290c5$export$fc97cac2ba066ec7 extends Error {
|
|
54
|
+
constructor(message){
|
|
55
|
+
super(message || "Unsupported chainId");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
class $f61917c2527290c5$export$2dfa2d8949b43fdc extends Error {
|
|
59
|
+
constructor(message){
|
|
60
|
+
super(message || "Unsupported HTTP method");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const $f61917c2527290c5$export$9bfcc39f106ad871 = ({ metrics: { prefix: prefix , registry: registry } , providers: providers , fetchRPC: fetchRPC , serverLogger: serverLogger , defaultChain: defaultChain , allowedRPCMethods: allowedRPCMethods })=>{
|
|
64
|
+
const rpcRequestBlocked = new (0, $3HXpq$promclient.Counter)({
|
|
65
|
+
name: prefix + "rpc_service_request_blocked",
|
|
66
|
+
help: "RPC service request blocked",
|
|
67
|
+
labelNames: [],
|
|
68
|
+
registers: []
|
|
69
|
+
});
|
|
70
|
+
registry.registerMetric(rpcRequestBlocked);
|
|
71
|
+
return async (req, res)=>{
|
|
72
|
+
try {
|
|
73
|
+
// Accept only POST requests
|
|
74
|
+
if (req.method !== "POST") // We don't care about tracking blocked requests here
|
|
75
|
+
throw new $f61917c2527290c5$export$2dfa2d8949b43fdc();
|
|
76
|
+
const chainId = Number(req.query.chainId || defaultChain);
|
|
77
|
+
// Allow only chainId of specified chains
|
|
78
|
+
if (providers[chainId] == null) // We don't care about tracking blocked requests here
|
|
79
|
+
throw new $f61917c2527290c5$export$fc97cac2ba066ec7();
|
|
80
|
+
// TODO: consider returning array of validators instead of throwing error right away
|
|
81
|
+
// Check if provided methods are allowed
|
|
82
|
+
for (const { method: method } of Array.isArray(req.body) ? req.body : [
|
|
83
|
+
req.body
|
|
84
|
+
]){
|
|
85
|
+
if (typeof method !== "string") throw new Error(`RPC method isn't string`);
|
|
86
|
+
if (!allowedRPCMethods.includes(method)) {
|
|
87
|
+
rpcRequestBlocked.inc();
|
|
88
|
+
throw new Error(`RPC method ${method} isn't allowed`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const requested = await (0, $3HXpq$lidofinancerpc.iterateUrls)(providers[chainId], // TODO: consider adding verification that body is actually matches FetchRpcInitBody
|
|
92
|
+
(url)=>fetchRPC(url, {
|
|
93
|
+
body: req.body
|
|
94
|
+
}, {
|
|
95
|
+
chainId: chainId
|
|
96
|
+
}), serverLogger.error);
|
|
97
|
+
var ref;
|
|
98
|
+
res.setHeader("Content-Type", (ref = requested.headers.get("Content-Type")) !== null && ref !== void 0 ? ref : "application/json");
|
|
99
|
+
res.status(requested.status).send(requested.body);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error instanceof Error) {
|
|
102
|
+
var _message;
|
|
103
|
+
// TODO: check if there are errors duplication with iterateUrls
|
|
104
|
+
serverLogger.error((_message = error.message) !== null && _message !== void 0 ? _message : $f61917c2527290c5$export$c982278a0ddc4dbe);
|
|
105
|
+
var _message1;
|
|
106
|
+
res.status(500).json((_message1 = error.message) !== null && _message1 !== void 0 ? _message1 : $f61917c2527290c5$export$c982278a0ddc4dbe);
|
|
107
|
+
} else res.status(500).json($f61917c2527290c5$export$56a189db5508cdcb);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
$parcel$exportWildcard(module.exports, $c081037d441fc5cd$exports);
|
|
114
|
+
$parcel$exportWildcard(module.exports, $a46a7fda392c6f12$exports);
|
|
115
|
+
$parcel$exportWildcard(module.exports, $f61917c2527290c5$exports);
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","sources":["packages/next/pages/src/index.ts","packages/next/pages/src/health.ts","packages/next/pages/src/metricsFactory.ts","packages/next/pages/src/rpcFactory.ts"],"sourcesContent":["export * from './health'\nexport * from './metricsFactory'\nexport * from './rpcFactory'\n","import { NextApiRequest, NextApiResponse } from 'next'\n\nexport const health = (_req: NextApiRequest, res: NextApiResponse): void => {\n res.status(200).send({ status: 'ok' })\n}\n","import { NextApiRequest, NextApiResponse } from 'next'\nimport { Registry } from 'prom-client'\n\nexport type MetricsFactoryParameters = {\n registry: Registry\n}\n\nexport const metricsFactory =\n ({ registry }: MetricsFactoryParameters) =>\n async (_req: NextApiRequest, res: NextApiResponse) => {\n const collectedMetrics = await registry.metrics()\n res.send(collectedMetrics)\n }\n","import type { NextApiRequest, NextApiResponse } from 'next'\nimport { Counter, Registry } from 'prom-client'\nimport { TrackedFetchRPC } from '@lidofinance/api-rpc'\nimport { ServerLogger } from '@lidofinance/api-logger'\nimport { FetchRpcInitBody, iterateUrls } from '@lidofinance/rpc'\n\nexport type RpcProviders = Record<string | number, [string, ...string[]]>\n\nexport const DEFAULT_API_ERROR_MESSAGE = 'Something went wrong. Sorry, try again later :('\n\nexport const HEALTHY_RPC_SERVICES_ARE_OVER = 'Healthy RPC services are over!'\n\nexport class UnsupportedChainIdError extends Error {\n constructor(message?: string) {\n super(message || 'Unsupported chainId')\n }\n}\n\nexport class UnsupportedHTTPMethodError extends Error {\n constructor(message?: string) {\n super(message || 'Unsupported HTTP method')\n }\n}\n\nexport type RPCFactoryParams = {\n metrics: {\n prefix: string\n registry: Registry\n }\n providers: RpcProviders\n fetchRPC: TrackedFetchRPC\n serverLogger: ServerLogger\n defaultChain: string | number\n // If we don't specify allowed RPC methods, then we can't use\n // fetchRPC with prometheus, otherwise it will blow up, if someone will send arbitrary\n // methods\n allowedRPCMethods: string[]\n}\n\nexport const rpcFactory = ({\n metrics: { prefix, registry },\n providers,\n fetchRPC,\n serverLogger,\n defaultChain,\n allowedRPCMethods,\n}: RPCFactoryParams) => {\n const rpcRequestBlocked = new Counter({\n name: prefix + 'rpc_service_request_blocked',\n help: 'RPC service request blocked',\n labelNames: [],\n registers: [],\n })\n registry.registerMetric(rpcRequestBlocked)\n\n return async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {\n try {\n // Accept only POST requests\n if (req.method !== 'POST') {\n // We don't care about tracking blocked requests here\n throw new UnsupportedHTTPMethodError()\n }\n\n const chainId = Number(req.query.chainId || defaultChain)\n\n // Allow only chainId of specified chains\n if (providers[chainId] == null) {\n // We don't care about tracking blocked requests here\n throw new UnsupportedChainIdError()\n }\n\n // TODO: consider returning array of validators instead of throwing error right away\n // Check if provided methods are allowed\n for (const { method } of Array.isArray(req.body) ? req.body : [req.body]) {\n if (typeof method !== 'string') {\n throw new Error(`RPC method isn't string`)\n }\n if (!allowedRPCMethods.includes(method)) {\n rpcRequestBlocked.inc()\n throw new Error(`RPC method ${method} isn't allowed`)\n }\n }\n\n const requested = await iterateUrls(\n providers[chainId],\n // TODO: consider adding verification that body is actually matches FetchRpcInitBody\n (url) => fetchRPC(url, { body: req.body as FetchRpcInitBody }, { chainId }),\n serverLogger.error,\n )\n\n res.setHeader('Content-Type', requested.headers.get('Content-Type') ?? 'application/json')\n res.status(requested.status).send(requested.body)\n } catch (error) {\n if (error instanceof Error) {\n // TODO: check if there are errors duplication with iterateUrls\n serverLogger.error(error.message ?? DEFAULT_API_ERROR_MESSAGE)\n res.status(500).json(error.message ?? DEFAULT_API_ERROR_MESSAGE)\n } else {\n res.status(500).json(HEALTHY_RPC_SERVICES_ARE_OVER)\n }\n }\n }\n}\n"],"names":[],"version":3,"file":"index.cjs.map"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NextApiRequest, NextApiResponse } from "next";
|
|
2
|
+
import { Registry } from "prom-client";
|
|
3
|
+
import { TrackedFetchRPC } from "@lidofinance/api-rpc";
|
|
4
|
+
import { ServerLogger } from "@lidofinance/api-logger";
|
|
5
|
+
export const health: (_req: NextApiRequest, res: NextApiResponse) => void;
|
|
6
|
+
export type MetricsFactoryParameters = {
|
|
7
|
+
registry: Registry;
|
|
8
|
+
};
|
|
9
|
+
export const metricsFactory: ({ registry }: MetricsFactoryParameters) => (_req: NextApiRequest, res: NextApiResponse) => Promise<void>;
|
|
10
|
+
export type RpcProviders = Record<string | number, [string, ...string[]]>;
|
|
11
|
+
export const DEFAULT_API_ERROR_MESSAGE = "Something went wrong. Sorry, try again later :(";
|
|
12
|
+
export const HEALTHY_RPC_SERVICES_ARE_OVER = "Healthy RPC services are over!";
|
|
13
|
+
export class UnsupportedChainIdError extends Error {
|
|
14
|
+
constructor(message?: string);
|
|
15
|
+
}
|
|
16
|
+
export class UnsupportedHTTPMethodError extends Error {
|
|
17
|
+
constructor(message?: string);
|
|
18
|
+
}
|
|
19
|
+
export type RPCFactoryParams = {
|
|
20
|
+
metrics: {
|
|
21
|
+
prefix: string;
|
|
22
|
+
registry: Registry;
|
|
23
|
+
};
|
|
24
|
+
providers: RpcProviders;
|
|
25
|
+
fetchRPC: TrackedFetchRPC;
|
|
26
|
+
serverLogger: ServerLogger;
|
|
27
|
+
defaultChain: string | number;
|
|
28
|
+
allowedRPCMethods: string[];
|
|
29
|
+
};
|
|
30
|
+
export const rpcFactory: ({ metrics: { prefix, registry }, providers, fetchRPC, serverLogger, defaultChain, allowedRPCMethods, }: RPCFactoryParams) => (req: NextApiRequest, res: NextApiResponse) => Promise<void>;
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";;;;AAEA,OAAO,MAAM,eAAgB,cAAc,OAAO,eAAe,KAAG,IAEnE,CAAA;ACDD,uCAAuC;IACrC,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAA;AAED,OAAO,MAAM,+BACI,wBAAwB,YAC1B,cAAc,OAAO,eAAe,kBAGhD,CAAA;ACNH,2BAA2B,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAA;AAEzE,OAAO,MAAM,6EAA6E,CAAA;AAE1F,OAAO,MAAM,gEAAgE,CAAA;AAE7E,oCAAqC,SAAQ,KAAK;gBACpC,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED,uCAAwC,SAAQ,KAAK;gBACvC,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED,+BAA+B;IAC7B,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,QAAQ,CAAA;KACnB,CAAA;IACD,SAAS,EAAE,YAAY,CAAA;IACvB,QAAQ,EAAE,eAAe,CAAA;IACzB,YAAY,EAAE,YAAY,CAAA;IAC1B,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;IAI7B,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAC5B,CAAA;AAED,OAAO,MAAM,qHAOV,gBAAgB,WASE,cAAc,OAAO,eAAe,KAAG,QAAQ,IAAI,CA+CvE,CAAA","sources":["packages/next/pages/src/src/health.ts","packages/next/pages/src/src/metricsFactory.ts","packages/next/pages/src/src/rpcFactory.ts","packages/next/pages/src/src/index.ts","packages/next/pages/src/index.ts"],"sourcesContent":[null,null,null,null,"export * from './health'\nexport * from './metricsFactory'\nexport * from './rpcFactory'\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {Counter as $bPUfb$Counter} from "prom-client";
|
|
2
|
+
import {iterateUrls as $bPUfb$iterateUrls} from "@lidofinance/rpc";
|
|
3
|
+
|
|
4
|
+
function $parcel$export(e, n, v, s) {
|
|
5
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
6
|
+
}
|
|
7
|
+
var $bb51b4a554c62d89$exports = {};
|
|
8
|
+
|
|
9
|
+
$parcel$export($bb51b4a554c62d89$exports, "health", function () { return $bb51b4a554c62d89$export$f0784a54fb0af903; });
|
|
10
|
+
const $bb51b4a554c62d89$export$f0784a54fb0af903 = (_req, res)=>{
|
|
11
|
+
res.status(200).send({
|
|
12
|
+
status: "ok"
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
var $4241956749180479$exports = {};
|
|
18
|
+
|
|
19
|
+
$parcel$export($4241956749180479$exports, "metricsFactory", function () { return $4241956749180479$export$fc20b1372f40c2c5; });
|
|
20
|
+
const $4241956749180479$export$fc20b1372f40c2c5 = ({ registry: registry })=>async (_req, res)=>{
|
|
21
|
+
const collectedMetrics = await registry.metrics();
|
|
22
|
+
res.send(collectedMetrics);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
var $2f7bb06869d30d12$exports = {};
|
|
27
|
+
|
|
28
|
+
$parcel$export($2f7bb06869d30d12$exports, "DEFAULT_API_ERROR_MESSAGE", function () { return $2f7bb06869d30d12$export$c982278a0ddc4dbe; });
|
|
29
|
+
$parcel$export($2f7bb06869d30d12$exports, "HEALTHY_RPC_SERVICES_ARE_OVER", function () { return $2f7bb06869d30d12$export$56a189db5508cdcb; });
|
|
30
|
+
$parcel$export($2f7bb06869d30d12$exports, "UnsupportedChainIdError", function () { return $2f7bb06869d30d12$export$fc97cac2ba066ec7; });
|
|
31
|
+
$parcel$export($2f7bb06869d30d12$exports, "UnsupportedHTTPMethodError", function () { return $2f7bb06869d30d12$export$2dfa2d8949b43fdc; });
|
|
32
|
+
$parcel$export($2f7bb06869d30d12$exports, "rpcFactory", function () { return $2f7bb06869d30d12$export$9bfcc39f106ad871; });
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const $2f7bb06869d30d12$export$c982278a0ddc4dbe = "Something went wrong. Sorry, try again later :(";
|
|
36
|
+
const $2f7bb06869d30d12$export$56a189db5508cdcb = "Healthy RPC services are over!";
|
|
37
|
+
class $2f7bb06869d30d12$export$fc97cac2ba066ec7 extends Error {
|
|
38
|
+
constructor(message){
|
|
39
|
+
super(message || "Unsupported chainId");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
class $2f7bb06869d30d12$export$2dfa2d8949b43fdc extends Error {
|
|
43
|
+
constructor(message){
|
|
44
|
+
super(message || "Unsupported HTTP method");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const $2f7bb06869d30d12$export$9bfcc39f106ad871 = ({ metrics: { prefix: prefix , registry: registry } , providers: providers , fetchRPC: fetchRPC , serverLogger: serverLogger , defaultChain: defaultChain , allowedRPCMethods: allowedRPCMethods })=>{
|
|
48
|
+
const rpcRequestBlocked = new (0, $bPUfb$Counter)({
|
|
49
|
+
name: prefix + "rpc_service_request_blocked",
|
|
50
|
+
help: "RPC service request blocked",
|
|
51
|
+
labelNames: [],
|
|
52
|
+
registers: []
|
|
53
|
+
});
|
|
54
|
+
registry.registerMetric(rpcRequestBlocked);
|
|
55
|
+
return async (req, res)=>{
|
|
56
|
+
try {
|
|
57
|
+
// Accept only POST requests
|
|
58
|
+
if (req.method !== "POST") // We don't care about tracking blocked requests here
|
|
59
|
+
throw new $2f7bb06869d30d12$export$2dfa2d8949b43fdc();
|
|
60
|
+
const chainId = Number(req.query.chainId || defaultChain);
|
|
61
|
+
// Allow only chainId of specified chains
|
|
62
|
+
if (providers[chainId] == null) // We don't care about tracking blocked requests here
|
|
63
|
+
throw new $2f7bb06869d30d12$export$fc97cac2ba066ec7();
|
|
64
|
+
// TODO: consider returning array of validators instead of throwing error right away
|
|
65
|
+
// Check if provided methods are allowed
|
|
66
|
+
for (const { method: method } of Array.isArray(req.body) ? req.body : [
|
|
67
|
+
req.body
|
|
68
|
+
]){
|
|
69
|
+
if (typeof method !== "string") throw new Error(`RPC method isn't string`);
|
|
70
|
+
if (!allowedRPCMethods.includes(method)) {
|
|
71
|
+
rpcRequestBlocked.inc();
|
|
72
|
+
throw new Error(`RPC method ${method} isn't allowed`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const requested = await (0, $bPUfb$iterateUrls)(providers[chainId], // TODO: consider adding verification that body is actually matches FetchRpcInitBody
|
|
76
|
+
(url)=>fetchRPC(url, {
|
|
77
|
+
body: req.body
|
|
78
|
+
}, {
|
|
79
|
+
chainId: chainId
|
|
80
|
+
}), serverLogger.error);
|
|
81
|
+
var ref;
|
|
82
|
+
res.setHeader("Content-Type", (ref = requested.headers.get("Content-Type")) !== null && ref !== void 0 ? ref : "application/json");
|
|
83
|
+
res.status(requested.status).send(requested.body);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
var _message;
|
|
87
|
+
// TODO: check if there are errors duplication with iterateUrls
|
|
88
|
+
serverLogger.error((_message = error.message) !== null && _message !== void 0 ? _message : $2f7bb06869d30d12$export$c982278a0ddc4dbe);
|
|
89
|
+
var _message1;
|
|
90
|
+
res.status(500).json((_message1 = error.message) !== null && _message1 !== void 0 ? _message1 : $2f7bb06869d30d12$export$c982278a0ddc4dbe);
|
|
91
|
+
} else res.status(500).json($2f7bb06869d30d12$export$56a189db5508cdcb);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
export {$bb51b4a554c62d89$export$f0784a54fb0af903 as health, $4241956749180479$export$fc20b1372f40c2c5 as metricsFactory, $2f7bb06869d30d12$export$c982278a0ddc4dbe as DEFAULT_API_ERROR_MESSAGE, $2f7bb06869d30d12$export$56a189db5508cdcb as HEALTHY_RPC_SERVICES_ARE_OVER, $2f7bb06869d30d12$export$fc97cac2ba066ec7 as UnsupportedChainIdError, $2f7bb06869d30d12$export$2dfa2d8949b43fdc as UnsupportedHTTPMethodError, $2f7bb06869d30d12$export$9bfcc39f106ad871 as rpcFactory};
|
|
100
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","sources":["packages/next/pages/src/index.ts","packages/next/pages/src/health.ts","packages/next/pages/src/metricsFactory.ts","packages/next/pages/src/rpcFactory.ts"],"sourcesContent":["export * from './health'\nexport * from './metricsFactory'\nexport * from './rpcFactory'\n","import { NextApiRequest, NextApiResponse } from 'next'\n\nexport const health = (_req: NextApiRequest, res: NextApiResponse): void => {\n res.status(200).send({ status: 'ok' })\n}\n","import { NextApiRequest, NextApiResponse } from 'next'\nimport { Registry } from 'prom-client'\n\nexport type MetricsFactoryParameters = {\n registry: Registry\n}\n\nexport const metricsFactory =\n ({ registry }: MetricsFactoryParameters) =>\n async (_req: NextApiRequest, res: NextApiResponse) => {\n const collectedMetrics = await registry.metrics()\n res.send(collectedMetrics)\n }\n","import type { NextApiRequest, NextApiResponse } from 'next'\nimport { Counter, Registry } from 'prom-client'\nimport { TrackedFetchRPC } from '@lidofinance/api-rpc'\nimport { ServerLogger } from '@lidofinance/api-logger'\nimport { FetchRpcInitBody, iterateUrls } from '@lidofinance/rpc'\n\nexport type RpcProviders = Record<string | number, [string, ...string[]]>\n\nexport const DEFAULT_API_ERROR_MESSAGE = 'Something went wrong. Sorry, try again later :('\n\nexport const HEALTHY_RPC_SERVICES_ARE_OVER = 'Healthy RPC services are over!'\n\nexport class UnsupportedChainIdError extends Error {\n constructor(message?: string) {\n super(message || 'Unsupported chainId')\n }\n}\n\nexport class UnsupportedHTTPMethodError extends Error {\n constructor(message?: string) {\n super(message || 'Unsupported HTTP method')\n }\n}\n\nexport type RPCFactoryParams = {\n metrics: {\n prefix: string\n registry: Registry\n }\n providers: RpcProviders\n fetchRPC: TrackedFetchRPC\n serverLogger: ServerLogger\n defaultChain: string | number\n // If we don't specify allowed RPC methods, then we can't use\n // fetchRPC with prometheus, otherwise it will blow up, if someone will send arbitrary\n // methods\n allowedRPCMethods: string[]\n}\n\nexport const rpcFactory = ({\n metrics: { prefix, registry },\n providers,\n fetchRPC,\n serverLogger,\n defaultChain,\n allowedRPCMethods,\n}: RPCFactoryParams) => {\n const rpcRequestBlocked = new Counter({\n name: prefix + 'rpc_service_request_blocked',\n help: 'RPC service request blocked',\n labelNames: [],\n registers: [],\n })\n registry.registerMetric(rpcRequestBlocked)\n\n return async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {\n try {\n // Accept only POST requests\n if (req.method !== 'POST') {\n // We don't care about tracking blocked requests here\n throw new UnsupportedHTTPMethodError()\n }\n\n const chainId = Number(req.query.chainId || defaultChain)\n\n // Allow only chainId of specified chains\n if (providers[chainId] == null) {\n // We don't care about tracking blocked requests here\n throw new UnsupportedChainIdError()\n }\n\n // TODO: consider returning array of validators instead of throwing error right away\n // Check if provided methods are allowed\n for (const { method } of Array.isArray(req.body) ? req.body : [req.body]) {\n if (typeof method !== 'string') {\n throw new Error(`RPC method isn't string`)\n }\n if (!allowedRPCMethods.includes(method)) {\n rpcRequestBlocked.inc()\n throw new Error(`RPC method ${method} isn't allowed`)\n }\n }\n\n const requested = await iterateUrls(\n providers[chainId],\n // TODO: consider adding verification that body is actually matches FetchRpcInitBody\n (url) => fetchRPC(url, { body: req.body as FetchRpcInitBody }, { chainId }),\n serverLogger.error,\n )\n\n res.setHeader('Content-Type', requested.headers.get('Content-Type') ?? 'application/json')\n res.status(requested.status).send(requested.body)\n } catch (error) {\n if (error instanceof Error) {\n // TODO: check if there are errors duplication with iterateUrls\n serverLogger.error(error.message ?? DEFAULT_API_ERROR_MESSAGE)\n res.status(500).json(error.message ?? DEFAULT_API_ERROR_MESSAGE)\n } else {\n res.status(500).json(HEALTHY_RPC_SERVICES_ARE_OVER)\n }\n }\n }\n}\n"],"names":[],"version":3,"file":"index.mjs.map"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lidofinance/next-pages",
|
|
3
|
+
"description": "Common next pages",
|
|
4
|
+
"repository": "git@github.com:lidofinance/lido-ui-blocks.git",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"version": "0.0.3",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">= 16",
|
|
12
|
+
"browsers": "> 0.5%, last 2 versions, not dead"
|
|
13
|
+
},
|
|
14
|
+
"source": "./src/index.ts",
|
|
15
|
+
"main": "dist/index.cjs",
|
|
16
|
+
"module": "dist/index.mjs",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "parcel build",
|
|
20
|
+
"format": "prettier --check src",
|
|
21
|
+
"format:fix": "yarn format --write",
|
|
22
|
+
"types": "tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@lidofinance/api-logger": "0.0.3",
|
|
26
|
+
"@lidofinance/api-rpc": "0.0.3",
|
|
27
|
+
"@lidofinance/rpc": "0.0.3",
|
|
28
|
+
"next": "^12.2.0",
|
|
29
|
+
"prom-client": "^14.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@lidofinance/config-prettier": "0.0.1",
|
|
33
|
+
"next": "^12.2.0",
|
|
34
|
+
"prom-client": "^14.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|