Skip to content

Commit

Permalink
Provide a type safe config with sane defaults on type level
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastinez committed Aug 29, 2024
1 parent 6c00951 commit 8c9ee12
Show file tree
Hide file tree
Showing 20 changed files with 256 additions and 153 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,15 @@ There's two ways to configure the UI:

**Environment variables**

1. Check [custom-environment-variables.json][env] for all available environment
variables.
2. Set the desired environment variables when building the UI.
The following environment variables are available:

- PUBLIC_EXPLORER_URL="https://app.radicle.xyz/nodes/$host/$rid$path"
- SUPPORTED_API_VERSION: "6.0.0"
- DEFAULT_HTTPD_API_PORT: 443
- DEFAULT_HTTPD_SCHEME: "https"
- HISTORY_COMMITS_PER_PAGE: 30
- SUPPORT_WEBSITE: "https://radicle.xyz"
- PREFERRED_SEEDS: '[{ "hostname": `hostname`, "port": `port number`, "scheme": `url scheme` }]'

> For advanced configuration options, have a look at the [`node-config`][nco]
> package.
Expand Down
16 changes: 0 additions & 16 deletions config/custom-environment-variables.json

This file was deleted.

14 changes: 5 additions & 9 deletions config/default.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
{
"nodes": {
"fallbackPublicExplorer": "https://app.radicle.xyz/nodes/$host/$rid$path",
"apiVersion": "5.0.0",
"defaultHttpdPort": 443,
"defaultHttpdScheme": "https"
},
"source": {
"commitsPerPage": 30
},
"publicExplorerUrl": "https://app.radicle.xyz/nodes/$host/$rid$path",
"supportedApiVersion": "6.0.0",
"defaultHttpdApiPort": 443,
"defaultHttpdScheme": "https",
"historyCommitsPerPage": 30,
"supportWebsite": "https://radicle.zulipchat.com",
"preferredSeeds": [
{
Expand Down
6 changes: 2 additions & 4 deletions config/test.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"nodes": {
"defaultHttpdPort": 8081,
"defaultHttpdScheme": "http"
},
"defaultHttpdApiPort": 8081,
"defaultHttpdScheme": "http",
"preferredSeeds": [
{
"hostname": "127.0.0.1",
Expand Down
12 changes: 6 additions & 6 deletions http-client/lib/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ export class ResponseParseError extends Error {
let description: string;
if (
apiVersion === undefined ||
compare(apiVersion, config.nodes.apiVersion, "<")
compare(apiVersion, config.supportedApiVersion, "<")
) {
description = `The node you are fetching from seems to be outdated, make sure the httpd API version is at least ${config.nodes.apiVersion} currently ${apiVersion ?? "unknown"}.`;
description = `The node you are fetching from seems to be outdated, make sure the httpd API version is at least ${config.supportedApiVersion} currently ${apiVersion ?? "unknown"}.`;
} else if (
config.nodes.apiVersion === undefined ||
compare(apiVersion, config.nodes.apiVersion, ">")
config.supportedApiVersion === undefined ||
compare(apiVersion, config.supportedApiVersion, ">")
) {
description = `The web client you are using is outdated, make sure it supports at least ${apiVersion} to interact with this node currently ${config.nodes.apiVersion ?? "unknown"}.`;
description = `The web client you are using is outdated, make sure it supports at least ${apiVersion} to interact with this node currently ${config.supportedApiVersion ?? "unknown"}.`;
} else {
description =
"This is usually due to a version mismatch between the seed and the web interface.";
Expand Down Expand Up @@ -122,7 +122,7 @@ export class Fetcher {
): Promise<TypeOf<T>> {
const response = await this.fetch({
...params,
query: { ...params.query, v: config.nodes.apiVersion },
query: { ...params.query, v: config.supportedApiVersion },
});

if (!response.ok) {
Expand Down
15 changes: 15 additions & 0 deletions http-client/lib/shared.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { z } from "zod";

import { array, boolean, literal, number, object, string, union } from "zod";
import defaults from "../../config/default.json" with { type: "json" };

export const scopeSchema = union([literal("followed"), literal("all")]);

Expand Down Expand Up @@ -123,3 +124,17 @@ export const authorSchema = object({
id: string(),
alias: string().optional(),
});

export type WebConfig = z.infer<typeof webConfigSchema>;

export const webConfigSchema = object({
publicExplorerUrl: string().default(defaults.publicExplorerUrl),
supportedApiVersion: string().default(defaults.supportedApiVersion),
defaultHttpdApiPort: number().default(defaults.defaultHttpdApiPort),
defaultHttpdScheme: string().default(defaults.defaultHttpdScheme),
historyCommitsPerPage: number().default(defaults.historyCommitsPerPage),
supportWebsite: string().default(defaults.supportWebsite),
preferredSeeds: array(
object({ hostname: string(), port: number(), scheme: string() }),
).default(defaults.preferredSeeds),
});
50 changes: 31 additions & 19 deletions http-client/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import nodeConfig from "config";
import path from "node:path";
import virtual from "vite-plugin-virtual";
import { configureAdapters } from "../vite.config";
import { defineConfig } from "vite";
import { loadConfig } from "zod-config";
import { webConfigSchema } from "./lib/shared";

export default defineConfig({
plugins: [
virtual({
"virtual:config": nodeConfig.util.toObject(),
}),
],
test: {
environment: "node",
include: ["http-client/tests/*.test.ts"],
reporters: "verbose",
globalSetup: "./tests/support/globalSetup",
},
resolve: {
alias: {
"@tests": path.resolve("./tests"),
"@app": path.resolve("./src"),
"@http-client": path.resolve("./http-client"),
export default defineConfig(async () => {
const adapters = await configureAdapters();
const config = await loadConfig({
schema: webConfigSchema,
adapters,
logger: {
warn: message => console.warn(`WARN [config]: ${message}`),
},
},
});
return {
plugins: [
virtual({
"virtual:config": config,
}),
],
test: {
environment: "node",
include: ["http-client/tests/*.test.ts"],
reporters: "verbose",
globalSetup: "./tests/support/globalSetup",
},
resolve: {
alias: {
"@tests": path.resolve("./tests"),
"@app": path.resolve("./src"),
"@http-client": path.resolve("./http-client"),
},
},
};
});
17 changes: 2 additions & 15 deletions module.d.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
declare module "virtual:*" {
const config: {
nodes: {
apiVersion: string;
fallbackPublicExplorer: string;
defaultHttpdPort: number;
defaultLocalHttpdPort: number;
defaultHttpdScheme: string;
};
source: {
commitsPerPage: number;
};
reactions: string[];
supportWebsite: string;
preferredSeeds: BaseUrl[];
};
import type { WebConfig } from "@http-client/lib/shared";
const config: WebConfig;

export default config;
}
48 changes: 40 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"@playwright/test": "^1.46.1",
"@sveltejs/vite-plugin-svelte": "^3.1.2",
"@tsconfig/svelte": "^5.0.4",
"@types/config": "^3.3.4",
"@types/dompurify": "^3.0.5",
"@types/katex": "^0.16.7",
"@types/lodash": "^4.17.7",
Expand Down Expand Up @@ -55,6 +54,7 @@
"wait-on": "^8.0.0"
},
"dependencies": {
"@absxn/process-env-parser": "^1.1.1",
"@efstajas/svelte-stored-writable": "^0.2.0",
"@radicle/gray-matter": "4.1.0",
"@wooorm/starry-night": "^3.4.0",
Expand All @@ -78,6 +78,10 @@
"plausible-tracker": "^0.3.9",
"svelte": "^4.2.19",
"twemoji": "^14.0.2",
"zod": "^3.23.8"
"zod": "^3.23.8",
"zod-config": "^0.0.5"
},
"peerDependencies": {
"dotenv": "^16.4.5"
}
}
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const config: PlaywrightTestConfig = {
command: "npm run start -- --strictPort --port 3002",
port: 3002,
// eslint-disable-next-line @typescript-eslint/naming-convention
env: { COMMITS_PER_PAGE: "4" },
env: { HISTORY_COMMITS_PER_PAGE: "4" },
},
],
};
Expand Down
14 changes: 7 additions & 7 deletions src/lib/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,15 @@ export async function replace(newRoute: Route): Promise<void> {
function extractBaseUrl(hostAndPort: string): BaseUrl {
if (
hostAndPort === "radicle.local" ||
hostAndPort === `radicle.local:${config.nodes.defaultHttpdPort}` ||
hostAndPort === `radicle.local:${config.defaultHttpdApiPort}` ||
hostAndPort === "0.0.0.0" ||
hostAndPort === `0.0.0.0:${config.nodes.defaultHttpdPort}` ||
hostAndPort === `0.0.0.0:${config.defaultHttpdApiPort}` ||
hostAndPort === "127.0.0.1" ||
hostAndPort === `127.0.0.1:${config.nodes.defaultHttpdPort}`
hostAndPort === `127.0.0.1:${config.defaultHttpdApiPort}`
) {
return {
hostname: "127.0.0.1",
port: config.nodes.defaultHttpdPort,
port: config.defaultHttpdApiPort,
scheme: "http",
};
} else if (hostAndPort.includes(":")) {
Expand All @@ -167,13 +167,13 @@ function extractBaseUrl(hostAndPort: string): BaseUrl {
scheme:
utils.isLocal(hostname) || utils.isOnion(hostname)
? "http"
: config.nodes.defaultHttpdScheme,
: config.defaultHttpdScheme,
};
} else {
return {
hostname: hostAndPort,
port: config.nodes.defaultHttpdPort,
scheme: config.nodes.defaultHttpdScheme,
port: config.defaultHttpdApiPort,
scheme: config.defaultHttpdScheme,
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/views/nodes/SeedSelector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
loading = true;
const seed = {
hostname: seedAddressInput.trim(),
port: config.nodes.defaultHttpdPort,
scheme: config.nodes.defaultHttpdScheme,
port: config.defaultHttpdApiPort,
scheme: config.defaultHttpdScheme,
};
validationMessage = await validateInput(seed);
if (validationMessage === undefined) {
Expand Down
4 changes: 2 additions & 2 deletions src/views/nodes/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export interface NodesLoadedRoute {
}

export function nodePath(baseUrl: BaseUrl) {
const port = baseUrl.port ?? config.nodes.defaultHttpdPort;
const port = baseUrl.port ?? config.defaultHttpdApiPort;

if (port === config.nodes.defaultHttpdPort) {
if (port === config.defaultHttpdApiPort) {
return `/nodes/${baseUrl.hostname}`;
} else {
return `/nodes/${baseUrl.hostname}:${port}`;
Expand Down
Loading

0 comments on commit 8c9ee12

Please sign in to comment.