Skip to content
Draft
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
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ npm --prefix admin run lint:fix # Auto-fix Admin
npm --prefix site run lint:fix # Auto-fix Site (includes stylelint)
```

These commands auto-fix import sorting, remove unused imports, and apply Prettier formatting. The root `lint:fix` also formats config files outside the packages.
These commands auto-fix import sorting, remove unused imports, and apply Prettier formatting. The root `lint:fix` also formats files outside the packages (repository-root config files, `site-configs/`, `.github/`, `.digitalocean/`, ...).

### Testing (API only currently)

Expand Down Expand Up @@ -153,6 +153,8 @@ The `site-configs/` directory manages site configurations, compiled into environ
- stylelint for Site SCSS/CSS
- knip for unused exports detection

Each package's `lint:eslint` covers `src/`, all JSON files, and the package-root `.ts`/`.mts`/`.js`/`.mjs`/`.cjs` files (`next.config.mjs`, `vite.config.mts`, `eslint.config.mjs`, ...). Because those config files are not part of the TypeScript project, each `eslint.config.mjs` disables the project service for them and allows importing devDependencies.

### Environment Files

- `.env` - Development defaults
Expand Down
2 changes: 1 addition & 1 deletion admin/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type CodegenConfig } from "@graphql-codegen/cli";
import type { CodegenConfig } from "@graphql-codegen/cli";
import { readFileSync } from "fs";
import { buildSchema } from "graphql";

Expand Down
28 changes: 27 additions & 1 deletion admin/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,34 @@ import eslintConfigReact from "@dextinity/eslint-config/react.js";
import { defineConfig, globalIgnores } from "eslint/config";

const config = defineConfig([
globalIgnores(["schema.json", "src/fragmentTypes.json", "dist/**", "src/**/*.generated.ts", "src/**/generated/**", "block-meta.json", "**/package-lock.json", "lang/**", "lang-compiled/**", "lang-extracted/**"]),
globalIgnores([
"schema.json",
"src/fragmentTypes.json",
"dist/**",
"src/**/*.generated.ts",
"src/**/generated/**",
"block-meta.json",
"**/package-lock.json",
"lang/**",
"lang-compiled/**",
"lang-extracted/**",
]),
...eslintConfigReact,
{
// Config files in the package root are dev-only tooling and not part of the TypeScript project,
// so they can't be parsed by the project service and may import devDependencies.
files: ["*.mjs", "*.cjs", "*.mts", "*.config.ts", "*.config.js"],
languageOptions: {
parserOptions: {
projectService: false,
project: null,
programs: null,
},
},
rules: {
"import/no-extraneous-dependencies": ["error", { devDependencies: true }],
},
},
]);

export default config;
4 changes: 2 additions & 2 deletions admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
"prelint": "npm run intl:compile && run-p gql:types generate-block-types",
"lint": "npm run admin-generator && run-p -l lint:{eslint,knip,prettier,tsc} intl:extract",
"lint:ci": "npm run lint",
"lint:eslint": "eslint --max-warnings 0 src/ '**/*.json' --no-warn-ignored",
"lint:eslint": "eslint --max-warnings 0 src/ '*.{ts,mts,js,mjs,cjs}' '**/*.json' --no-warn-ignored",
"lint:fix": "run-p lint:fix:{eslint,prettier}",
"lint:fix:eslint": "npm run lint:eslint -- --fix",
"lint:fix:prettier": "npm run lint:prettier -- --write",
"lint:knip": "knip --exports --files --dependencies --tags=-knipignore",
"lint:prettier": "npx prettier --check '*.{ts,js,json,md,yml,yaml}'",
"lint:prettier": "npx prettier --check '*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}'",
"lint:tsc": "tsc --project .",
"preview": "npm run build && vite preview",
"serve": "node server",
Expand Down
28 changes: 26 additions & 2 deletions api/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,31 @@ import eslintConfigNestJs from "@dextinity/eslint-config/nestjs.js";
import { defineConfig, globalIgnores } from "eslint/config";

const config = defineConfig([
globalIgnores(["src/db/migrations/**", "dist/**", "src/**/*.generated.ts", "src/**/generated", "block-meta.json", "package-lock.json", "uploads/**"]),
globalIgnores([
"src/db/migrations/**",
"dist/**",
"src/**/*.generated.ts",
"src/**/generated",
"block-meta.json",
"package-lock.json",
"uploads/**",
]),
...eslintConfigNestJs,
{
// Config files in the package root are dev-only tooling and not part of the TypeScript project,
// so they can't be parsed by the project service and may import devDependencies.
files: ["*.mjs", "*.cjs", "*.mts", "*.config.ts", "*.config.js"],
languageOptions: {
parserOptions: {
projectService: false,
project: null,
programs: null,
},
},
rules: {
"import/no-extraneous-dependencies": ["error", { devDependencies: true }],
},
},
{
rules: {
"no-restricted-imports": [
Expand All @@ -12,7 +35,8 @@ const config = defineConfig([
paths: [
{
name: "@faker-js/faker",
message: "Import faker from '@src/db/fixtures/faker' instead, which lazily loads @faker-js/faker so it isn't pulled into memory on every API startup.",
message:
"Import faker from '@src/db/fixtures/faker' instead, which lazily loads @faker-js/faker so it isn't pulled into memory on every API startup.",
},
],
},
Expand Down
4 changes: 2 additions & 2 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
"lint": "npm run api-generator && run-p -l lint:{eslint,knip,prettier,tsc,api-can-start}",
"lint:api-can-start": "MIKRO_ORM_NO_CONNECT=true PRIVATE_SITE_CONFIGS=$(echo '[]' | base64) dotenv -e ../.env -- ts-node --transpile-only -r tsconfig-paths/register src/console.ts --help",
"lint:ci": "npm run lint && npm run lint:generated-files-not-modified",
"lint:eslint": "eslint --max-warnings 0 src/ '**/*.json' --no-warn-ignored",
"lint:eslint": "eslint --max-warnings 0 src/ '*.{ts,mts,js,mjs,cjs}' '**/*.json' --no-warn-ignored",
"lint:fix": "run-p lint:fix:{eslint,prettier}",
"lint:fix:eslint": "npm run lint:eslint -- --fix",
"lint:fix:prettier": "npm run lint:prettier -- --write",
"lint:generated-files-not-modified": "git diff --exit-code HEAD -- schema.gql block-meta.json",
"lint:knip": "knip --exports --files --dependencies --tags=-knipignore",
"lint:prettier": "npx prettier --check '*.{ts,js,json,md,yml,yaml}'",
"lint:prettier": "npx prettier --check '*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}'",
"lint:tsc": "tsc --project ./tsconfig.lint.json",
"mikro-orm": "dotenv -e .env.secrets -e .env.local -e .env -e .env.site-configs -- mikro-orm",
"repl": "npm run start -- --watch --entryFile repl",
Expand Down
15 changes: 15 additions & 0 deletions create-app/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ import { defineConfig, globalIgnores } from "eslint/config";
const config = defineConfig([
globalIgnores(["src/db/migrations/**", "dist/**", "src/**/*.generated.ts", "package-lock.json"]),
...eslintConfigNestJs,
{
// Config files in the package root are dev-only tooling and not part of the TypeScript project,
// so they can't be parsed by the project service and may import devDependencies.
files: ["*.mjs", "*.cjs", "*.mts", "*.config.ts", "*.config.js"],
languageOptions: {
parserOptions: {
projectService: false,
project: null,
programs: null,
},
},
rules: {
"import/no-extraneous-dependencies": ["error", { devDependencies: true }],
},
},
{
rules: {
"@dextinity/no-other-module-relative-import": "off",
Expand Down
4 changes: 2 additions & 2 deletions create-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
"build": "tsc --project tsconfig.json",
"clean": "rimraf lib",
"lint": "run-p -l lint:{eslint,knip,prettier,tsc}",
"lint:eslint": "eslint --max-warnings 0 src/ '**/*.json' --no-warn-ignored",
"lint:eslint": "eslint --max-warnings 0 src/ '*.{ts,mts,js,mjs,cjs}' '**/*.json' --no-warn-ignored",
"lint:knip": "knip --exports --files --dependencies --tags=-knipignore",
"lint:prettier": "npx prettier --check '*.{ts,js,json,md,yml,yaml}'",
"lint:prettier": "npx prettier --check '*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}'",
"lint:tsc": "tsc --project ./tsconfig.json",
"prepublishOnly": "npm run lint && npm run build",
"prestart": "npm run clean",
Expand Down
13 changes: 8 additions & 5 deletions lint-staged.config.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
module.exports = {
"admin/src/**/*.{ts,tsx,js,jsx,json,css,md}": () => ["npm --prefix admin run lint:eslint", "npm --prefix admin run lint:knip"],
"admin/**/*.{ts,tsx}": () => ["npm --prefix admin run lint:tsc", "npm --prefix admin run intl:extract"],
"admin/*.{ts,js,json,md,yml,yaml}": () => "npm --prefix admin run lint:prettier",
"admin/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}": () => ["npm --prefix admin run lint:prettier", "npm --prefix admin run lint:eslint"],
"api/src/**/*.{ts,tsx,js,jsx,json,css,md}": () => ["npm --prefix api run lint:eslint", "npm --prefix api run lint:knip"],
"api/**/*.{ts,tsx}": () => "npm --prefix api run lint:tsc",
"api/*.{ts,js,json,md,yml,yaml}": () => "npm --prefix api run lint:prettier",
"api/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}": () => ["npm --prefix api run lint:prettier", "npm --prefix api run lint:eslint"],
"site/src/**/*.{ts,tsx,js,jsx,json,css,md}": () => ["npm --prefix site run lint:eslint", "npm --prefix site run lint:knip"],
"site/**/*.{ts,tsx}": () => ["npm --prefix site run lint:tsc", "npm --prefix site run intl:extract"],
"site/*.{ts,js,json,md,yml,yaml}": () => "npm --prefix site run lint:prettier",
"site/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}": () => ["npm --prefix site run lint:prettier", "npm --prefix site run lint:eslint"],
"site/src/**/*.{css,scss}": () => "npm --prefix site run lint:style",
"create-app/src/**/*.{ts,tsx,js,jsx,json,css,scss,md}": () => "npm --prefix create-app run lint:eslint",
"create-app/**/*.{ts,tsx}": () => "npm --prefix create-app run lint:tsc",
"create-app/*.{ts,js,json,md,yml,yaml}": () => "npm --prefix create-app run lint:prettier",
"./**/*.{js,json,md,yml,yaml}": () => "npm run lint:root",
"create-app/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}": () => [
"npm --prefix create-app run lint:prettier",
"npm --prefix create-app run lint:eslint",
],
"./**/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}": () => "npm run lint:root",
};
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
"lint:admin": "npm --prefix admin run lint",
"lint:api": "npm --prefix api run lint",
"lint:ci": "npm run lint:root",
"lint:create-app": "npm --prefix api run lint",
"lint:create-app": "npm --prefix create-app run lint",
"lint:fix": "run-p -l lint:fix:{admin,api,root,site}",
"lint:fix:admin": "npm --prefix admin run lint:fix",
"lint:fix:api": "npm --prefix api run lint:fix",
"lint:fix:root": "npx prettier --write './!(admin|api|site|create-app)/**/*.{js,json,md,yml,yaml}'",
"lint:fix:root": "npx prettier --write '*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}' './{site-configs,!(admin|api|site|create-app)}/**/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}'",
"lint:fix:site": "npm --prefix site run lint:fix",
"lint:knip": "run-p -l lint:knip:{admin,api,site}",
"lint:knip:admin": "npm --prefix admin run lint:knip",
"lint:knip:api": "npm --prefix api run lint:knip",
"lint:knip:site": "npm --prefix site run lint:knip",
"lint:root": "npx prettier --check './!(admin|api|site|create-app)/**/*.{js,json,md,yml,yaml}'",
"lint:root": "npx prettier --check '*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}' './{site-configs,!(admin|api|site|create-app)}/**/*.{ts,mts,js,mjs,cjs,json,md,yml,yaml}'",
"lint:site": "npm --prefix site run lint",
"test:ci": "run-p test:ci:*",
"test:ci:api": "npm --prefix api run test:ci",
Expand Down
6 changes: 3 additions & 3 deletions site-configs/site-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ export type GetSiteConfig = (env: Environment) => SiteConfig;

const isValidEnvironment = (env: string): env is Environment => {
return ["local", "dev", "test", "staging", "prod"].includes(env);
}
};

// Called by `npx @dextinity/cli inject-site-configs`
const getSiteConfigs = async (env: string): Promise<SiteConfig[]> => {
if(!isValidEnvironment(env)) {
if (!isValidEnvironment(env)) {
throw new Error(`Invalid environment: ${env}`);
}

const imports = [main, secondary];
return imports.map((getSiteConfig) => {
return getSiteConfig(env);
Expand Down
10 changes: 7 additions & 3 deletions site/cache-handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable no-console */
import { Redis } from "ioredis";
import { LRUCache } from "lru-cache";
import type { CacheHandler as NextCacheHandler, CacheHandlerValue } from "next/dist/server/lib/incremental-cache";
Expand Down Expand Up @@ -42,7 +41,10 @@ let isFallbackInUse = false;
function parseBodyForGqlError(body: string) {
try {
const decodedBody = Buffer.from(body, "base64").toString("utf-8");
if (!decodedBody.startsWith("{")) return null; // Not a JSON response, ignore
// Not a JSON response, ignore
if (!decodedBody.startsWith("{")) {
return null;
}
return JSON.parse(decodedBody);
} catch (error) {
console.error("CacheHandler.parseBodyForGqlError error", error);
Expand Down Expand Up @@ -117,7 +119,9 @@ export default class CacheHandler {
}

async revalidateTag(tags: string | string[]): Promise<void> {
if (tags.length === 0) return;
if (tags.length === 0) {
return;
}
console.warn("CacheHandler.revalidateTag", tags);
}
}
2 changes: 1 addition & 1 deletion site/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type CodegenConfig } from "@graphql-codegen/cli";
import type { CodegenConfig } from "@graphql-codegen/cli";
import { readFileSync } from "fs";
import { buildSchema } from "graphql";

Expand Down
25 changes: 21 additions & 4 deletions site/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ import { defineConfig, globalIgnores } from "eslint/config";
const docsLink = "https://cms-docs.dextinity.com/docs/faqs/environment-variables-in-site";

const config = defineConfig([
globalIgnores(["**/**/*.generated.ts", "dist/**", "lang/**", "lang-compiled/**", "lang-extracted/**", ".next/**", "public/**", "block-meta.json", "package-lock.json"]),
globalIgnores([
"**/**/*.generated.ts",
"dist/**",
"lang/**",
"lang-compiled/**",
"lang-extracted/**",
".next/**",
"public/**",
"block-meta.json",
"package-lock.json",
]),
...eslintConfigNextJs,
{
rules: {
Expand All @@ -19,20 +29,27 @@ const config = defineConfig([
},
},
{
files: ["next.config.*"],
// Config files in the package root are dev-only tooling and not part of the TypeScript project,
// so they can't be parsed by the project service and may import devDependencies.
files: ["*.mjs", "*.cjs", "*.mts", "*.config.ts", "*.config.js"],
languageOptions: {
parserOptions: {
projectService: false,
project: null,
programs: null,
},
},
rules: {
"import/no-extraneous-dependencies": ["error", { devDependencies: true }],
},
},
{
files: ["next.config.*"],
rules: {
"no-restricted-syntax": [
"error",
{
selector:
"MemberExpression[object.type='MemberExpression'][object.object.name='process'][object.property.name='env']",
selector: "MemberExpression[object.type='MemberExpression'][object.object.name='process'][object.property.name='env']",
message: `Usage of process.env in next.config is not allowed. Use site configs or runtime configuration instead. See ${docsLink}`,
},
],
Expand Down
4 changes: 2 additions & 2 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
"prelint": "npm run intl:compile && run-p gql:types generate-block-types css:types",
"lint": "run-p -l lint:{eslint,knip,prettier,style,tsc} intl:extract",
"lint:ci": "npm run lint",
"lint:eslint": "eslint --max-warnings 0 src/ '**/*.json' --no-warn-ignored",
"lint:eslint": "eslint --max-warnings 0 src/ '*.{ts,mts,js,mjs,cjs}' '**/*.json' --no-warn-ignored",
"lint:fix": "run-p lint:fix:{eslint,prettier,style}",
"lint:fix:eslint": "npm run lint:eslint -- --fix",
"lint:fix:prettier": "npm run lint:prettier -- --write",
"lint:fix:style": "npm run lint:style -- --fix",
"lint:knip": "knip --exports --files --dependencies --tags=-knipignore",
"lint:prettier": "npx prettier --check '*.{ts,js,json,md,yml,yaml,css,scss}'",
"lint:prettier": "npx prettier --check '*.{ts,mts,js,mjs,cjs,json,md,yml,yaml,css,scss}'",
"lint:style": "npx stylelint '**/*.{css,scss}'",
"lint:tsc": "npx next typegen && tsc --project .",
"serve": "NODE_ENV=production node dist/server.js",
Expand Down
2 changes: 2 additions & 0 deletions site/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const handle = app.getRequestHandler();

app.prepare().then(() => {
if (process.env.TRACING_ENABLED === "1") {
// Loaded lazily via require so tracing is only initialized when enabled.
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./tracing");
}
createServer(async (req, res) => {
Expand Down