Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[N/A] environmental variables validation #1165

Merged
merged 1 commit into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/testing-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ jobs:
command-prefix: yarn dlx
command: "yarn test:e2e"
env:
NEXT_PUBLIC_MAPBOX_API_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPBOX_API_TOKEN }}
NEXT_PUBLIC_API_URL: ${{ secrets.CYPRESS_API_URL }}
NEXT_TELEMETRY_DISABLED: 1
NEXTAUTH_URL: http://localhost:3000
Expand Down
3 changes: 0 additions & 3 deletions client/.env.sample
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
NEXT_PUBLIC_MAPBOX_API_TOKEN="[mapbox-token]"
NEXT_PUBLIC_API_URL="http://[api-url]"
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="nyancat"
NEXT_PUBLIC_FILE_UPLOADER_MAX_SIZE=10000000
NEXT_TELEMETRY_DISABLED=1
2 changes: 0 additions & 2 deletions client/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ ARG UID=5000
ARG GID=5000
ARG NEXTAUTH_URL
ARG NEXTAUTH_SECRET
ARG NEXT_PUBLIC_MAPBOX_API_TOKEN
ARG NEXT_PUBLIC_API_URL
ARG CYPRESS_USERNAME
ARG CYPRESS_PASSWORD
Expand All @@ -14,7 +13,6 @@ ENV USER $NAME
ENV APP_HOME /opt/$NAME
ENV NEXTAUTH_URL $NEXTAUTH_URL
ENV NEXTAUTH_SECRET $NEXTAUTH_SECRET
ENV NEXT_PUBLIC_MAPBOX_API_TOKEN $NEXT_PUBLIC_MAPBOX_API_TOKEN
ENV NEXT_PUBLIC_API_URL $NEXT_PUBLIC_API_URL
ENV NEXT_TELEMETRY_DISABLED 1
ENV CYPRESS_USERNAME $CYPRESS_USERNAME
Expand Down
13 changes: 0 additions & 13 deletions client/ENV_VARS.md

This file was deleted.

11 changes: 11 additions & 0 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ Run the development server:
```bash
yarn dev
```

