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 12, 2024
1 parent 165c793 commit c5185fd
Show file tree
Hide file tree
Showing 19 changed files with 269 additions and 141 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
PUBLIC_EXPLORER_URL="https://app.radicle.xyz/nodes/$host/$rid$path"
SUPPORTED_API_VERSION: "4.0.0"
DEFAULT_HTTPD_API_PORT: 443
DEFAULT_HTTPD_SCHEME: "https"
HISTORY_COMMITS_PER_PAGE: 30
SUPPORT_WEBSITE: "https://radicle.xyz"
PREFERRED_SEEDS: '[{ "hostname": "seed.radicle.garden", "port": 443, "scheme": "https" }]'
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": "4.0.0",
"defaultHttpdPort": 443,
"defaultHttpdScheme": "https"
},
"source": {
"commitsPerPage": 30
},
"publicExplorerUrl": "https://app.radicle.xyz/nodes/$host/$rid$path",
"supportedApiVersion": "4.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
32 changes: 32 additions & 0 deletions http-client/lib/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,35 @@ export const authorSchema = object({
id: string(),
alias: string().optional(),
});

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

export const webConfigSchema = object({
publicExplorerUrl: string().default(
"https://app.radicle.xyz/nodes/$host/$rid$path",
),
supportedApiVersion: string().default("4.0.0"),
defaultHttpdApiPort: number().default(443),
defaultHttpdScheme: string().default("https"),
historyCommitsPerPage: number().default(30),
supportWebsite: string().default("https://radicle.zulipchat.com"),
preferredSeeds: array(
object({ hostname: string(), port: number(), scheme: string() }),
).default([
{
hostname: "ash.radicle.garden",
port: 443,
scheme: "https",
},
{
hostname: "seed.radicle.xyz",
port: 443,
scheme: "https",
},
{
hostname: "seed.radicle.garden",
port: 443,
scheme: "https",
},
]),
});
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;
}
41 changes: 40 additions & 1 deletion package-lock.json

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

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"wait-on": "^7.2.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 @@ -77,6 +78,10 @@
"plausible-tracker": "^0.3.9",
"svelte": "^4.2.18",
"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
4 changes: 2 additions & 2 deletions src/views/projects/Header/CloneButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
$: radCloneUrl = `rad clone ${id}`;
$: portFragment =
baseUrl.scheme === config.nodes.defaultHttpdScheme &&
baseUrl.port === config.nodes.defaultHttpdPort
baseUrl.scheme === config.defaultHttpdScheme &&
baseUrl.port === config.defaultHttpdApiPort
? ""
: `:${baseUrl.port}`;
$: gitCloneUrl = `git clone ${baseUrl.scheme}://${
Expand Down
2 changes: 1 addition & 1 deletion src/views/projects/History.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
const response = await api.project.getAllCommits(project.id, {
parent: allCommitHeaders[0].id,
page,
perPage: config.source.commitsPerPage,
perPage: config.historyCommitsPerPage,
});
allCommitHeaders = [...allCommitHeaders, ...response];
} catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion src/views/projects/Share.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
}, 1000);
async function copy() {
const text = new URL(config.nodes.fallbackPublicExplorer).origin.concat(
const text = new URL(config.publicExplorerUrl).origin.concat(
window.location.pathname,
);
await toClipboard(text);
Expand Down
Loading

0 comments on commit c5185fd

Please sign in to comment.