1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2026-06-05 19:15:30 -04:00

validate environment variables at build time

This commit is contained in:
2025-04-09 09:11:18 -04:00
parent 84702aeab1
commit eb92e54fd6
23 changed files with 150 additions and 60 deletions
+3 -7
View File
@@ -8,10 +8,6 @@ export const AVATAR_PATH = "app/avatar.jpg";
// maximum width of content wrapper (e.g. for images) in pixels
export const MAX_WIDTH = 865;
// same logic as metadataBase: https://nextjs.org/docs/app/api-reference/functions/generate-metadata#default-value
export const BASE_URL =
process.env.NEXT_PUBLIC_VERCEL_ENV === "production" && process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL
? `https://${process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL}`
: process.env.NEXT_PUBLIC_VERCEL_ENV === "preview" && process.env.NEXT_PUBLIC_VERCEL_URL
? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
: `http://localhost:${process.env.PORT || 3000}`;
// defined in next.config.ts
export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL!;
export const RELEASE_TIMESTAMP = process.env.NEXT_PUBLIC_RELEASE_TIMESTAMP!;
+2 -2
View File
@@ -2,7 +2,7 @@ import * as config from ".";
import { BASE_URL } from "./constants";
import type { Metadata } from "next";
const metadata: Metadata = {
const defaultMetadata: Metadata = {
metadataBase: new URL(BASE_URL),
title: {
template: `%s ${config.siteName}`,
@@ -44,4 +44,4 @@ const metadata: Metadata = {
},
};
export default metadata;
export default defaultMetadata;
+34
View File
@@ -0,0 +1,34 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { vercel } from "@t3-oss/env-nextjs/presets-valibot";
import * as v from "valibot";
export const env = createEnv({
extends: [vercel()],
server: {
GITHUB_TOKEN: v.optional(v.pipe(v.string(), v.startsWith("ghp_"))),
KV_REST_API_TOKEN: v.string(),
KV_REST_API_URL: v.pipe(v.string(), v.url(), v.startsWith("https://"), v.endsWith(".upstash.io")),
RESEND_API_KEY: v.pipe(v.string(), v.startsWith("re_")),
RESEND_FROM_EMAIL: v.optional(v.pipe(v.string(), v.email())),
RESEND_TO_EMAIL: v.pipe(v.string(), v.email()),
TURNSTILE_SECRET_KEY: v.optional(v.string()),
},
client: {
NEXT_PUBLIC_GISCUS_CATEGORY_ID: v.optional(v.string()),
NEXT_PUBLIC_GISCUS_REPO_ID: v.optional(v.string()),
NEXT_PUBLIC_ONION_DOMAIN: v.optional(v.pipe(v.string(), v.endsWith(".onion"))),
NEXT_PUBLIC_TURNSTILE_SITE_KEY: v.optional(v.string()),
NEXT_PUBLIC_UMAMI_URL: v.optional(v.pipe(v.string(), v.url())),
NEXT_PUBLIC_UMAMI_WEBSITE_ID: v.optional(v.string()),
},
experimental__runtimeEnv: {
NEXT_PUBLIC_GISCUS_CATEGORY_ID: process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID,
NEXT_PUBLIC_GISCUS_REPO_ID: process.env.NEXT_PUBLIC_GISCUS_REPO_ID,
NEXT_PUBLIC_ONION_DOMAIN: process.env.NEXT_PUBLIC_ONION_DOMAIN,
NEXT_PUBLIC_TURNSTILE_SITE_KEY: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY,
NEXT_PUBLIC_UMAMI_URL: process.env.NEXT_PUBLIC_UMAMI_URL,
NEXT_PUBLIC_UMAMI_WEBSITE_ID: process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID,
},
emptyStringAsUndefined: true,
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
});
+5 -5
View File
@@ -1,7 +1,7 @@
import { Feed } from "feed";
import { getFrontMatter, getContent } from "./posts";
import * as config from "../config";
import { BASE_URL } from "../config/constants";
import { BASE_URL, RELEASE_TIMESTAMP } from "../config/constants";
import type { Item as FeedItem } from "feed";
import ogImage from "../../app/opengraph-image.jpg";
@@ -12,12 +12,12 @@ import ogImage from "../../app/opengraph-image.jpg";
*/
export const buildFeed = async (): Promise<Feed> => {
const feed = new Feed({
id: BASE_URL,
link: BASE_URL,
id: `${BASE_URL}`,
link: `${BASE_URL}`,
title: config.siteName,
description: config.longDescription,
copyright: config.licenseUrl,
updated: new Date(process.env.RELEASE_DATE || Date.now()),
updated: new Date(RELEASE_TIMESTAMP),
image: `${BASE_URL}${ogImage.src}`,
feedLinks: {
rss: `${BASE_URL}/feed.xml`,
@@ -41,7 +41,7 @@ export const buildFeed = async (): Promise<Feed> => {
author: [
{
name: config.authorName,
link: BASE_URL,
link: `${BASE_URL}`,
},
],
date: new Date(post.date),
+1 -1
View File
@@ -1,4 +1,4 @@
import defaultMetadata from "../config/metadata";
import defaultMetadata from "../config/seo";
import type { Metadata } from "next";
/**