### Environmental variables
The application handles environmental variables using [@t3-oss/env-nextjs](https://env.t3.gg/docs). You can see the available (and required) variables in the `./src/env` file. **NOTE**: the application will NOT start if the required variables are not set previously.

#### Testing
Additionally, and exclusively for testing purposes, you can set the following environmental variables:

- `CYPRESS_USERNAME`: email to authenticate for the e2e tests.
- `CYPRESS_PASSWORD`: password to authenticate for the e2e tests.
- `CYPRESS_API_URL`: API used to run the e2e tests.

### Running tests

Run the tests locally:
Expand Down
1 change: 0 additions & 1 deletion client/docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ services:
args:
- NEXTAUTH_URL=http://localhost:3000
- NEXTAUTH_SECRET=secret
- NEXT_PUBLIC_MAPBOX_API_TOKEN=token
ports:
- "3000:3000"
container_name: landgriffon-client
Expand Down
20 changes: 10 additions & 10 deletions client/next.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import { fileURLToPath } from 'node:url';

import createJiti from 'jiti';

import { env } from './src/env.mjs';

const jiti = createJiti(fileURLToPath(import.meta.url));
jiti('./src/env.mjs');

/** @type {import('next').NextConfig} */
const nextConfig = {
poweredByHeader: false,
Expand All @@ -21,7 +30,7 @@ const nextConfig = {
destination: '/auth/signin',
permanent: false,
},
...(process.env.NEXT_PUBLIC_ENABLE_EUDR !== 'true'
...(!env.NEXT_PUBLIC_ENABLE_EUDR
? [
{
source: '/eudr',
Expand All @@ -32,15 +41,6 @@ const nextConfig = {
: []),
];
},
env: {
NEXT_PUBLIC_PLANET_API_KEY: 'PLAK6679039df83f414faf798ba4ad4530db',
NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN:
'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfemsydWhpaDYiLCJqdGkiOiJjY2JlMjUyYSJ9.LoqzuDp076ESVYmHm1mZNtfhnqOVGmSxzp60Fht8PQw',
NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN:
'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfemsydWhpaDYiLCJqdGkiOiJjZDk0ZWIyZSJ9.oqLagnOEc-j7Z4hY-MTP1yoZA_vJ7WYYAkOz_NUmCJo',
NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN:
'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfemsydWhpaDYiLCJqdGkiOiI3NTFkNzA1YSJ9.jrVugV7HYfhmjxj-p2Iks8nL_AjHR91Q37JVP2fNmtc',
},
};

export default nextConfig;
5 changes: 4 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@
"tailwindcss": "3.4.1",
"tailwindcss-animate": "1.0.7",
"uuid": "8.3.2",
"yup": "0.32.11"
"yup": "0.32.11",
"zod": "3.22.4"
},
"devDependencies": {
"@t3-oss/env-nextjs": "0.9.2",
"@types/chroma-js": "2.1.3",
"@types/d3-format": "3.0.1",
"@types/d3-scale": "4.0.2",
Expand All @@ -116,6 +118,7 @@
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.1.3",
"istanbul-reports": "3.0.0",
"jiti": "1.21.0",
"nyc": "15.1.0",
"nyc-report-lcov-absolute": "1.0.0",
"prettier": "^3.1.1",
Expand Down
4 changes: 3 additions & 1 deletion client/src/components/map/layers/maplibre/raster/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import queryString from 'query-string';

import { env } from '@/env.mjs';

import type { ContextualLayerApiResponse } from 'hooks/layers/getContextualLayers';

export const getTiler = (
Expand All @@ -9,7 +11,7 @@ export const getTiler = (
return queryString.stringifyUrl({
url: tilerPath.match(/^(http|https):\/\//)
? tilerPath
: `${process.env.NEXT_PUBLIC_API_URL}${tilerPath}`,
: `${env.NEXT_PUBLIC_API_URL}${tilerPath}`,
query: tilerParams,
});
};
11 changes: 6 additions & 5 deletions client/src/containers/analysis-eudr/map/compare.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useAppSelector } from '@/store/hooks';
import { INITIAL_VIEW_STATE, MAP_STYLES } from '@/components/map';
import { useEUDRData, usePlotGeometries } from '@/hooks/eudr';
import { formatNumber } from '@/utils/number-format';
import { env } from '@/env.mjs';

import type { PickingInfo, MapViewState } from '@deck.gl/core/typed';

Expand Down Expand Up @@ -174,7 +175,7 @@ const EUDRCompareMap = () => {
credentials: {
apiVersion: API_VERSIONS.V3,
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken: process.env.NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN,
accessToken: env.NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN,
},
});

Expand All @@ -192,7 +193,7 @@ const EUDRCompareMap = () => {
credentials: {
apiVersion: API_VERSIONS.V3,
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken: process.env.NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN,
accessToken: env.NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN,
},
});

Expand All @@ -217,7 +218,7 @@ const EUDRCompareMap = () => {
credentials: {
apiVersion: API_VERSIONS.V3,
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken: process.env.NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN,
accessToken: env.NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN,
},
});

Expand Down Expand Up @@ -298,7 +299,7 @@ const EUDRCompareMap = () => {
planetLayer.year
}_${monthFormatter(
planetLayer.month.toString(),
)}_mosaic/gmap/{z}/{x}/{y}.png?api_key=${process.env.NEXT_PUBLIC_PLANET_API_KEY}`,
)}_mosaic/gmap/{z}/{x}/{y}.png?api_key=${env.NEXT_PUBLIC_PLANET_API_KEY}`,
]}
tileSize={256}
>
Expand All @@ -318,7 +319,7 @@ const EUDRCompareMap = () => {
planetCompareLayer.year
}_${monthFormatter(
planetCompareLayer.month.toString(),
)}_mosaic/gmap/{z}/{x}/{y}.png?api_key=${process.env.NEXT_PUBLIC_PLANET_API_KEY}`,
)}_mosaic/gmap/{z}/{x}/{y}.png?api_key=${env.NEXT_PUBLIC_PLANET_API_KEY}`,
]}
tileSize={256}
>
Expand Down
9 changes: 5 additions & 4 deletions client/src/containers/analysis-eudr/map/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useAppSelector } from '@/store/hooks';
import { INITIAL_VIEW_STATE, MAP_STYLES } from '@/components/map';
import { useEUDRData, usePlotGeometries } from '@/hooks/eudr';
import { formatNumber } from '@/utils/number-format';
import { env } from '@/env.mjs';

