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

feat: move sanity and web schemaTypes config to @pkg/common, and add a web config file #112

Merged
merged 6 commits into from
Feb 18, 2025
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
2 changes: 1 addition & 1 deletion apps/sanity/sanity.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { structure } from '@/structure';
import { defaultDocumentNode } from '@/structure/defaultDocumentNode';
import { appConfig } from './config/app';
import { setupSingletons } from '@pkg/sanity-toolkit/studio/singletons';
import { LOCKED_DOCUMENT_TYPES } from '@/config/schema';
import { LOCKED_DOCUMENT_TYPES } from '@pkg/common/config/schemaTypes';
import { noteField } from '@pkg/sanity-toolkit/studio/studioComponents/noteField/plugin';
import { documentActions } from '@/actions';

Expand Down
2 changes: 1 addition & 1 deletion apps/sanity/schema/types/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SchemaTypeDefinition } from 'sanity';
import { page } from './documents/page';
import { redirects } from '@pkg/sanity-toolkit/redirects/schema';
import { DOCUMENT } from '@pkg/common/constants/schemaTypes';
import { INTERNAL_LINK_TYPES } from '@/config/schema';
import { INTERNAL_LINK_TYPES } from '@pkg/common/config/schemaTypes';
import { announcements } from '@/schema/types/documents/announcements';
import { article } from '@/schema/types/documents/article';

Expand Down
2 changes: 1 addition & 1 deletion apps/sanity/structure/defaultViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from 'sanity/structure';
import { LuPencilLine } from 'react-icons/lu';
import { seoPreviewPane } from '@/structure/seo-pane';
import { SEO_PREVIEW_DOCUMENT_TYPES } from '@/config/schema';
import { SEO_PREVIEW_DOCUMENT_TYPES } from '@pkg/common/config/schemaTypes';

