Skip to content

Commit

Permalink
feat(web): get Env from API endpoint (#678)
Browse files Browse the repository at this point in the history
* feat(web): fetch env from API endpoint in client side

* feat(web): adapt server side sentry env config for any environment

* fix(web): limit to '1' env query

* refactor(web): reset 'server' and 'edge' sentry config

* refactor(web): move env endpoint from API package to Next API

* feat: remove default env value

* feat(web): use Next env api endpoint to init sentry in clientside

* chore(web): remove unnecessary export

* refactor(web): remove unnecessary env fetch utils file

* feat(web): validate env API request json parsing

* chore(web): update changeset

* refactor(web): infer clien env zod schema in Env provider

* feat(web): update client vars schema

* feat(web): update client env var references after name refactor

* style(web): type provider env vars

* chore: update `pnpm-lock`

* chore(web): remove `NEXT` prefix env vars

* chore(web): parse env vars fetched from api

* chore(web): use type casting instead of Zod schema parsing on client as env vars are already parsed on the server

* chore(web): fix blobscan version info

---------

Co-authored-by: PJColombo <paulo.colombo@pm.me>
  • Loading branch information
xFJA and PJColombo authored Feb 13, 2025
1 parent d51d2bb commit 22ae59a
Show file tree
Hide file tree
Showing 28 changed files with 516 additions and 389 deletions.
5 changes: 5 additions & 0 deletions .changeset/sweet-beans-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/web": minor
---

Get environment variables from API endpoint.
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ NEXTAUTH_URL=http://localhost:3000
# You can generate the secret via 'openssl rand -base64 32' on Unix
# @see https://next-auth.js.org/configuration/options#secret
SECRET_KEY=supersecret
NEXT_PUBLIC_NETWORK_NAME=mainnet
PUBLIC_NETWORK_NAME=mainnet
NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED=false
NEXT_PUBLIC_BEACON_BASE_URL=https://dora.ethpandaops.io/
NEXT_PUBLIC_EXPLORER_BASE_URL=https://etherscan.io/
PUBLIC_BEACON_BASE_URL=https://dora.ethpandaops.io/
PUBLIC_EXPLORER_BASE_URL=https://etherscan.io/

#### rest api server

Expand Down
14 changes: 7 additions & 7 deletions apps/docs/src/app/docs/environment/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ nextjs:
| -------------------------------------- | ------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DATABASE_URL` | PostgreSQL database URI | Yes | (empty) |
| `FEEDBACK_WEBHOOK_URL` | Discord webhook URL for feedback | No | (empty) |
| `NEXT_PUBLIC_NETWORK_NAME` | Network name | No | mainnet |
| `NEXT_PUBLIC_EXPLORER_BASE_URL` | Block explorer URL | No | `https://etherscan.io` |
| `NEXT_PUBLIC_BEACON_BASE_URL` | Beacon explorer URL | No | `https://beaconcha.in/` |
| `PUBLIC_NETWORK_NAME` | Network name | No | mainnet |
| `PUBLIC_EXPLORER_BASE_URL` | Block explorer URL | No | `https://etherscan.io` |
| `PUBLIC_BEACON_BASE_URL` | Beacon explorer URL | No | `https://beaconcha.in/` |
| `NEXT_PUBLIC_BLOBSCAN_RELEASE` | Blobscan version | No | (empty) |
| `NEXT_PUBLIC_SUPPORTED_NETWORKS` | Link to other pages from the Network menu | No | `[{"label":"Ethereum Mainnet","href":"https://blobscan.com/"},{"label":"Gnosis","href":"https://gnosis.blobscan.com/"},{"label":"Holesky Testnet","href":"https://holesky.blobscan.com/"},{"label":"Sepolia Testnet","href":"https://sepolia.blobscan.com/"}]` |
| `PUBLIC_SUPPORTED_NETWORKS` | Link to other pages from the Network menu | No | `[{"label":"Ethereum Mainnet","href":"https://blobscan.com/"},{"label":"Gnosis","href":"https://gnosis.blobscan.com/"},{"label":"Holesky Testnet","href":"https://holesky.blobscan.com/"},{"label":"Sepolia Testnet","href":"https://sepolia.blobscan.com/"}]` |
| `NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED` | Enable Vercel analytics | No | `false` |
| `NEXT_PUBLIC_SENTRY_DSN_WEB` | Sentry DSN | No | (empty) |
| `PUBLIC_SENTRY_DSN_WEB` | Sentry DSN | No | (empty) |
| `NODE_ENV` | Used in Node.js applications to specify the environment in which the application is running | No | (empty) |
| `SENTRY_PROJECT` | Sentry project name | No | (empty) |
| `SENTRY_ORG` | Sentry organization | No | (empty) |
| `METRICS_ENABLED` | Expose the /metrics endpoint | No | `false` |
| `TRACES_ENABLED` | Enable instrumentation of functions and sending traces to a collector | No | `false` |
| `NEXT_PUBLIC_POSTHOG_ID` | PostHog project API key used for tracking events and analytics | No | (empty) |
| `NEXT_PUBLIC_POSTHOG_HOST` | Host URL for the PostHog instance used for analytics tracking | No | `https://us.i.posthog.com` |
| `PUBLIC_POSTHOG_ID` | PostHog project API key used for tracking events and analytics | No | (empty) |
| `PUBLIC_POSTHOG_HOST` | Host URL for the PostHog instance used for analytics tracking | No | `https://us.i.posthog.com` |

## Blobscan API

Expand Down
13 changes: 5 additions & 8 deletions apps/web/banner.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ export function printBanner() {
console.log("Blobscan Web App (EIP-4844 blob explorer) - blobscan.com");
console.log("=======================================================\n");
console.log(
`Configuration: network=${process.env.NEXT_PUBLIC_NETWORK_NAME} explorer=${
process.env.NEXT_PUBLIC_EXPLORER_BASE_URL
`Configuration: network=${process.env.PUBLIC_NETWORK_NAME} explorer=${
process.env.PUBLIC_EXPLORER_BASE_URL
} beaconExplorer=${
process.env.NEXT_PUBLIC_BEACON_BASE_URL
process.env.PUBLIC_BEACON_BASE_URL
} feedbackEnabled=${!!process.env
.FEEDBACK_WEBHOOK_URL} tracesEnabled=${!!process.env
.TRACES_ENABLED} sentryEnabled=${!!process.env
.NEXT_PUBLIC_SENTRY_DSN_WEB}`
.TRACES_ENABLED} sentryEnabled=${!!process.env.PUBLIC_SENTRY_DSN_WEB}`
);
console.log(
`Blob storage manager configuration: chainId=${process.env.CHAIN_ID}, file_system=${process.env.FILE_SYSTEM_STORAGE_ENABLED} postgres=${process.env.POSTGRES_STORAGE_ENABLED}, gcs=${process.env.GOOGLE_STORAGE_ENABLED}, swarm=${process.env.SWARM_STORAGE_ENABLED}`
Expand All @@ -35,9 +34,7 @@ export function printBanner() {
}

if (process.env.SWARM_STORAGE_ENABLED) {
console.log(
`Swarm configuration: beeEndpoint=${process.env.BEE_ENDPOINT}`
);
console.log(`Swarm configuration: beeEndpoint=${process.env.BEE_ENDPOINT}`);
}

if (process.env.FILE_SYSTEM_STORAGE_ENABLED) {
Expand Down
1 change: 0 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"@blobscan/dates": "workspace:*",
"@blobscan/dayjs": "workspace:^0.1.0",
"@blobscan/db": "workspace:^0.13.0",
"@blobscan/env": "workspace:^0.1.0",
"@blobscan/eth-format": "workspace:^0.1.0",
"@blobscan/open-telemetry": "workspace:^0.0.9",
"@blobscan/rollups": "workspace:^0.2.2",
Expand Down
31 changes: 24 additions & 7 deletions apps/web/sentry.client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,29 @@
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from "@sentry/nextjs";
import type { z } from "zod";

import { env } from "./src/env.mjs";
import type { clientEnvVarsSchema } from "~/env.mjs";

Sentry.init({
dsn: env.NEXT_PUBLIC_SENTRY_DSN_WEB,
environment: env.NEXT_PUBLIC_NETWORK_NAME,
tracesSampleRate: 1,
debug: false,
});
type ClientEnvVars = z.output<typeof clientEnvVarsSchema>;

const initSentry = async () => {
try {
const request = await fetch("/api/env");
const env = (await request.json()) as ClientEnvVars;

const dns = env.PUBLIC_SENTRY_DSN_WEB;
const environment = env.PUBLIC_NETWORK_NAME;

Sentry.init({
dsn: dns,
environment,
tracesSampleRate: 1,
debug: false,
});
} catch (error) {
console.error("Error during Sentry initialization", error);
}
};

initSentry();
4 changes: 2 additions & 2 deletions apps/web/sentry.edge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import * as Sentry from "@sentry/nextjs";
import { env } from "./src/env.mjs";

Sentry.init({
dsn: env.NEXT_PUBLIC_SENTRY_DSN_WEB,
environment: env.NEXT_PUBLIC_NETWORK_NAME,
dsn: env.PUBLIC_SENTRY_DSN_WEB,
environment: env.PUBLIC_NETWORK_NAME,
tracesSampleRate: 1,
debug: false,
});
4 changes: 2 additions & 2 deletions apps/web/sentry.server.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import * as Sentry from "@sentry/nextjs";
import { env } from "./src/env.mjs";

Sentry.init({
dsn: env.NEXT_PUBLIC_SENTRY_DSN_WEB,
environment: env.NEXT_PUBLIC_NETWORK_NAME,
dsn: env.PUBLIC_SENTRY_DSN_WEB,
environment: env.PUBLIC_NETWORK_NAME,
tracesSampleRate: 1,
debug: false,
});
26 changes: 8 additions & 18 deletions apps/web/src/components/BlobscanVersionInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
import { env } from "~/env.mjs";
import { Link } from "./Link";

function getVersionData(): { url: string; label: string } {
export const BlobscanVersionInfo: React.FC = () => {
let url = "https://github.com/Blobscan/blobscan/";
let label = "Development";

if (env.NEXT_PUBLIC_BLOBSCAN_RELEASE) {
return {
url: `https://github.com/Blobscan/blobscan/releases/tag/${env.NEXT_PUBLIC_BLOBSCAN_RELEASE}`,
label: env.NEXT_PUBLIC_BLOBSCAN_RELEASE,
};
url = `https://github.com/Blobscan/blobscan/releases/tag/${env.NEXT_PUBLIC_BLOBSCAN_RELEASE}`;
label = env.NEXT_PUBLIC_BLOBSCAN_RELEASE;
}

if (env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA) {
return {
url: `https://github.com/Blobscan/blobscan/commit/${env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA}`,
label: env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA.slice(0, 7),
};
url = `https://github.com/Blobscan/blobscan/commit/${env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA}`;
label = env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA.slice(0, 7);
}

return {
url: "https://github.com/Blobscan/blobscan/",
label: "Development",
};
}

export const BlobscanVersionInfo: React.FC = () => {
const { url, label } = getVersionData();

return (
<div className="flex items-center gap-1">
<div className="text-xs text-contentTertiary-light dark:text-contentTertiary-dark">
Expand Down
13 changes: 11 additions & 2 deletions apps/web/src/components/ExplorerDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import Skeleton from "react-loading-skeleton";
import { formatTtl } from "@blobscan/dates";

import { api } from "~/api-client";
import { env } from "~/env.mjs";
import Gas from "~/icons/gas.svg";
import { useEnv } from "~/providers/Env";
import { capitalize, formatNumber } from "~/utils";
import { EtherUnitDisplay } from "./Displays/EtherUnitDisplay";

Expand Down Expand Up @@ -45,11 +45,20 @@ export function ExplorerDetails({ placement }: ExplorerDetailsProps) {
const { data: blobStoragesState } = api.blobStoragesState.getState.useQuery();
const { data: latestBlock } = api.block.getLatestBlock.useQuery();

const { env } = useEnv();

const explorerDetailsItems: ExplorerDetailsItemProps[] = [];

if (placement === "top") {
explorerDetailsItems.push(
{ name: "Network", value: capitalize(env.NEXT_PUBLIC_NETWORK_NAME) },
{
name: "Network",
value: env ? (
capitalize(env.PUBLIC_NETWORK_NAME)
) : (
<Skeleton height={14} width={48} />
),
},
{
name: "Blob gas price",
icon: <Gas className="h-4 w-4" />,
Expand Down
34 changes: 6 additions & 28 deletions apps/web/src/components/Filters/RollupFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,22 @@
import { useRef } from "react";
import type { FC } from "react";

import { getChainRollups } from "@blobscan/rollups";

import { Dropdown } from "~/components/Dropdown";
import type { DropdownProps, Option } from "~/components/Dropdown";
import { RollupIcon } from "~/components/RollupIcon";
import { env } from "~/env.mjs";
import type { Rollup } from "~/types";
import { capitalize, getChainIdByName } from "~/utils";
import { RollupBadge } from "../Badges/RollupBadge";

type RollupFilterProps = Pick<DropdownProps, "selected" | "disabled"> & {
type RollupFilterProps = Pick<
DropdownProps,
"selected" | "disabled" | "options"
> & {
onChange(newRollups: Option[]): void;
selected: Option[] | null;
};

const chainId = getChainIdByName(env.NEXT_PUBLIC_NETWORK_NAME);
const rollups = chainId ? getChainRollups(chainId) : [];

export const ROLLUP_OPTIONS = rollups.map(
([name, addresses]) =>
({
value: addresses,
selectedLabel: (
<RollupBadge rollup={name.toLowerCase() as Rollup} size="sm" />
),
label: (
<div className="flex flex-row items-center gap-2">
<RollupIcon rollup={name.toLowerCase() as Rollup} />
<div>{capitalize(name)}</div>
</div>
),
} satisfies Option)
) satisfies Option[];

export const RollupFilter: FC<RollupFilterProps> = function ({
onChange,
selected,
disabled,
options,
}) {
const noneIsSelected = useRef<boolean>(false);

Expand Down Expand Up @@ -66,7 +44,7 @@ export const RollupFilter: FC<RollupFilterProps> = function ({
return (
<Dropdown
selected={selected}
options={ROLLUP_OPTIONS}
options={options}
onChange={handleOnChange}
placeholder="Rollup"
width="w-[120px] min-[440px]:w-[180px] min-[540px]:w-[260px] min-[580px]:w-[280px] sm:w-[170px] md:w-[110px] lg:w-[180px] xl:w-[200px]"
Expand Down
Loading

0 comments on commit 22ae59a

Please sign in to comment.