Skip to content

Commit

Permalink
Merge pull request #13 from whats-good/kerem/config-2
Browse files Browse the repository at this point in the history
Kerem/config 2
  • Loading branch information
mechanical-turk authored Nov 29, 2023
2 parents f656912 + 6f49cd0 commit 5fe39e3
Show file tree
Hide file tree
Showing 21 changed files with 477 additions and 89 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-bananas-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatsgood/nexus": patch
---

requiring provider configs
5 changes: 5 additions & 0 deletions .changeset/dull-clocks-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatsgood/nexus": minor
---

chains need to be explicitly configured via config now
5 changes: 5 additions & 0 deletions .changeset/great-maps-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatsgood/nexus": patch
---

Updated registry override behavior: additional chain support statements will override previous ones for the same chain id
5 changes: 5 additions & 0 deletions .changeset/loud-insects-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatsgood/nexus": minor
---

Global singleton registry exported now. Clients can now extend the registry to change chain, network and provider behavior
3 changes: 3 additions & 0 deletions examples/cloudflare-worker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { NexusServer } from "@whatsgood/nexus";
// TODO: add onboarding & UX. (setup admin access, login, etc)
// TODO: add tests for the worker

// TODO: add documentation for registry extensions

type Env = Record<string, string>;

const server = NexusServer.create<Env>({
env: (ctx) => ctx,
providers: ["alchemy"],
chains: [84531],
});

export default { fetch: server.fetch };
1 change: 1 addition & 0 deletions examples/nodejs-standalone-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createServer } from "node:http";

const server = NexusServer.create({
providers: ["base"],
chains: [84531],
});