import type { PickingInfo, MapViewState } from '@deck.gl/core/typed';

Expand Down Expand Up @@ -169,7 +170,7 @@ const EUDRMap: React.FC<{ supplierId?: string }> = ({ supplierId }) => {
credentials: {
apiVersion: API_VERSIONS.V3,
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken: process.env.NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN,
accessToken: env.NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN,
},
});

Expand All @@ -187,7 +188,7 @@ const EUDRMap: React.FC<{ supplierId?: string }> = ({ supplierId }) => {
credentials: {
apiVersion: API_VERSIONS.V3,
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken: process.env.NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN,
accessToken: env.NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN,
},
});

Expand All @@ -212,7 +213,7 @@ const EUDRMap: React.FC<{ supplierId?: string }> = ({ supplierId }) => {
credentials: {
apiVersion: API_VERSIONS.V3,
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken: process.env.NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN,
accessToken: env.NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN,
},
});

Expand Down Expand Up @@ -277,7 +278,7 @@ const EUDRMap: React.FC<{ supplierId?: string }> = ({ supplierId }) => {
planetLayer.year
}_${monthFormatter(
planetLayer.month.toString(),
)}_mosaic/gmap/{z}/{x}/{y}.png?api_key=${process.env.NEXT_PUBLIC_PLANET_API_KEY}`,
)}_mosaic/gmap/{z}/{x}/{y}.png?api_key=${env.NEXT_PUBLIC_PLANET_API_KEY}`,
]}
tileSize={256}
>
Expand Down
5 changes: 2 additions & 3 deletions client/src/containers/uploader/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useRouter } from 'next/router';
import { useUploadDataSource } from 'hooks/sourcing-data';
import { useLasTask } from 'hooks/tasks';
import FileDropzone from 'components/file-dropzone';
import { env } from '@/env.mjs';

import type { FileDropZoneProps } from 'components/file-dropzone/types';
import type { Task } from 'types';
Expand All @@ -15,14 +16,12 @@ type DataUploaderProps = {
onUploadInProgress?: (inProgress: boolean) => void;
};

const MAX_SIZE = Number(process.env.NEXT_PUBLIC_FILE_UPLOADER_MAX_SIZE || '10000000');

const uploadOptions = {
accept: {
'application/vnd.ms-excel': ['.xls'],
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
},
maxSize: MAX_SIZE,
maxSize: env.NEXT_PUBLIC_FILE_UPLOADER_MAX_SIZE,
};

const DataUploader: React.FC<DataUploaderProps> = ({ variant = 'default', onUploadInProgress }) => {
Expand Down
63 changes: 63 additions & 0 deletions client/src/env.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { createEnv } from '@t3-oss/env-nextjs';
import { z } from 'zod';

export const env = createEnv({
shared: {
NODE_ENV: z.enum(['development', 'production', 'test']),
},

/*
* Serverside Environment variables, not available on the client.
* Will throw if you access these variables on the client.
*/
server: {
// ? URL (including protocol) of the client application
NEXTAUTH_URL: z
.string()
.url()
.default(`http://localhost:${process.env.PORT || 3000}`),
// ? Secret used for cryptographic operations in the client application. Generate using `openssl rand -base64 32`
NEXTAUTH_SECRET: z.string().min(1),
},
/*
* Environment variables available on the client (and server).
*
* 💡 You'll get type errors if these are not prefixed with NEXT_PUBLIC_.
*/
client: {
// ? URL (including protocol) of the API
NEXT_PUBLIC_API_URL: z.string().url(),
// ? enables access to EUDR page
NEXT_PUBLIC_ENABLE_EUDR: z.coerce.boolean().optional().default(false),
NEXT_PUBLIC_PLANET_API_KEY: z.string().default('PLAK6679039df83f414faf798ba4ad4530db'),
NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN: z
.string()
.default(
'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfemsydWhpaDYiLCJqdGkiOiJjY2JlMjUyYSJ9.LoqzuDp076ESVYmHm1mZNtfhnqOVGmSxzp60Fht8PQw',
),
NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN: z
.string()
.default(
'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfemsydWhpaDYiLCJqdGkiOiJjZDk0ZWIyZSJ9.oqLagnOEc-j7Z4hY-MTP1yoZA_vJ7WYYAkOz_NUmCJo',
),
NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN: z
.string()
.default(
'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfemsydWhpaDYiLCJqdGkiOiI3NTFkNzA1YSJ9.jrVugV7HYfhmjxj-p2Iks8nL_AjHR91Q37JVP2fNmtc',
),
NEXT_PUBLIC_FILE_UPLOADER_MAX_SIZE: z.coerce.number().default(10000000),
},
runtimeEnv: {
NODE_ENV: process.env.NODE_ENV,
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
NEXT_PUBLIC_ENABLE_EUDR: process.env.NEXT_PUBLIC_ENABLE_EUDR,
NEXT_PUBLIC_PLANET_API_KEY: process.env.NEXT_PUBLIC_PLANET_API_KEY,
NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN: process.env.NEXT_PUBLIC_CARTO_FOREST_ACCESS_TOKEN,
NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN:
process.env.NEXT_PUBLIC_CARTO_DEFORESTATION_ACCESS_TOKEN,
NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN: process.env.NEXT_PUBLIC_CARTO_RADD_ACCESS_TOKEN,
NEXT_PUBLIC_FILE_UPLOADER_MAX_SIZE: process.env.NEXT_PUBLIC_FILE_UPLOADER_MAX_SIZE,
},
});
3 changes: 2 additions & 1 deletion client/src/layouts/application/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CollectionIcon as CollectionIconSolid } from '@heroicons/react/solid';