export function defaultViews(
S: StructureBuilder,
Expand Down
16 changes: 16 additions & 0 deletions apps/web/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
NEXT_PUBLIC_SITE_DOMAIN=localhost:3000
NEXT_PUBLIC_BASE_URL=http://localhost:3000

NEXT_PUBLIC_SANITY_PROJECT_ID=zxcvbnma
NEXT_PUBLIC_SANITY_DATASET=development
NEXT_PUBLIC_SANITY_API_VERSION=2025-02-11
NEXT_PUBLIC_SANITY_STUDIO_URL=http://localhost:3333

NEXT_PUBLIC_SANITY_DEBUG_STEGA=false
NEXT_PUBLIC_DEBUG_SANITY_NO_CACHE=false

SANITY_REVALIDATE_SECRET=
SANITY_API_READ_TOKEN=

SANITY_STUDIO_SECRET_KEY=

160 changes: 160 additions & 0 deletions apps/web/config/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/**
* Config for your Next application.
* Do not import this into your Sanity application.
*
* For Vercel env vars, see: https://vercel.com/docs/projects/environment-variables/system-environment-variables
*/

const envBaseUrl = process.env.NEXT_PUBLIC_BASE_URL;
const siteDomainAsBaseUrl = process.env.NEXT_PUBLIC_SITE_DOMAIN
? `https://${process.env.NEXT_PUBLIC_SITE_DOMAIN}`
: undefined;
const vercelUrlAsBaseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: undefined;

const baseUrl = envBaseUrl ?? siteDomainAsBaseUrl ?? vercelUrlAsBaseUrl ?? '';

const sanityStudioUrl = checkValue(
process.env.NEXT_PUBLIC_SANITY_STUDIO_URL,
'NEXT_PUBLIC_SANITY_STUDIO_URL',
'',
);

export type AppConfig = typeof appConfig;

export const appConfig = {
siteDomain: process.env.NEXT_PUBLIC_SITE_DOMAIN ?? process.env.VERCEL_URL ?? '',
baseUrl: envBaseUrl ?? siteDomainAsBaseUrl ?? vercelUrlAsBaseUrl ?? '',

apiBaseUrl: assertValue(process.env.NEXT_PUBLIC_API_BASE_URL, 'NEXT_PUBLIC_API_BASE_URL'),

// Not exposed to the front-end, used solely by the server
dataSyncAuthToken: checkServerOnlyValue(
process.env.SANITY_API_SYNC_AUTH_TOKEN,
'SANITY_API_SYNC_AUTH_TOKEN',
'',
),

metadata: {
noIndex: asBool(process.env.NEXT_PUBLIC_NO_INDEX, process.env.NODE_ENV !== 'production'),
},

security: {
cors: {
paths: ['api/*'],
allowedMethods: ['*'],
allowedOrigins: [baseUrl, sanityStudioUrl],
allowedHeaders: [
// Normal defaults included automatically
'X-Built-By',
'X-Redirected-From',
'X-Redirected-By',
'X-Redirects-Retrieved',
'sanity-webhook-signature',
],
},
},

sanity: {
projectId: assertValue(
process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
'NEXT_PUBLIC_SANITY_PROJECT_ID',
),

dataset: assertValue(process.env.NEXT_PUBLIC_SANITY_DATASET, 'NEXT_PUBLIC_SANITY_DATASET'),

workspace:
process.env.NEXT_PUBLIC_SANITY_WORKSPACE ?? process.env.NEXT_PUBLIC_SANITY_DATASET,

apiVersion: process.env.NEXT_PUBLIC_SANITY_API_VERSION ?? '2024-04-26',

studioUrl: sanityStudioUrl,

revalidateSecret: checkServerOnlyValue(
process.env.SANITY_REVALIDATE_SECRET,
'SANITY_REVALIDATE_SECRET',
'',
),

// Not exposed to the front-end, used solely by the server
readToken: checkServerOnlyValue(
process.env.SANITY_API_READ_TOKEN,
'SANITY_API_READ_TOKEN',
'',
),
dataSyncToken: checkServerOnlyValue(
process.env.SANITY_API_DATA_SYNC_WRITE_TOKEN,
'SANITY_API_DATA_SYNC_WRITE_TOKEN',
'',
),

debugStega: asBool(process.env.NEXT_PUBLIC_SANITY_DEBUG_STEGA, false),
},
debug: {
// Don't cache any requests to Sanity in Next's Data Cache (i.e. when using `fetch()` with a Sanity endpoint)
sanityNoCache: asBool(
process.env.NEXT_PUBLIC_DEBUG_SANITY_NO_CACHE,
process.env.NODE_ENV === 'development',
),
},
};

/**
* Ensure the value is always a boolean, no matter what is in .env.
* If "true" or "false" are in .env, get the corresponding boolean's TRUE or FALSE.
*/
function asBool(value?: string | boolean, defaultVal = true) {
if (value === 'false' || value === false) {
return false;
}
if (value === 'true' || value === true) {
return true;
}

return defaultVal;
}

/**
* Ensure the value is always an int, no matter what is in .env.
* If value in .env is an integer as a string, get an integer, otherwise get the default value specified.
*/
function _asInt(value?: string, defaultVal?: number) {
if (value) {
return Number.parseInt(value);
}

return defaultVal ?? undefined;
}

function assertValue<T>(v: T | undefined, variableName: string): T {
if (v === undefined) {
throw new Error(`Missing environment variable: ${variableName}`);
}

return v;
}

function checkValue<T>(v: T | undefined, variableName: string, fallback: T): T {
if (v === undefined) {
console.warn(`Missing environment variable: ${variableName}`);

return fallback;
}

return v;
}

function checkServerOnlyValue<T>(v: T | undefined, variableName: string, fallback: T): T {
if (typeof window === 'undefined') {
return checkValue(v, variableName, fallback);
}

if (v !== undefined) {
console.warn(
`Potential environment variable leak. Environment variable ${variableName} detected on client, but set in config as server only`,
);
}

return fallback;
}
9 changes: 8 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"generate:types": "npx sanity typegen generate",
"generate:types": "pnpm sanity typegen generate",
"lint": "next lint && pnpm prettier",
"lint:fix": "next lint --fix && pnpm prettier:fix",
"prettier": "prettier --check .",
Expand All @@ -29,12 +29,18 @@
"typecheck": "tsc --project ./tsconfig.json --noEmit"
},
"dependencies": {
"@next/third-parties": "15.1.7",
"@pkg/common": "workspace:*",
"@pkg/sanity-toolkit": "workspace:*",
"@pkg/utilities": "workspace:*",
"next-sanity": "9.8.49",
"next": "15.1.7",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "3.2.0",
"@sanity/react-loader": "1.10.41",
"@sanity/types": "3.76.1",
"@types/node": "22.13.4",
"@types/react": "19.0.10",
Expand All @@ -45,6 +51,7 @@
"eslint-config-next": "15.1.7",
"postcss": "8.5.2",
"prettier": ">=3.4.2 <5.0.0",
"sanity": "3.76.1",
"tailwindcss": "3.4.17",
"typescript": "5.7.3",
"vitest": "3.0.6"
Expand Down
2 changes: 1 addition & 1 deletion apps/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./src",
"target": "esnext",
"module": "esnext",
"moduleResolution": "bundler",
Expand All @@ -23,6 +22,7 @@
}
],
"paths": {
"@/config/*": ["./config/*"],
"@/*": ["./src/*"]
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DOCUMENT, SINGLETON } from '@pkg/common/constants/schemaTypes';
import { DOCUMENT, SINGLETON } from '../constants/schemaTypes';

/**
* Document Types that should be shown in Internal Link fields, e.g. in Header Nav Menu.
Expand Down
Loading
Loading