createServer(server).listen(4005, () => {
Expand Down
37 changes: 5 additions & 32 deletions packages/nexus/src/chain/chain.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,12 @@
import type { Registry } from "@src/registry";

export class Network {
private readonly chains = new Map<string, Chain>();

private constructor(public readonly name: string) {}

public addChain(chain: Chain) {
if (this.chains.has(chain.name)) {
throw new Error(`Chain ${chain.name} already exists`);
}

this.chains.set(chain.name, chain);
}

public getChain(name: string): Chain | undefined {
return this.chains.get(name);
}

public static init(
registry: Registry,
name: string,
aliases?: string[]
): Network {
const existingNetwork = registry.getNetwork(name);
const network = existingNetwork || new Network(name);

registry.registerNetwork(network, aliases);

return network;
}
}
import type { Config } from "@src/config";
import type { Network } from "./network";

export interface ChainStatus {
chainId: number;
chainName: string;
networkName: string;
isEnabled: boolean;
// TODO: add isDeprecated
// isDeprecated: boolean;
}
Expand All @@ -46,11 +18,12 @@ export class Chain {
public readonly name: string
) {}

public get status(): ChainStatus {
public getStatus(config: Config): ChainStatus {
return {
chainName: this.name,
chainId: this.chainId,
networkName: this.network.name,
isEnabled: !!config.chains[this.chainId]?.enabled,
// isDeprecated: this.isDeprecated,
};
}
Expand Down
1 change: 1 addition & 0 deletions packages/nexus/src/chain/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./chain";
export * from "./network";
33 changes: 33 additions & 0 deletions packages/nexus/src/chain/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Registry } from "@src/registry";
import type { Chain } from "./chain";

export class Network {
private readonly chains = new Map<string, Chain>();

private constructor(public readonly name: string) {}

public addChain(chain: Chain) {
if (this.chains.has(chain.name)) {
throw new Error(`Chain ${chain.name} already exists`);
}

this.chains.set(chain.name, chain);
}

public getChain(name: string): Chain | undefined {
return this.chains.get(name);
}

public static init(
registry: Registry,
name: string,
aliases?: string[]
): Network {
const existingNetwork = registry.getNetwork(name);
const network = existingNetwork || new Network(name);

registry.registerNetwork(network, aliases);

return network;
}
}
66 changes: 52 additions & 14 deletions packages/nexus/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from "zod";
import { defaultRegistry } from "./registry/default-registry";
import { globalSingletonRegistry } from "./registry/global-singleton-registry";
import type { Registry } from "./registry";
import { toUpperSnakeCase } from "./utils";

const RpxRelayRecoveryModeSchema = z.enum(["none", "cycle"]);
// none -> don't try to recover and fail immediately
Expand All @@ -12,14 +13,27 @@ type RpcRelayRecoveryMode = z.infer<typeof RpxRelayRecoveryModeSchema>;

interface ProviderConfig {
key?: string;
disabled?: boolean;
enabled: boolean;
}

interface ProviderConfigWithName extends ProviderConfig {
name: string;
type ProviderConfigParam =
| string
| {
name: string;
key?: string;
enabled?: boolean;
};

interface ChainConfig {
enabled: boolean;
}

type ProviderConfigParam = string | ProviderConfigWithName;
type ChainConfigParam =
| number
| {
chainId: number;
enabled?: boolean;
};

type Env = Partial<Record<string, string>>;

Expand All @@ -32,6 +46,8 @@ export class Config {

public providers: Partial<Record<string, ProviderConfig>> = {};

public chains: Partial<Record<number, ChainConfig>> = {};

// all client-side access to the rpc-proxy should include this key.
public globalAccessKey?: string;

Expand All @@ -41,36 +57,58 @@ export class Config {

public readonly registry: Registry;

public readonly env: Env;

constructor(params: {
env?: Env;
providers?: ProviderConfigParam[];
providers: [ProviderConfigParam, ...ProviderConfigParam[]];
chains: [ChainConfigParam, ...ChainConfigParam[]];
globalAccessKey?: string;
recoveryMode?: RpcRelayRecoveryMode;
registry?: Registry;
}) {
const envRaw: Env = params.env || process.env;

// only allow keys that start with NEXUS_ to be used
this.env = Object.fromEntries(
// TODO: is this necessary now that we're not exporting the env object?
const env = Object.fromEntries(
Object.entries(envRaw).filter(([key]) => key.startsWith("NEXUS_"))
);

params.providers?.forEach((provider) => {
params.providers.forEach((provider) => {
if (typeof provider === "string") {
this.providers[provider] = {
disabled: false,
enabled: true,
};
} else {
// TODO: scan all NEXUS_PROVIDER_*_KEY env vars and warn if there are any unused ones
// or alternatively automatically enable the provider if there is a key for it
this.providers[provider.name] = {
enabled: provider.enabled ?? true,
key: provider.key || env[this.getEnvSecretKeyName(provider.name)],
};
}
});

params.chains.forEach((chain) => {
if (typeof chain === "number") {
this.chains[chain] = {
enabled: true,
};
} else {
this.providers[provider.name] = provider;
this.chains[chain.chainId] = {
enabled: chain.enabled ?? true,
};
}
});

this.globalAccessKey =
params.globalAccessKey || this.env.NEXUS_GLOBAL_ACCESS_KEY;
params.globalAccessKey || env.NEXUS_GLOBAL_ACCESS_KEY;
this.recoveryMode = params.recoveryMode ?? "cycle";

this.registry = params.registry || defaultRegistry;
this.registry = params.registry || globalSingletonRegistry;
}

private getEnvSecretKeyName(name: string): string {
// TODO: update env vars and documentation to reflect this change
return `NEXUS_PROVIDER_${toUpperSnakeCase(name)}_KEY`;
}
}
1 change: 1 addition & 0 deletions packages/nexus/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./nexus";
export * from "./config";
export * from "./registry";
2 changes: 1 addition & 1 deletion packages/nexus/src/nexus/nexus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class NexusServer<TServerContext = EmptyServerContext>
typeof value === "function" ? value(serverContext, request) : value,
])
);
const config = new Config(configParams);
const config = new Config(configParams as ConfigConstructorParams);

return this.requestHandler.handle(config, request);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Registry } from "./registry";

export const defaultRegistry = new Registry();
export const globalSingletonRegistry = new Registry();

defaultRegistry
globalSingletonRegistry
.network("ethereum", ["eth"])
.chain(1, "mainnet")
.chain(4, "rinkeby")
Expand All @@ -19,7 +19,7 @@ defaultRegistry
.network("local", ["hardhat", "foundry"])
.chain(31337, "local");

defaultRegistry
globalSingletonRegistry
.provider("alchemy")
.support(1, {
baseURL: "https://eth-mainnet.alchemyapi.io/v2",
Expand Down
2 changes: 1 addition & 1 deletion packages/nexus/src/registry/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from "./registry";
export * from "./default-registry";
export * from "./global-singleton-registry";
Loading

0 comments on commit 5fe39e3

Please sign in to comment.