mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-11-23 11:46:08 -05:00
move documentation of environment variables into lib/env.ts
This commit is contained in:
@@ -3,7 +3,7 @@ export const POSTS_DIR = "notes";
|
||||
|
||||
// path to an image used in various places to represent the site, relative to project root
|
||||
// IMPORTANT: must be included in next.config.ts under "outputFileTracingIncludes"
|
||||
export const AVATAR_PATH = "app/avatar.jpg";
|
||||
export const AVATAR_PATH = "app/selfie.jpg";
|
||||
|
||||
// maximum width of content wrapper (e.g. for images) in pixels
|
||||
export const MAX_WIDTH = 865;
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import * as config from ".";
|
||||
import { BASE_URL } from "./constants";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
const defaultMetadata: Metadata = {
|
||||
metadataBase: new URL(BASE_URL),
|
||||
title: {
|
||||
template: `%s – ${config.siteName}`,
|
||||
default: `${config.siteName} – ${config.shortDescription}`,
|
||||
},
|
||||
description: config.longDescription,
|
||||
openGraph: {
|
||||
siteName: config.siteName,
|
||||
title: {
|
||||
template: "%s",
|
||||
default: `${config.siteName} – ${config.shortDescription}`,
|
||||
},
|
||||
url: "/",
|
||||
locale: config.siteLocale?.replace("-", "_"),
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
creator: `@${config.authorSocial?.twitter}`,
|
||||
},
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
types: {
|
||||
"application/rss+xml": [
|
||||
{
|
||||
title: `${config.siteName} (RSS)`,
|
||||
url: "/feed.xml",
|
||||
},
|
||||
],
|
||||
"application/atom+xml": [
|
||||
{
|
||||
title: `${config.siteName} (Atom)`,
|
||||
url: "/feed.atom",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
other: {
|
||||
humans: "/humans.txt",
|
||||
},
|
||||
};
|
||||
|
||||
export default defaultMetadata;
|
||||
98
lib/env.ts
98
lib/env.ts
@@ -3,22 +3,110 @@ import { vercel } from "@t3-oss/env-nextjs/presets-valibot";
|
||||
import * as v from "valibot";
|
||||
|
||||
export const env = createEnv({
|
||||
extends: [vercel()],
|
||||
extends: [
|
||||
// NOTE: Some assumptions are sprinkled throughout the code that this site is being deployed on Vercel. If not, find
|
||||
// and replace `env.VERCEL_` (especially `VERCEL_ENV` and `VERCEL_PROJECT_PRODUCTION_URL`) with more appropriate
|
||||
// variables.
|
||||
vercel(),
|
||||
],
|
||||
server: {
|
||||
/**
|
||||
* Required. GitHub API token used for /projects grid. Only needs the `public_repo` scope since we don't need/want
|
||||
* to change anything, obviously.
|
||||
*
|
||||
* @see https://github.com/settings/tokens/new?scopes=public_repo
|
||||
*/
|
||||
GITHUB_TOKEN: v.optional(v.pipe(v.string(), v.startsWith("ghp_"))),
|
||||
|
||||
/**
|
||||
* Required. Redis storage credentials for hit counter's server component (app/notes/[slug]/counter.tsx) and API
|
||||
* endpoint. Currently set automatically by Vercel's Upstash integration.
|
||||
*
|
||||
* @see https://upstash.com/docs/redis/sdks/ts/getstarted
|
||||
* @see https://vercel.com/marketplace/upstash
|
||||
*/
|
||||
KV_REST_API_TOKEN: v.string(),
|
||||
/**
|
||||
* Required. Redis storage credentials for hit counter's server component (app/notes/[slug]/counter.tsx) and API
|
||||
* endpoint. Currently set automatically by Vercel's Upstash integration.
|
||||
*
|
||||
* @see https://upstash.com/docs/redis/sdks/ts/getstarted
|
||||
* @see https://vercel.com/marketplace/upstash
|
||||
*/
|
||||
KV_REST_API_URL: v.pipe(v.string(), v.url(), v.startsWith("https://"), v.endsWith(".upstash.io")),
|
||||
|
||||
/**
|
||||
* Required. Uses Resend API to send contact form submissions via a server action (see app/contact/actions.ts). May
|
||||
* be set automatically by Vercel's Resend integration.
|
||||
*
|
||||
* @see https://resend.com/api-keys
|
||||
* @see https://vercel.com/integrations/resend
|
||||
*/
|
||||
RESEND_API_KEY: v.pipe(v.string(), v.startsWith("re_")),
|
||||
RESEND_FROM_EMAIL: v.optional(v.pipe(v.string(), v.email())),
|
||||
/**
|
||||
* Optional, but will throw a warning if unset. Use an approved domain (or subdomain) on the Resend account to send
|
||||
* submissions from. Sender's real email is passed via a Reply-To header, so setting this makes zero difference to
|
||||
* the user, only for deliverability success. Defaults to `onboarding@resend.dev`.
|
||||
*
|
||||
* @see https://resend.com/domains
|
||||
*/
|
||||
RESEND_FROM_EMAIL: v.optional(v.pipe(v.string(), v.email()), "onboarding@resend.dev"),
|
||||
/**
|
||||
* Required. The destination email for contact form submissions.
|
||||
*/
|
||||
RESEND_TO_EMAIL: v.pipe(v.string(), v.email()),
|
||||
TURNSTILE_SECRET_KEY: v.optional(v.string()),
|
||||
|
||||
/**
|
||||
* Required. Secret for Cloudflare `siteverify` API to validate a form's turnstile result on the backend.
|
||||
*
|
||||
* @see https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
||||
*/
|
||||
TURNSTILE_SECRET_KEY: v.optional(v.string(), "1x0000000000000000000000000000000AA"),
|
||||
},
|
||||
client: {
|
||||
/**
|
||||
* Optional. Enables comments on blog posts via GitHub discussions.
|
||||
*
|
||||
* @see https://giscus.app/
|
||||
*/
|
||||
NEXT_PUBLIC_GISCUS_CATEGORY_ID: v.optional(v.string()),
|
||||
/**
|
||||
* Optional. Enables comments on blog posts via GitHub discussions.
|
||||
*
|
||||
* @see https://giscus.app/
|
||||
*/
|
||||
NEXT_PUBLIC_GISCUS_REPO_ID: v.optional(v.string()),
|
||||
|
||||
/**
|
||||
* Optional. Sets an `Onion-Location` header in responses to advertise a URL for the same page but hosted on a
|
||||
* hidden service on the Tor network. Browsers like Brave and Tor Browser will automatically pick this up and offer
|
||||
* to redirect users to it.
|
||||
*
|
||||
* @see https://community.torproject.org/onion-services/advanced/onion-location/
|
||||
*/
|
||||
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())),
|
||||
|
||||
/**
|
||||
* Required. Site key must be prefixed with NEXT_PUBLIC_ since it is used to embed the captcha widget. Falls back to
|
||||
* testing keys if not set or in dev environment.
|
||||
*
|
||||
* @see https://developers.cloudflare.com/turnstile/troubleshooting/testing/
|
||||
*/
|
||||
NEXT_PUBLIC_TURNSTILE_SITE_KEY: v.optional(v.string(), "XXXX.DUMMY.TOKEN.XXXX"),
|
||||
|
||||
/**
|
||||
* Optional. The base URL of a self-hosted Umami instance (including https://) to proxy requests to. If the website
|
||||
* ID is set but this isn't, the managed Umami Cloud endpoint at https://cloud.umami.is is used.
|
||||
*
|
||||
* @see https://umami.is/docs/bypass-ad-blockers
|
||||
*/
|
||||
NEXT_PUBLIC_UMAMI_URL: v.optional(v.pipe(v.string(), v.startsWith("https://"), v.url()), "https://cloud.umami.is"),
|
||||
/**
|
||||
* Optional. Enables privacy-friendly tracking via Umami, either managed or self-hosted. This ID can be found in the
|
||||
* dashboard under Settings > Websites > Edit > Details.
|
||||
*
|
||||
* @see https://umami.is/docs/collect-data
|
||||
*/
|
||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID: v.optional(v.string()),
|
||||
},
|
||||
experimental__runtimeEnv: {
|
||||
|
||||
@@ -1,6 +1,49 @@
|
||||
import defaultMetadata from "../config/seo";
|
||||
import * as config from "../config";
|
||||
import { BASE_URL } from "../config/constants";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const defaultMetadata: Metadata = {
|
||||
metadataBase: new URL(BASE_URL),
|
||||
title: {
|
||||
template: `%s – ${config.siteName}`,
|
||||
default: `${config.siteName} – ${config.shortDescription}`,
|
||||
},
|
||||
description: config.longDescription,
|
||||
openGraph: {
|
||||
siteName: config.siteName,
|
||||
title: {
|
||||
template: "%s",
|
||||
default: `${config.siteName} – ${config.shortDescription}`,
|
||||
},
|
||||
url: "/",
|
||||
locale: config.siteLocale?.replace("-", "_"),
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
creator: `@${config.authorSocial?.twitter}`,
|
||||
},
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
types: {
|
||||
"application/rss+xml": [
|
||||
{
|
||||
title: `${config.siteName} (RSS)`,
|
||||
url: "/feed.xml",
|
||||
},
|
||||
],
|
||||
"application/atom+xml": [
|
||||
{
|
||||
title: `${config.siteName} (Atom)`,
|
||||
url: "/feed.atom",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
other: {
|
||||
humans: "/humans.txt",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to deep merge a page's metadata into the default site metadata
|
||||
* @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata
|
||||
|
||||
Reference in New Issue
Block a user