diff --git a/README.md b/README.md index 60fe599..6c691b8 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,35 @@ +# BGD RPC ENV + +When working on multichain projects it is a tedious task to setup private RPCs and managing them in your local environment or github actions. +This repository is a suite of tools to streamline the handling of RPC environment variables, by automating the creation and injection of environment variables following a common [naming scheme](./src/lib.test.ts). + ## NodeJS: `@bgd-labs/rpc-env` [![NPM Version](https://img.shields.io/npm/v/%40bgd-labs%2Frpc-env)](https://www.npmjs.com/package/@bgd-labs/rpc-env) -### Usage +### Usage as a library ```typescript import { getRPCUrl, ChainId } from "@bgd-labs/rpc-env"; -const url = getRPCUrl(ChainId.mainnet, "[YOUR_ALCHEMY_KEY]"); +// will fetch the rpc based on a opinionated priorization and does not error if no rpc is found +// 1. checks if `RPC_MAINNET` is set, otherwise +// 2. checks if alchemy key was provided & if alchemy supports the network, otherwise +// 3. checks if a public rpc is configured +const url = getRPCUrl(ChainId.mainnet, { alchemyKey?: "[YOUR_ALCHEMY_KEY]" }); + +// alternatively you can use the explicit getters, which will throw if no rpc is found +const url = getExplicitRPC(ChainId.mainnet); +const url = getAlchemyRPC(ChainId.mainnet, alchemyKey); +const url = getPublicRpc(ChainId.mainnet); +``` + +### Usage as cli + +The cli will emit explicit rps and a foundry.toml configuration for each network. + +``` +export ALCHEMY_API_KEY=<> && npx @bgd-labs/rpc-env ``` ## Action: `action-rpc-env` diff --git a/dist/action.js b/dist/action.js index c2353d7..d807671 100644 --- a/dist/action.js +++ b/dist/action.js @@ -23673,7 +23673,7 @@ var ChainId = { linea: linea.id }; -// src/public.ts +// src/publicRPCs.ts var publicRPCs = { [ChainId.mainnet]: "https://eth.llamarpc.com", [ChainId.polygon]: "https://polygon.llamarpc.com", diff --git a/dist/action.mjs b/dist/action.mjs index 4bc2ca7..0f8b62d 100644 --- a/dist/action.mjs +++ b/dist/action.mjs @@ -23671,7 +23671,7 @@ var ChainId = { linea: linea.id }; -// src/public.ts +// src/publicRPCs.ts var publicRPCs = { [ChainId.mainnet]: "https://eth.llamarpc.com", [ChainId.polygon]: "https://polygon.llamarpc.com", diff --git a/lefthook.yml b/lefthook.yml index 7dd037f..6e3a304 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -3,7 +3,7 @@ pre-commit: commands: build: glob: "*.{ts,package-lock.json}" - run: node src/prepare.mjs > src/alchemyIds.ts && git add src/alchemyIds.ts && npm run build && git add dist/* + run: node src/prepare.mjs > src/alchemyIds.ts && git add src/alchemyIds.ts && npm run build && git add . # yes we're actually committing the build output, because github actions works like that stage_fixed: true format: diff --git a/package-lock.json b/package-lock.json index 629dcfb..fb2699d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,14 @@ "name": "@bgd-labs/rpc-env", "version": "2.1.2", "license": "MIT", + "bin": { + "rpc-env": "dist/cli.js" + }, "devDependencies": { "@actions/core": "^1.11.1", "@biomejs/biome": "^1.9.4", "@types/node": "^22.8.6", + "dotenv": "^16.4.5", "lefthook": "^1.8.2", "tsup": "^8.3.5", "typescript": "^5.6.3", @@ -1386,6 +1390,18 @@ "node": ">=6" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", diff --git a/package.json b/package.json index bdbb105..36e93b8 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "publishConfig": { "access": "public" }, + "sideEffects": false, "scripts": { "build": "tsup", "test": "vitest", @@ -38,7 +39,8 @@ "tsup": "^8.3.5", "typescript": "^5.6.3", "viem": "^2.21.48", - "vitest": "^2.1.4" + "vitest": "^2.1.4", + "dotenv": "^16.4.5" }, "tsup": { "entry": ["src/action.ts", "src/lib.ts", "src/cli.ts"], diff --git a/src/cli.ts b/src/cli.ts index 2d8df6e..5b1ea5c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node +import "dotenv/config"; import { ChainId, getNetworkEnv, getRPCUrl } from "./lib"; (function print() { @@ -6,7 +7,11 @@ import { ChainId, getNetworkEnv, getRPCUrl } from "./lib"; let toml = ""; Object.entries(ChainId).map(([key, chainId]) => { const networkEnv = getNetworkEnv(chainId); - const rpc = getRPCUrl(chainId, { alchemyKey: process.env.ALCHEMY_API_KEY }); + const rpc = getRPCUrl(chainId, { + alchemyKey: process.env.ALCHEMY_API_KEY, + quicknodeToken: process.env.QUICKNODE_TOKEN, + quicknodeEndpointName: process.env.QUICKNODE_ENDPOINT_NAME, + }); env += `${networkEnv}=${rpc || ""}\n`; toml += `${key}="\${${networkEnv}}"\n`; }); diff --git a/src/lib.ts b/src/lib.ts index 92750e4..39aaef1 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -1,6 +1,6 @@ import { networkMap } from "./alchemyIds"; import { ChainId, ChainList } from "./chainIds"; -import { publicRPCs } from "./public"; +import { publicRPCs } from "./publicRPCs"; import { quicknodeNetworkMap } from "./quicknodeIds"; type SupportedChainIds = (typeof ChainId)[keyof typeof ChainId]; @@ -141,4 +141,4 @@ export const getRPCUrl = ( } catch (e) {} }; -export { ChainId, ChainList }; +export { ChainId, ChainList, type SupportedChainIds }; diff --git a/src/prepare.mjs b/src/prepare.mjs index 3da7d29..de77032 100644 --- a/src/prepare.mjs +++ b/src/prepare.mjs @@ -444,7 +444,7 @@ const quickNodeApiResponse = { }; const quicknodeNetworkMap = quickNodeApiResponse.data.reduce((acc, network) => { - network.networks.forEach((nw) => { + network.networks.map((nw) => { if (nw.chain_id) { acc[nw.chain_id] = nw.slug; } diff --git a/src/public.ts b/src/publicRPCs.ts similarity index 80% rename from src/public.ts rename to src/publicRPCs.ts index 41804bd..894c670 100644 --- a/src/public.ts +++ b/src/publicRPCs.ts @@ -1,5 +1,9 @@ import { ChainId } from "./chainIds"; +/** + * A manually maintained list of public rpcs. + * These should only be used for prs coming from forks, which should not access secrets like the alchemy api key. + */ export const publicRPCs = { [ChainId.mainnet]: "https://eth.llamarpc.com", [ChainId.polygon]: "https://polygon.llamarpc.com",