Compare commits
14
Commits
3f43a62243
..
v1.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01a297884a | ||
|
|
01196b0843 | ||
|
|
48bdd6f2e6 | ||
|
|
2d003a2101 | ||
|
|
2f5d2b6e09 | ||
|
|
f31afb5318 | ||
|
|
b12eaeef82 | ||
|
|
c6905d3865 | ||
|
|
8876b38f0a | ||
|
|
02280d0f42 | ||
|
|
f43bb234ab | ||
|
|
dacc4cadfd | ||
|
|
65f118c918 | ||
|
|
cc458332d7 |
No files matched your search
@@ -1,10 +1,5 @@
|
|||||||
name: CI
|
name: CI
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- "feat/**"
|
|
||||||
- "fix/**"
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@@ -13,7 +8,7 @@ jobs:
|
|||||||
check:
|
check:
|
||||||
runs-on: shell
|
runs-on: shell
|
||||||
steps:
|
steps:
|
||||||
- name: Typecheck, lint, security audit, and test
|
- name: Typecheck, lint, and test
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
WORK="$(mktemp -d /var/tmp/epicnext-ci.XXXXXX)"
|
WORK="$(mktemp -d /var/tmp/epicnext-ci.XXXXXX)"
|
||||||
@@ -38,10 +33,8 @@ jobs:
|
|||||||
export ARGON2_MEMORY_SIZE=1024
|
export ARGON2_MEMORY_SIZE=1024
|
||||||
export ARGON2_ITERATIONS=1
|
export ARGON2_ITERATIONS=1
|
||||||
export BCRYPT_ROUNDS=4
|
export BCRYPT_ROUNDS=4
|
||||||
export DATABASE_URL="mysql://ci:[email protected]:3306/ci"
|
|
||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
pnpm prisma:generate
|
pnpm prisma:generate
|
||||||
pnpm audit --audit-level=high || echo "WARNING: pnpm audit found high/critical vulnerabilities"
|
|
||||||
pnpm biome:lint
|
pnpm biome:lint
|
||||||
pnpm typecheck
|
pnpm typecheck
|
||||||
pnpm test
|
pnpm test
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
name: Renovate
|
name: Renovate
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 5 * * *" # every day at 05:00
|
- cron: "0 5 * * *" # Every day at 05:00 UTC
|
||||||
workflow_dispatch: # manual trigger
|
workflow_dispatch: # Manual trigger
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
renovate:
|
renovate:
|
||||||
@@ -11,7 +11,13 @@ jobs:
|
|||||||
- name: Self-hosted Renovate
|
- name: Self-hosted Renovate
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Zorg ervoor dat de cache-map lokaal bestaat vóór Docker start
|
||||||
|
# Dit voorkomt dat Docker de map automatisch als 'root' aanmaakt
|
||||||
|
mkdir -p /var/tmp/renovate-cache
|
||||||
|
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
|
--user "$(id -u):$(id -g)" \
|
||||||
-e RENOVATE_TOKEN="${{ secrets.RENOVATE_TOKEN }}" \
|
-e RENOVATE_TOKEN="${{ secrets.RENOVATE_TOKEN }}" \
|
||||||
-e RENOVATE_AUTODISCOVER=false \
|
-e RENOVATE_AUTODISCOVER=false \
|
||||||
-e RENOVATE_REPOSITORIES="${{ gitea.repository }}" \
|
-e RENOVATE_REPOSITORIES="${{ gitea.repository }}" \
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.5.5/schema.json",
|
"$schema": "https://biomejs.dev",
|
||||||
"vcs": {
|
"vcs": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"clientKind": "git",
|
"clientKind": "git",
|
||||||
|
|||||||
+27
-1
@@ -1,4 +1,7 @@
|
|||||||
import js from "@eslint/js";
|
import js from "@eslint/js";
|
||||||
|
import nextPlugin from "@next/eslint-plugin-next";
|
||||||
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
|
import security from "eslint-plugin-security";
|
||||||
import unusedImports from "eslint-plugin-unused-imports";
|
import unusedImports from "eslint-plugin-unused-imports";
|
||||||
import tseslint from "typescript-eslint";
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
@@ -12,9 +15,32 @@ export default tseslint.config(
|
|||||||
files: ["src/**/*.{ts,tsx}", "pages/**/*.{ts,tsx}", "app/**/*.{ts,tsx}"],
|
files: ["src/**/*.{ts,tsx}", "pages/**/*.{ts,tsx}", "app/**/*.{ts,tsx}"],
|
||||||
plugins: {
|
plugins: {
|
||||||
"unused-imports": unusedImports,
|
"unused-imports": unusedImports,
|
||||||
|
security: security,
|
||||||
|
"react-hooks": reactHooks,
|
||||||
|
"@next/next": nextPlugin,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"unused-imports/no-unused-vars": "error",
|
// Laad automatisch alle aanbevolen beveiligings- en framework-regels in
|
||||||
|
...security.configs.recommended.rules,
|
||||||
|
...reactHooks.configs.recommended.rules,
|
||||||
|
...nextPlugin.configs.recommended.rules,
|
||||||
|
|
||||||
|
// Zorg dat variabelen die beginnen met een underscore (_req) genegeerd worden
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
argsIgnorePattern: "^_",
|
||||||
|
varsIgnorePattern: "^_",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"unused-imports/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
argsIgnorePattern: "^_",
|
||||||
|
varsIgnorePattern: "^_",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
"no-console": "warn",
|
"no-console": "warn",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
+26
-22
@@ -11,7 +11,7 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"prisma:generate": "prisma generate",
|
"prisma:generate": "prisma generate",
|
||||||
"typecheck": "tsc --noEmit --incremental false",
|
"typecheck": "tsc6 --noEmit --incremental false",
|
||||||
"biome:check": "biome check --write .",
|
"biome:check": "biome check --write .",
|
||||||
"biome:lint": "biome lint .",
|
"biome:lint": "biome lint .",
|
||||||
"biome:format": "biome format --write .",
|
"biome:format": "biome format --write .",
|
||||||
@@ -43,11 +43,11 @@
|
|||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@hookform/resolvers": "^5.4.0",
|
"@hookform/resolvers": "^5.5.7",
|
||||||
"@prisma/adapter-mariadb": "^7.9.0",
|
"@prisma/adapter-mariadb": "^7.9.1",
|
||||||
"@prisma/client": "^7.9.0",
|
"@prisma/client": "^7.9.1",
|
||||||
"@sentry/nextjs": "^10.67.0",
|
"@sentry/nextjs": "^10.68.0",
|
||||||
"@tanstack/react-virtual": "^3.14.7",
|
"@tanstack/react-virtual": "^3.14.8",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@@ -60,21 +60,21 @@
|
|||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lenis": "^1.3.25",
|
"lenis": "^1.3.25",
|
||||||
"lucide-react": "^1.25.0",
|
"lucide-react": "^1.27.0",
|
||||||
"lzma": "^2.3.2",
|
"lzma": "^2.3.2",
|
||||||
"music-metadata": "^11.14.0",
|
"music-metadata": "^11.14.0",
|
||||||
"mysql2": "^3.23.1",
|
"mysql2": "^3.23.2",
|
||||||
"next": "^16.2.11",
|
"next": "^16.2.12",
|
||||||
"next-auth": "5.0.0-beta.32",
|
"next-auth": "5.0.0-beta.32",
|
||||||
"next-intl": "^4.13.3",
|
"next-intl": "^4.13.4",
|
||||||
"next-view-transitions": "^0.3.5",
|
"next-view-transitions": "^0.3.5",
|
||||||
"nodemailer": "^9.0.3",
|
"nodemailer": "^9.0.3",
|
||||||
"otplib": "^13.4.1",
|
"otplib": "^13.4.1",
|
||||||
"pino": "^10.3.1",
|
"pino": "^10.3.1",
|
||||||
"react": "^19.2.8",
|
"react": "^19.2.8",
|
||||||
"react-dom": "^19.2.8",
|
"react-dom": "^19.2.8",
|
||||||
"react-hook-form": "^7.82.0",
|
"react-hook-form": "^7.83.0",
|
||||||
"resend": "^6.18.0",
|
"resend": "^6.18.1",
|
||||||
"sanitize-html": "^2.17.6",
|
"sanitize-html": "^2.17.6",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"sharp": "^0.35.3",
|
"sharp": "^0.35.3",
|
||||||
@@ -84,32 +84,36 @@
|
|||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.5.5",
|
"@biomejs/biome": "2.5.6",
|
||||||
"@eslint/js": "10.0.1",
|
"@eslint/js": "10.0.1",
|
||||||
"@lhci/cli": "^0.15.1",
|
"@lhci/cli": "^0.15.1",
|
||||||
"@next/bundle-analyzer": "^16.2.11",
|
"@next/bundle-analyzer": "^16.2.12",
|
||||||
"@playwright/test": "1.61.1",
|
"@next/eslint-plugin-next": "^16.2.12",
|
||||||
|
"@playwright/test": "1.62.0",
|
||||||
"@tailwindcss/forms": "^0.5.11",
|
"@tailwindcss/forms": "^0.5.11",
|
||||||
"@tailwindcss/postcss": "^4.3.3",
|
"@tailwindcss/postcss": "^4.3.3",
|
||||||
"@tailwindcss/typography": "^0.5.20",
|
"@tailwindcss/typography": "^0.5.20",
|
||||||
"@types/bcrypt": "^6.0.0",
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/node": "^26.1.1",
|
"@types/node": "^26.1.2",
|
||||||
"@types/nodemailer": "^7.0.12",
|
"@types/nodemailer": "^8.0.1",
|
||||||
"@types/react": "^19.2.17",
|
"@types/react": "^19.2.17",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/sanitize-html": "^2.16.1",
|
"@types/sanitize-html": "^2.16.1",
|
||||||
"@vitest/coverage-v8": "4.1.10",
|
"@vitest/coverage-v8": "4.1.10",
|
||||||
"dotenv": "^17.0.0",
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
|
"dotenv": "^17.4.2",
|
||||||
"eslint": "10.8.0",
|
"eslint": "10.8.0",
|
||||||
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
|
"eslint-plugin-security": "^4.0.1",
|
||||||
"eslint-plugin-unused-imports": "4.4.1",
|
"eslint-plugin-unused-imports": "4.4.1",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"knip": "^6.27.0",
|
"knip": "^6.29.0",
|
||||||
"pino-pretty": "^13.1.3",
|
"pino-pretty": "^13.1.3",
|
||||||
"postcss": "^8.5.21",
|
"postcss": "^8.5.24",
|
||||||
"prisma": "^7.9.0",
|
"prisma": "^7.9.1",
|
||||||
"tailwindcss": "^4.3.3",
|
"tailwindcss": "^4.3.3",
|
||||||
"tsx": "^4.23.1",
|
"tsx": "^4.23.1",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
||||||
"typescript-eslint": "^8.65.0",
|
"typescript-eslint": "^8.65.0",
|
||||||
"vite": "8.1.5",
|
"vite": "8.1.5",
|
||||||
"vitest": "4.1.10"
|
"vitest": "4.1.10"
|
||||||
|
|||||||
Generated
+1558
-1479
File diff suppressed because it is too large.
Load diff
+30
-10
@@ -1,15 +1,35 @@
|
|||||||
onlyBuiltDependencies:
|
# pnpm-workspace.yaml
|
||||||
- esbuild
|
|
||||||
- prisma
|
|
||||||
- "@prisma/client"
|
|
||||||
- "@prisma/engines"
|
|
||||||
- sharp
|
|
||||||
- "@parcel/watcher"
|
|
||||||
- "@swc/core"
|
|
||||||
- "@sentry/cli"
|
|
||||||
- bcrypt
|
|
||||||
|
|
||||||
|
# pnpm v11 vervanger voor onlyBuiltDependencies
|
||||||
|
allowBuilds:
|
||||||
|
esbuild: true
|
||||||
|
prisma: true
|
||||||
|
"@prisma/client": true
|
||||||
|
"@prisma/engines": true
|
||||||
|
sharp: true
|
||||||
|
"@parcel/watcher": true
|
||||||
|
"@swc/core": true
|
||||||
|
"@sentry/cli": true
|
||||||
|
bcrypt: true
|
||||||
|
|
||||||
|
# Al jouw overrides netjes bij elkaar inclusief de nieuwe security patches
|
||||||
overrides:
|
overrides:
|
||||||
|
glob: "^10.4.5"
|
||||||
|
inflight: "npm:lru-cache@^10.2.2"
|
||||||
|
rimraf: "^5.0.7"
|
||||||
|
uuid: "^9.0.1"
|
||||||
fast-uri: "^3.1.3"
|
fast-uri: "^3.1.3"
|
||||||
"@hono/node-server": "^1.19.13"
|
"@hono/node-server": "^1.19.13"
|
||||||
postcss: "^8.5.19"
|
postcss: "^8.5.19"
|
||||||
|
# Dwingt alle diepe subdependencies (zoals lhci) naar de veilige tmp-versie
|
||||||
|
tmp: "^0.2.6"
|
||||||
|
# NIEUWE SECURITY PATCHES:
|
||||||
|
sharp: "^0.35.3"
|
||||||
|
brace-expansion: "^5.0.8"
|
||||||
|
|
||||||
|
# Zorgt voor een schone terminal zonder de Next-Auth / Nodemailer waarschuwing
|
||||||
|
peerDependencyRules:
|
||||||
|
allowedVersions:
|
||||||
|
nodemailer: "9.0.3"
|
||||||
|
ignoreMissing:
|
||||||
|
- nodemailer
|
||||||
+40
-114
@@ -1,116 +1,42 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": ["config:recommended", "helpers:disableTypesNodeMajor"],
|
||||||
"config:recommended",
|
"labels": ["dependencies"],
|
||||||
":pinAllExceptPeerDependencies",
|
"rangeStrategy": "bump",
|
||||||
"helpers:disableTypesNodeMajor"
|
"dependencyDashboard": true,
|
||||||
],
|
"dependencyDashboardTitle": "Dependency Dashboard",
|
||||||
"labels": ["dependencies"],
|
"commitMessagePrefix": "chore(deps):",
|
||||||
"rangeStrategy": "bump",
|
"commitMessageAction": "update",
|
||||||
"dependencyDashboard": true,
|
"schedule": ["at any time"],
|
||||||
"dependencyDashboardTitle": "Dependency Dashboard",
|
"timezone": "Europe/Amsterdam",
|
||||||
"commitMessagePrefix": "chore(deps):",
|
"rebaseWhen": "conflicted",
|
||||||
"commitMessageAction": "update",
|
"prCreation": "immediate",
|
||||||
"schedule": ["at any time"],
|
"prConcurrentLimit": 5,
|
||||||
"timezone": "Europe/Amsterdam",
|
"packageRules": [
|
||||||
"rebaseWhen": "conflicted",
|
{
|
||||||
"prCreation": "immediate",
|
"description": "Group all dependency updates into a single PR",
|
||||||
"prConcurrentLimit": 5,
|
"matchPackagePatterns": ["*"],
|
||||||
"packageRules": [
|
"groupName": "All dependencies",
|
||||||
{
|
"groupSlug": "all",
|
||||||
"description": "Group Next.js core and tooling",
|
"automerge": true
|
||||||
"matchPackageNames": ["next", "@next/bundle-analyzer", "next-auth", "next-intl", "next-view-transitions"],
|
},
|
||||||
"groupName": "Next.js",
|
{
|
||||||
"groupSlug": "nextjs"
|
"description": "Major updates need manual review",
|
||||||
},
|
"matchUpdateTypes": ["major"],
|
||||||
{
|
"labels": ["dependencies", "major"],
|
||||||
"description": "Group Prisma packages",
|
"automerge": false,
|
||||||
"matchPackageNames": ["prisma", "@prisma/client", "@prisma/adapter-mariadb"],
|
"assignees": [],
|
||||||
"groupName": "Prisma",
|
"reviewers": []
|
||||||
"groupSlug": "prisma"
|
},
|
||||||
},
|
{
|
||||||
{
|
"description": "Disable updates for engine pins",
|
||||||
"description": "Group React core and types",
|
"matchPackageNames": ["node", "pnpm"],
|
||||||
"matchPackageNames": ["react", "react-dom", "@types/react", "@types/react-dom"],
|
"enabled": false
|
||||||
"groupName": "React",
|
},
|
||||||
"groupSlug": "react"
|
{
|
||||||
},
|
"description": "Disable server-only (abandoned, pinned at 0.0.1)",
|
||||||
{
|
"matchPackageNames": ["server-only"],
|
||||||
"description": "Group Tailwind CSS packages",
|
"enabled": false
|
||||||
"matchPackageNames": ["tailwindcss", "@tailwindcss/postcss", "@tailwindcss/forms", "@tailwindcss/typography", "tailwindcss-animate", "tailwind-merge"],
|
}
|
||||||
"groupName": "Tailwind CSS",
|
]
|
||||||
"groupSlug": "tailwind"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group DnD kit packages",
|
|
||||||
"matchPackageNames": ["@dnd-kit/core", "@dnd-kit/sortable", "@dnd-kit/utilities"],
|
|
||||||
"groupName": "DnD Kit",
|
|
||||||
"groupSlug": "dnd-kit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group Biome with ESLint tooling",
|
|
||||||
"matchPackageNames": ["@biomejs/biome", "eslint", "@eslint/js", "eslint-plugin-unused-imports", "typescript-eslint"],
|
|
||||||
"groupName": "Linting",
|
|
||||||
"groupSlug": "linting"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group TypeScript and types",
|
|
||||||
"matchPackageNames": ["typescript", "typescript-eslint"],
|
|
||||||
"groupName": "TypeScript",
|
|
||||||
"groupSlug": "typescript"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group Vitest and testing packages",
|
|
||||||
"matchPackageNames": ["vitest", "@vitest/coverage-v8", "vite", "@playwright/test"],
|
|
||||||
"groupName": "Testing",
|
|
||||||
"groupSlug": "testing"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group Sentry packages",
|
|
||||||
"matchPackageNames": ["@sentry/nextjs"],
|
|
||||||
"groupName": "Sentry",
|
|
||||||
"groupSlug": "sentry"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group hashing/crypto packages",
|
|
||||||
"matchPackageNames": ["bcrypt", "@types/bcrypt", "hash-wasm", "otplib"],
|
|
||||||
"groupName": "Cryptography",
|
|
||||||
"groupSlug": "crypto"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group hook form packages",
|
|
||||||
"matchPackageNames": ["react-hook-form", "@hookform/resolvers"],
|
|
||||||
"groupName": "React Hook Form",
|
|
||||||
"groupSlug": "react-hook-form"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Automerge minor and patch updates for production deps (already >=1.0.0)",
|
|
||||||
"matchUpdateTypes": ["minor", "patch"],
|
|
||||||
"matchCurrentVersion": ">=1.0.0",
|
|
||||||
"automerge": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Automerge all devDependency updates",
|
|
||||||
"matchDepTypes": ["devDependencies"],
|
|
||||||
"automerge": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Major updates need manual review",
|
|
||||||
"matchUpdateTypes": ["major"],
|
|
||||||
"labels": ["dependencies", "major"],
|
|
||||||
"automerge": false,
|
|
||||||
"assignees": [],
|
|
||||||
"reviewers": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Disable updates for engine pins",
|
|
||||||
"matchPackageNames": ["node", "pnpm"],
|
|
||||||
"enabled": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Disable server-only (abandoned, pinned at 0.0.1)",
|
|
||||||
"matchPackageNames": ["server-only"],
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ export function ClientView({
|
|||||||
window.removeEventListener("touchmove", onTouchMove);
|
window.removeEventListener("touchmove", onTouchMove);
|
||||||
window.removeEventListener("touchend", onEnd);
|
window.removeEventListener("touchend", onEnd);
|
||||||
};
|
};
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: snapPos is a useCallback used intentionally here
|
// biome-ignore lint/correctness/useExhaustiveDependencies: snapPos is a useCallback used intentionally here
|
||||||
}, [dragging, snapPos]);
|
}, [dragging, snapPos]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export function InlineEditor({ pageId, onSaved }: InlineEditorProps) {
|
|||||||
}
|
}
|
||||||
document.addEventListener("keydown", onKeyDown);
|
document.addEventListener("keydown", onKeyDown);
|
||||||
return () => document.removeEventListener("keydown", onKeyDown);
|
return () => document.removeEventListener("keydown", onKeyDown);
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: handleSave is a stable callback from parent
|
// biome-ignore lint/correctness/useExhaustiveDependencies: handleSave is a stable callback from parent
|
||||||
}, [canEdit, isDirty, saving, page, handleSave]);
|
}, [canEdit, isDirty, saving, page, handleSave]);
|
||||||
|
|
||||||
const loadPage = useCallback(
|
const loadPage = useCallback(
|
||||||
|
|||||||
@@ -338,13 +338,13 @@ export function RegisterForm({
|
|||||||
>
|
>
|
||||||
{isPending ? (
|
{isPending ? (
|
||||||
<span className="inline-flex items-center justify-center gap-2">
|
<span className="inline-flex items-center justify-center gap-2">
|
||||||
<svg
|
<svg
|
||||||
className="animate-spin h-4 w-4"
|
className="animate-spin h-4 w-4"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
role="img"
|
role="img"
|
||||||
aria-label="Loading"
|
aria-label="Loading"
|
||||||
>
|
>
|
||||||
<circle
|
<circle
|
||||||
className="opacity-25"
|
className="opacity-25"
|
||||||
cx="12"
|
cx="12"
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import type * as React from "react";
|
|||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Label({ className, htmlFor, ...props }: React.ComponentProps<"label">) {
|
function Label({
|
||||||
|
className,
|
||||||
|
htmlFor,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"label">) {
|
||||||
return (
|
return (
|
||||||
// biome-ignore lint/a11y/noLabelWithoutControl: reusable component, input is associated via htmlFor at usage site
|
// biome-ignore lint/a11y/noLabelWithoutControl: reusable component, input is associated via htmlFor at usage site
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -34,8 +34,12 @@ describe("production deploy workflow", () => {
|
|||||||
const chownCmd = `sudo chown -R "${userVar}:${groupVar}"`;
|
const chownCmd = `sudo chown -R "${userVar}:${groupVar}"`;
|
||||||
expect(toContainLiteral(workflow, chownCmd)).toBe(true);
|
expect(toContainLiteral(workflow, chownCmd)).toBe(true);
|
||||||
const reclaimAt = deployJob.indexOf(chownCmd);
|
const reclaimAt = deployJob.indexOf(chownCmd);
|
||||||
expect(toContainLiteral(deployJob, `git -C "${liveVar}" fetch origin --prune`)).toBe(true);
|
expect(
|
||||||
const fetchAt = deployJob.indexOf(`git -C "${liveVar}" fetch origin --prune`);
|
toContainLiteral(deployJob, `git -C "${liveVar}" fetch origin --prune`),
|
||||||
|
).toBe(true);
|
||||||
|
const fetchAt = deployJob.indexOf(
|
||||||
|
`git -C "${liveVar}" fetch origin --prune`,
|
||||||
|
);
|
||||||
expect(reclaimAt).toBeGreaterThan(-1);
|
expect(reclaimAt).toBeGreaterThan(-1);
|
||||||
expect(fetchAt).toBeGreaterThan(reclaimAt);
|
expect(fetchAt).toBeGreaterThan(reclaimAt);
|
||||||
});
|
});
|
||||||
@@ -53,8 +57,12 @@ describe("production deploy workflow", () => {
|
|||||||
|
|
||||||
it("swaps a built .next artifact during a short service cutover", () => {
|
it("swaps a built .next artifact during a short service cutover", () => {
|
||||||
expect(deployJob).toContain("mv .next .next.prev");
|
expect(deployJob).toContain("mv .next .next.prev");
|
||||||
expect(toContainLiteral(deployJob, `mv "${stageVar}/.next" .next`)).toBe(true);
|
expect(toContainLiteral(deployJob, `mv "${stageVar}/.next" .next`)).toBe(
|
||||||
expect(toContainLiteral(deployJob, `mv "${stageVar}/node_modules" node_modules`)).toBe(true);
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
toContainLiteral(deployJob, `mv "${stageVar}/node_modules" node_modules`),
|
||||||
|
).toBe(true);
|
||||||
expect(deployJob).toContain("Rolling back .next to previous artifact");
|
expect(deployJob).toContain("Rolling back .next to previous artifact");
|
||||||
const buildAt = deployJob.indexOf("pnpm build");
|
const buildAt = deployJob.indexOf("pnpm build");
|
||||||
const stopAt = deployJob.indexOf("pm2 stop next");
|
const stopAt = deployJob.indexOf("pm2 stop next");
|
||||||
@@ -84,7 +92,12 @@ describe("production deploy workflow", () => {
|
|||||||
it("exports APP_VERSION from git for Sentry releases", () => {
|
it("exports APP_VERSION from git for Sentry releases", () => {
|
||||||
const exportCmd = `export APP_VERSION="$(git -C "${liveVar}" rev-parse --short origin/main)"`;
|
const exportCmd = `export APP_VERSION="$(git -C "${liveVar}" rev-parse --short origin/main)"`;
|
||||||
expect(toContainLiteral(workflow, exportCmd)).toBe(true);
|
expect(toContainLiteral(workflow, exportCmd)).toBe(true);
|
||||||
expect(toContainLiteral(workflow, `export NEXT_PUBLIC_APP_VERSION="${appVerVar}"`)).toBe(true);
|
expect(
|
||||||
|
toContainLiteral(
|
||||||
|
workflow,
|
||||||
|
`export NEXT_PUBLIC_APP_VERSION="${appVerVar}"`,
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("runs an HTTP health check before declaring deploy success", () => {
|
it("runs an HTTP health check before declaring deploy success", () => {
|
||||||
|
|||||||
@@ -9,10 +9,23 @@ const mockDb = {} as CurrencyDb;
|
|||||||
|
|
||||||
describe("sendCurrency", () => {
|
describe("sendCurrency", () => {
|
||||||
it("returns false for non-positive amount", async () => {
|
it("returns false for non-positive amount", async () => {
|
||||||
expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", 0)).toBe(false);
|
expect(
|
||||||
expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", -5)).toBe(false);
|
await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", 0),
|
||||||
expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", null)).toBe(false);
|
).toBe(false);
|
||||||
expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", undefined)).toBe(false);
|
expect(
|
||||||
|
await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", -5),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", null),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
await sendCurrency(
|
||||||
|
{ rcon: {} as never, db: mockDb },
|
||||||
|
1,
|
||||||
|
"credits",
|
||||||
|
undefined,
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("delivers credits via RCON", async () => {
|
it("delivers credits via RCON", async () => {
|
||||||
@@ -23,7 +36,10 @@ describe("sendCurrency", () => {
|
|||||||
givePointsGotw: vi.fn(),
|
givePointsGotw: vi.fn(),
|
||||||
};
|
};
|
||||||
const result = await sendCurrency(
|
const result = await sendCurrency(
|
||||||
{ rcon, db: { user: { update: vi.fn() }, usersCurrency: { upsert: vi.fn() } } },
|
{
|
||||||
|
rcon,
|
||||||
|
db: { user: { update: vi.fn() }, usersCurrency: { upsert: vi.fn() } },
|
||||||
|
},
|
||||||
1,
|
1,
|
||||||
"credits",
|
"credits",
|
||||||
100,
|
100,
|
||||||
@@ -43,7 +59,10 @@ describe("sendCurrency", () => {
|
|||||||
const result = await sendCurrency(
|
const result = await sendCurrency(
|
||||||
{
|
{
|
||||||
rcon,
|
rcon,
|
||||||
db: { user: { update: userUpdate }, usersCurrency: { upsert: vi.fn() } },
|
db: {
|
||||||
|
user: { update: userUpdate },
|
||||||
|
usersCurrency: { upsert: vi.fn() },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
1,
|
1,
|
||||||
"credits",
|
"credits",
|
||||||
@@ -64,7 +83,10 @@ describe("sendCurrency", () => {
|
|||||||
givePointsGotw: vi.fn(),
|
givePointsGotw: vi.fn(),
|
||||||
};
|
};
|
||||||
const result = await sendCurrency(
|
const result = await sendCurrency(
|
||||||
{ rcon, db: { user: { update: vi.fn() }, usersCurrency: { upsert: vi.fn() } } },
|
{
|
||||||
|
rcon,
|
||||||
|
db: { user: { update: vi.fn() }, usersCurrency: { upsert: vi.fn() } },
|
||||||
|
},
|
||||||
1,
|
1,
|
||||||
"duckets",
|
"duckets",
|
||||||
50,
|
50,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
"ignoreDeprecations": "6.0",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user