import { ChartBarIconOutline, ChartBarIconSolid } from './icons/chart-bar';

import { env } from '@/env.mjs';
import { useLasTask } from 'hooks/tasks';
import Navigation from 'containers/navigation/desktop';
import UserDropdown from 'containers/user-dropdown';
Expand All @@ -31,7 +32,7 @@ const ApplicationLayout: React.FC<React.PropsWithChildren> = ({ children }) => {
icon: { default: ChartBarIconOutline, active: ChartBarIconSolid },
disabled: !!(!lastTask || lastTask?.status === 'processing'),
},
...(process.env.NEXT_PUBLIC_ENABLE_EUDR === 'true'
...(env.NEXT_PUBLIC_ENABLE_EUDR
? [
{
name: 'EUDR',
Expand Down
4 changes: 3 additions & 1 deletion client/src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Jsona from 'jsona';
import { getSession, signOut } from 'next-auth/react';
import toast from 'react-hot-toast';

import { env } from '@/env.mjs';

import type { ApiError, ErrorResponse } from 'types';
import type { AxiosRequestConfig, AxiosResponse } from 'axios';

Expand All @@ -14,7 +16,7 @@ import type { AxiosRequestConfig, AxiosResponse } from 'axios';
const dataFormatter = new Jsona();

const defaultConfig: AxiosRequestConfig = {
baseURL: `${process.env.NEXT_PUBLIC_API_URL}/api/v1`,
baseURL: `${env.NEXT_PUBLIC_API_URL}/api/v1`,
headers: { 'Content-Type': 'application/json' },
};

Expand Down
4 changes: 3 additions & 1 deletion client/src/services/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import axios from 'axios';

import { env } from '@/env.mjs';

export const authService = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_API_URL}/auth`,
baseURL: `${env.NEXT_PUBLIC_API_URL}/auth`,
headers: { 'Content-Type': 'application/json' },
});

Expand Down
3 changes: 2 additions & 1 deletion client/src/services/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import axios, { AxiosError } from 'axios';
import { getServerSession } from 'next-auth/next';

import { options as authOptions } from 'pages/api/auth/[...nextauth]';
import { env } from '@/env.mjs';

export const sessionSSR = async ({ req, res }) => await getServerSession(req, res, authOptions);

Expand All @@ -14,7 +15,7 @@ export const tasksSSR = async ({ req, res }) => {

return await axios({
method: 'GET',
url: `${process.env.NEXT_PUBLIC_API_URL}/api/v1/tasks`,
url: `${env.NEXT_PUBLIC_API_URL}/api/v1/tasks`,
params: { 'page[size]': 1, 'page[number]': 1, sort: '-createdAt' },
headers: {
Authorization: `Bearer ${session.accessToken}`,
Expand Down
Loading
Loading