├── .dockerignore
├── hosts
├── nginx
├── certs
│ ├── example
│ │ ├── live
│ │ │ ├── local.mproske.com
│ │ │ │ ├── cert.pem
│ │ │ │ ├── chain.pem
│ │ │ │ ├── privkey.pem
│ │ │ │ ├── fullchain.pem
│ │ │ │ └── README
│ │ │ └── README
│ │ ├── archive
│ │ │ └── local.mproske.com
│ │ │ │ ├── privkey1.pem
│ │ │ │ ├── cert1.pem
│ │ │ │ ├── chain1.pem
│ │ │ │ └── fullchain1.pem
│ │ └── dhparam-2048.pem
│ ├── README.md
│ ├── get-wildcard-cert.sh
│ └── get-wildcard-cert-windows.sh
├── .gitignore
├── Dockerfile
├── nginx.conf
├── ssl.conf
├── headers.conf
└── sites-enabled
│ └── default.conf
├── next-js-app
├── jsconfig.json
├── public
│ ├── favicon.ico
│ ├── img
│ │ ├── fastblob.gif
│ │ └── slowblob.gif
│ ├── vercel.svg
│ ├── thirteen.svg
│ └── next.svg
├── src
│ ├── pages
│ │ ├── _app.js
│ │ ├── api
│ │ │ └── hello.js
│ │ ├── _document.js
│ │ └── index.js
│ ├── lib
│ │ └── postgres.js
│ ├── components
│ │ └── Blob.js
│ └── styles
│ │ ├── globals.css
│ │ └── Home.module.css
├── .gitignore
├── next.config.js
├── package.json
├── dev.Dockerfile
├── prod-without-multistage.Dockerfile
├── prod.Dockerfile
└── pnpm-lock.yaml
├── next-ts-app
├── public
│ ├── favicon.ico
│ ├── img
│ │ ├── fastblob.gif
│ │ └── slowblob.gif
│ ├── vercel.svg
│ ├── thirteen.svg
│ └── next.svg
├── src
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── api
│ │ │ └── hello.ts
│ │ └── index.tsx
│ ├── lib
│ │ └── postgres.ts
│ ├── components
│ │ └── Blob.tsx
│ └── styles
│ │ ├── globals.css
│ │ └── Home.module.css
├── package.json
├── next.config.js
├── .gitignore
├── tsconfig.json
├── dev.Dockerfile
├── prod-without-multistage.Dockerfile
├── prod.Dockerfile
└── pnpm-lock.yaml
├── .vscode
├── extensions.json
└── settings.json
├── postgres
├── dev.Dockerfile
└── data.sql
├── .gitignore
├── prod.sh
├── prod-without-multistage.sh
├── dev.sh
├── .env
├── package.json
├── eslint.config.mjs
├── docker-compose.prod.yml
├── docker-compose.prod-without-multistage.yml
├── docker-compose.dev.yml
└── README.md
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/hosts:
--------------------------------------------------------------------------------
1 | 127.0.0.1 local.mproske.com
2 |
--------------------------------------------------------------------------------
/nginx/certs/example/live/local.mproske.com/cert.pem:
--------------------------------------------------------------------------------
1 | ../../archive/local.mproske.com/cert1.pem
--------------------------------------------------------------------------------
/next-js-app/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "."
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/nginx/certs/example/live/local.mproske.com/chain.pem:
--------------------------------------------------------------------------------
1 | ../../archive/local.mproske.com/chain1.pem
--------------------------------------------------------------------------------
/nginx/certs/example/live/local.mproske.com/privkey.pem:
--------------------------------------------------------------------------------
1 | ../../archive/local.mproske.com/privkey1.pem
--------------------------------------------------------------------------------
/nginx/certs/example/live/local.mproske.com/fullchain.pem:
--------------------------------------------------------------------------------
1 | ../../archive/local.mproske.com/fullchain1.pem
--------------------------------------------------------------------------------
/next-js-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxproske/nextjs-docker-production-kit/HEAD/next-js-app/public/favicon.ico
--------------------------------------------------------------------------------
/next-ts-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxproske/nextjs-docker-production-kit/HEAD/next-ts-app/public/favicon.ico
--------------------------------------------------------------------------------
/next-js-app/public/img/fastblob.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxproske/nextjs-docker-production-kit/HEAD/next-js-app/public/img/fastblob.gif
--------------------------------------------------------------------------------
/next-js-app/public/img/slowblob.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxproske/nextjs-docker-production-kit/HEAD/next-js-app/public/img/slowblob.gif
--------------------------------------------------------------------------------
/next-ts-app/public/img/fastblob.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxproske/nextjs-docker-production-kit/HEAD/next-ts-app/public/img/fastblob.gif
--------------------------------------------------------------------------------
/next-ts-app/public/img/slowblob.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxproske/nextjs-docker-production-kit/HEAD/next-ts-app/public/img/slowblob.gif
--------------------------------------------------------------------------------
/next-js-app/src/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css'
2 |
3 | export default function App({ Component, pageProps }) {
4 | return
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | // Nginx formatting
4 | "raynigon.nginx-formatter",
5 | // React formatting
6 | "dbaeumer.vscode-eslint",
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/postgres/dev.Dockerfile:
--------------------------------------------------------------------------------
1 | # Target your exact production database version
2 | FROM postgres:17-alpine
3 |
4 | # Seed database with placeholder data
5 | COPY *.sql /docker-entrypoint-initdb.d/
6 |
--------------------------------------------------------------------------------
/next-js-app/src/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default function handler(req, res) {
4 | res.status(200).json({ name: 'John Doe' })
5 | }
6 |
--------------------------------------------------------------------------------
/next-ts-app/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css'
2 | import type { AppProps } from 'next/app'
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # local env files
7 | .env.local
8 | .env.development.local
9 | .env.test.local
10 | .env.production.local
11 |
--------------------------------------------------------------------------------
/nginx/certs/README.md:
--------------------------------------------------------------------------------
1 | Generate a wildcard SSL certificate for `your-domain.com` with LetsEncrypt:
2 |
3 | - macOS/Linux: Run `./get-wildcard-cert.sh your-domain.com`
4 | - Windows: Run `./get-wildcard-cert-windows.sh your-domain.com`
5 |
6 | Follow the instructions to add a TXT record to your DNS Zone file.
7 |
--------------------------------------------------------------------------------
/nginx/certs/example/archive/local.mproske.com/privkey1.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvZ9H7PNPUKE9GI6y
3 | Rww6RKO8NxyIUHkIUnoU+QmHWR2hRANCAASMVf7jSvFLdpoK3W7tpt1YEM2W+t9o
4 | D9K/0hPvc6U/Gp5o9FZKWfvG91F3k8igaYQ//jXOlsebrbSN5cz9rxKv
5 | -----END PRIVATE KEY-----
6 |
--------------------------------------------------------------------------------
/next-js-app/src/pages/_document.js:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document'
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/next-ts-app/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document'
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/nginx/certs/get-wildcard-cert.sh:
--------------------------------------------------------------------------------
1 | docker run -it --rm \
2 | -v "$PWD":/etc/letsencrypt \
3 | certbot/certbot \
4 | certonly --manual \
5 | --preferred-challenges=dns \
6 | --server https://acme-v02.api.letsencrypt.org/directory \
7 | --email example@example.com \
8 | --agree-tos \
9 | -d *.$1 -d $1
10 |
--------------------------------------------------------------------------------
/prod.sh:
--------------------------------------------------------------------------------
1 | # Create a network, which allows containers to communicate
2 | # with each other, by using their container name as a hostname
3 | docker network create my_network
4 |
5 | # Build prod
6 | docker compose -f docker-compose.prod.yml build
7 |
8 | # Up prod in detached mode
9 | docker compose -f docker-compose.prod.yml up -d
10 |
--------------------------------------------------------------------------------
/next-ts-app/src/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(_req: NextApiRequest, res: NextApiResponse) {
9 | res.status(200).json({ name: 'John Doe' })
10 | }
11 |
--------------------------------------------------------------------------------
/nginx/certs/get-wildcard-cert-windows.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | winpty docker run -it --rm \
4 | -v /"$(pwd)":/etc/letsencrypt \
5 | certbot/certbot \
6 | certonly --manual \
7 | --preferred-challenges=dns \
8 | --server https://acme-v02.api.letsencrypt.org/directory \
9 | --email example@example.com \
10 | --agree-tos \
11 | -d *.$1 -d $1
12 |
--------------------------------------------------------------------------------
/nginx/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 |
3 | # All except the example cert are ignored from version control
4 | # If you wish to add your certs to version control, change your
5 | # repo to private before removing these lines:
6 | certs/*
7 | !certs/*.sh
8 | !certs/*.md
9 | !certs/example
10 | certs/example/accounts
11 | certs/example/csr
12 | certs/example/keys
13 | certs/example/renewal
14 | certs/example/renewal-hooks
15 |
--------------------------------------------------------------------------------
/prod-without-multistage.sh:
--------------------------------------------------------------------------------
1 | # Create a network, which allows containers to communicate
2 | # with each other, by using their container name as a hostname
3 | docker network create my_network
4 |
5 | # Build prod without multistage
6 | docker compose -f docker-compose.prod-without-multistage.yml build
7 |
8 | # Up prod without multistage in detached mode
9 | docker compose -f docker-compose.prod-without-multistage.yml up -d
10 |
--------------------------------------------------------------------------------
/next-js-app/src/lib/postgres.js:
--------------------------------------------------------------------------------
1 | import postgres from 'postgres'
2 |
3 | const sql = postgres({
4 | host: process.env.POSTGRES_HOST,
5 | port: Number(process.env.POSTGRES_PORT),
6 | database: process.env.POSTGRES_DATABASE,
7 | username: process.env.POSTGRES_USER,
8 | password: process.env.POSTGRES_PASSWORD,
9 | // Transform the column names only from camel case
10 | transform: postgres.camel,
11 | })
12 |
13 | export default sql
14 |
--------------------------------------------------------------------------------
/next-ts-app/src/lib/postgres.ts:
--------------------------------------------------------------------------------
1 | import postgres from 'postgres'
2 |
3 | const sql = postgres({
4 | host: process.env.POSTGRES_HOST,
5 | port: Number(process.env.POSTGRES_PORT),
6 | database: process.env.POSTGRES_DATABASE,
7 | username: process.env.POSTGRES_USER,
8 | password: process.env.POSTGRES_PASSWORD,
9 | // Transform the column names only from camel case
10 | transform: postgres.camel,
11 | })
12 |
13 | export default sql
14 |
--------------------------------------------------------------------------------
/nginx/certs/example/dhparam-2048.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
3 | +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
4 | 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
5 | YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
6 | 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
7 | ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
8 | -----END DH PARAMETERS-----
--------------------------------------------------------------------------------
/next-js-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
--------------------------------------------------------------------------------
/next-ts-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "next dev --turbo",
5 | "build": "next build",
6 | "start": "next start"
7 | },
8 | "dependencies": {
9 | "next": "^15.0.3",
10 | "postgres": "^3.4.5",
11 | "react": "^18.3.1",
12 | "react-dom": "^18.3.1"
13 | },
14 | "devDependencies": {
15 | "@types/node": "^22.9.0",
16 | "@types/react": "^18.3.12",
17 | "@types/react-dom": "^18.3.1",
18 | "typescript": "^5.6.3"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/dev.sh:
--------------------------------------------------------------------------------
1 | # Stop all running containers
2 | docker kill $(docker ps -aq) && docker rm $(docker ps -aq)
3 |
4 | # Create a network, which allows containers to communicate
5 | # with each other, by using their container name as a hostname
6 | docker network create my_network
7 |
8 | # Build dev
9 | docker compose -f docker-compose.dev.yml build
10 |
11 | # Up dev
12 | # --renew-anon-volumes
13 | # postgres/mysql retrieve volumes from previous containers after being killed
14 | docker compose -f docker-compose.dev.yml up --renew-anon-volumes
15 |
--------------------------------------------------------------------------------
/next-ts-app/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | output: 'standalone',
5 | basePath: '',
6 | webpack(config, { dev, isServer }) {
7 | // Required for Hot Reloading on Windows
8 | // https://github.com/vercel/next.js/issues/6417
9 | if (dev && !isServer) {
10 | config.watchOptions = {
11 | poll: 1000,
12 | aggregateTimeout: 300,
13 | }
14 | }
15 | return config
16 | },
17 | }
18 |
19 | module.exports = nextConfig
20 |
--------------------------------------------------------------------------------
/next-js-app/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | output: 'standalone',
5 | basePath: '/js',
6 | webpack(config, { dev, isServer }) {
7 | // Required for Hot Reloading on Windows
8 | // https://github.com/vercel/next.js/issues/6417
9 | if (dev && !isServer) {
10 | config.watchOptions = {
11 | poll: 1000,
12 | aggregateTimeout: 300,
13 | }
14 | }
15 | return config
16 | },
17 | }
18 |
19 | module.exports = nextConfig
20 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | # DO NOT ADD SECRETS TO THIS FILE. This is a good place for defaults.
2 | # If you want to add secrets use any of the following filenames instead,
3 | # which are automatically detected by Docker Compose:
4 | # .env.local
5 | # .env.development.local
6 | # .env.test.local
7 | # .env.production.local
8 |
9 | ENV_VARIABLE=production_server_only_variable
10 | NEXT_PUBLIC_ENV_VARIABLE=production_public_variable
11 |
12 | POSTGRES_HOST=postgres
13 | POSTGRES_PORT=5432
14 | POSTGRES_DATABASE=saas
15 | POSTGRES_USER=saas_user
16 | POSTGRES_PASSWORD=password
17 |
--------------------------------------------------------------------------------
/next-ts-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/next-js-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "next dev --turbo",
5 | "build": "next build",
6 | "start": "next start"
7 | },
8 | "dependencies": {
9 | "next": "^15.0.3",
10 | "postgres": "^3.4.5",
11 | "react": "^18.3.1",
12 | "react-dom": "^18.3.1"
13 | },
14 | "devDependencies": {
15 | "@eslint/compat": "^1.2.3",
16 | "@eslint/js": "^9.15.0",
17 | "@types/eslint__js": "^8.42.3",
18 | "eslint": "^9.15.0",
19 | "eslint-plugin-react-hooks": "^5.0.0",
20 | "typescript": "^5.6.3",
21 | "typescript-eslint": "^8.14.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/next-js-app/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/next-ts-app/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.23
2 |
3 | WORKDIR /etc/nginx
4 |
5 | # Module for hiding headers
6 | RUN apt-get update && apt-get install -y nginx-extras
7 |
8 | # Copy config files
9 | COPY nginx.conf .
10 | COPY headers.conf .
11 | COPY ssl.conf .
12 |
13 | # Copy SSL certs
14 | COPY certs/example/live/local.mproske.com/fullchain.pem ./certs/local.mproske.com/fullchain.pem
15 | COPY certs/example/live/local.mproske.com/privkey.pem ./certs/local.mproske.com/privkey.pem
16 | COPY certs/example/dhparam-2048.pem ./certs/dhparam-2048.pem
17 |
18 | # Copy sites files
19 | COPY sites-enabled/ ./
20 |
21 | # Create new files as www-data, not root
22 | RUN usermod -u 1000 www-data
23 |
24 | CMD nginx
25 |
--------------------------------------------------------------------------------
/next-js-app/src/components/Blob.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import Image from 'next/image'
3 | import styles from '../styles/Home.module.css'
4 | import { useRouter } from 'next/router'
5 |
6 | export default function Blob() {
7 | const [isFast, setIsFast] = useState(false)
8 | const { basePath } = useRouter()
9 |
10 | return (
11 | setIsFast((prev) => !prev)}>
12 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/next-ts-app/src/components/Blob.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import Image from 'next/image'
3 | import styles from '../styles/Home.module.css'
4 | import { useRouter } from 'next/router'
5 |
6 | export default function Blob() {
7 | const [isFast, setIsFast] = useState(false)
8 | const { basePath } = useRouter()
9 |
10 | return (
11 | setIsFast((prev) => !prev)}>
12 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/next-ts-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "baseUrl": ".",
18 | "plugins": [
19 | {
20 | "name": "next"
21 | }
22 | ]
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/nginx/certs/example/live/local.mproske.com/README:
--------------------------------------------------------------------------------
1 | This directory contains your keys and certificates.
2 |
3 | `privkey.pem` : the private key for your certificate.
4 | `fullchain.pem`: the certificate file used in most server software.
5 | `chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
6 | `cert.pem` : will break many server configurations, and should not be used
7 | without reading further documentation (see link below).
8 |
9 | WARNING: DO NOT MOVE OR RENAME THESE FILES!
10 | Certbot expects these files to remain in this location in order
11 | to function properly!
12 |
13 | We recommend not moving these files. For more information, see the Certbot
14 | User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.
15 |
--------------------------------------------------------------------------------
/nginx/certs/example/live/README:
--------------------------------------------------------------------------------
1 | This directory contains your keys and certificates.
2 |
3 | `[cert name]/privkey.pem` : the private key for your certificate.
4 | `[cert name]/fullchain.pem`: the certificate file used in most server software.
5 | `[cert name]/chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
6 | `[cert name]/cert.pem` : will break many server configurations, and should not be used
7 | without reading further documentation (see link below).
8 |
9 | WARNING: DO NOT MOVE OR RENAME THESE FILES!
10 | Certbot expects these files to remain in this location in order
11 | to function properly!
12 |
13 | We recommend not moving these files. For more information, see the Certbot
14 | User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-docker-production-kit",
3 | "version": "1.0.0",
4 | "repository": "https://github.com/maxproske/nextjs-docker-production-kit.git",
5 | "author": "Max Proske ",
6 | "license": "MIT",
7 | "devDependencies": {
8 | "@eslint/eslintrc": "^3.2.0",
9 | "@eslint/js": "^9.15.0",
10 | "@types/node": "^22.9.0",
11 | "@types/react": "^18.3.12",
12 | "@types/react-dom": "^18.3.1",
13 | "@typescript-eslint/eslint-plugin": "^8.14.0",
14 | "@typescript-eslint/parser": "^8.14.0",
15 | "eslint": "^9.15.0",
16 | "eslint-config-next": "^15.0.3",
17 | "eslint-config-prettier": "^9.1.0",
18 | "eslint-plugin-prettier": "^5.2.1",
19 | "eslint-plugin-react": "^7.37.2",
20 | "eslint-plugin-react-hooks": "^5.0.0",
21 | "next": "^15.0.3",
22 | "prettier": "^3.3.3",
23 | "react": "^18.3.1",
24 | "react-dom": "^18.3.1",
25 | "typescript": "^5.6.3"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 | import { fileURLToPath } from 'node:url'
3 | import js from '@eslint/js'
4 | import { FlatCompat } from '@eslint/eslintrc'
5 |
6 | const __filename = fileURLToPath(import.meta.url)
7 | const __dirname = path.dirname(__filename)
8 | const compat = new FlatCompat({
9 | baseDirectory: __dirname,
10 | recommendedConfig: js.configs.recommended,
11 | allConfig: js.configs.all,
12 | })
13 |
14 | export default [
15 | ...compat.extends('eslint:recommended', 'next', 'plugin:prettier/recommended'),
16 | {
17 | rules: {
18 | 'react/react-in-jsx-scope': 'off',
19 | 'prettier/prettier': [
20 | 'error',
21 | {
22 | singleQuote: true,
23 | bracketSpacing: true,
24 | arrowParens: 'always',
25 | printWidth: 120,
26 | semi: false,
27 | trailingComma: 'es5',
28 | tabWidth: 2,
29 | useTabs: false,
30 | endOfLine: 'auto',
31 | },
32 | ],
33 | },
34 | },
35 | ]
36 |
--------------------------------------------------------------------------------
/postgres/data.sql:
--------------------------------------------------------------------------------
1 | \connect saas saas_user
2 |
3 | -- Schema
4 | CREATE SCHEMA saas AUTHORIZATION saas_user;
5 | GRANT ALL PRIVILEGES ON SCHEMA saas TO saas_user;
6 | ALTER DEFAULT PRIVILEGES IN SCHEMA saas GRANT ALL PRIVILEGES ON TABLES TO saas_user;
7 | ALTER DEFAULT PRIVILEGES IN SCHEMA saas GRANT ALL PRIVILEGES ON SEQUENCES TO saas_user;
8 | ALTER DEFAULT PRIVILEGES IN SCHEMA saas GRANT ALL PRIVILEGES ON FUNCTIONS TO saas_user;
9 |
10 | -- Tables
11 | CREATE TABLE saas.users (
12 | id SERIAL PRIMARY KEY,
13 | username character varying(32),
14 | created_at timestamptz NOT NULL DEFAULT now()
15 | );
16 |
17 | -- Data
18 | INSERT INTO saas.users (id, username, created_at)
19 | VALUES (1, 'Test', '2023-01-01 00:00:00.000000');
20 |
21 | -- Reset sequences in case placeholder data has explicit primary key inserts,
22 | -- regardless whether table has rows or not, otherwise UPDATEs may fail
23 | SELECT setval(pg_get_serial_sequence('saas.users', 'id'), coalesce(max(id), 0) + 1, false) FROM saas.users;
24 |
25 | -- Indexes
26 | CREATE INDEX ON saas.users (created_at);
27 |
--------------------------------------------------------------------------------
/next-js-app/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/next-ts-app/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | # Required to use `more_clear_headers`
2 | load_module modules/ngx_http_headers_more_filter_module.so;
3 |
4 | http {
5 | # Hide Nginx version number in headers, including on error pages
6 | server_tokens off;
7 |
8 | # Hide Nginx server header
9 | more_clear_headers Server;
10 |
11 | # Hide other server headers (Node.js, PHP, etc.)
12 | more_clear_headers X-Powered-By;
13 |
14 | # More headers
15 | include /etc/nginx/headers.conf;
16 |
17 | # Recommended defaults
18 | include /etc/nginx/mime.types;
19 | default_type application/octet-stream;
20 | sendfile on;
21 | tcp_nodelay on;
22 |
23 | # Allow long domain names
24 | # Fixes "could not build server_names_hash, you should increase server_names_hash_bucket_size: 64"
25 | server_names_hash_bucket_size 128;
26 |
27 | # Sites
28 | include /etc/nginx/sites-enabled/*;
29 | }
30 |
31 | # More recommended defaults
32 | events {
33 | worker_connections 2048;
34 | multi_accept on;
35 | use epoll;
36 | }
37 |
38 | user www-data;
39 | worker_processes 4;
40 | pid /run/nginx.pid;
41 | daemon off;
42 |
--------------------------------------------------------------------------------
/next-js-app/dev.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 |
3 | WORKDIR /app
4 |
5 | # Install dependencies based on the preferred package manager
6 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
7 | RUN \
8 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
9 | elif [ -f package-lock.json ]; then npm ci; \
10 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
11 | # Allow install without lockfile, so example works even without Node.js installed locally
12 | else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
13 | fi
14 |
15 | COPY src ./src
16 | COPY public ./public
17 | COPY next.config.js .
18 | COPY jsconfig.json .
19 |
20 | # Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
21 | # Uncomment the following line to disable telemetry at run time
22 | # ENV NEXT_TELEMETRY_DISABLED 1
23 |
24 | # Note: Don't expose ports here, Compose will handle that for us
25 |
26 | # Start Next.js in development mode based on the preferred package manager
27 | CMD \
28 | if [ -f yarn.lock ]; then yarn dev; \
29 | elif [ -f package-lock.json ]; then npm run dev; \
30 | elif [ -f pnpm-lock.yaml ]; then pnpm dev; \
31 | else yarn dev; \
32 | fi
33 |
--------------------------------------------------------------------------------
/next-ts-app/dev.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 |
3 | WORKDIR /app
4 |
5 | # Install dependencies based on the preferred package manager
6 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
7 | RUN \
8 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
9 | elif [ -f package-lock.json ]; then npm ci; \
10 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
11 | # Allow install without lockfile, so example works even without Node.js installed locally
12 | else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
13 | fi
14 |
15 | COPY src ./src
16 | COPY public ./public
17 | COPY next.config.js .
18 | COPY tsconfig.json .
19 |
20 | # Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
21 | # Uncomment the following line to disable telemetry at run time
22 | # ENV NEXT_TELEMETRY_DISABLED 1
23 |
24 | # Note: Don't expose ports here, Compose will handle that for us
25 |
26 | # Start Next.js in development mode based on the preferred package manager
27 | CMD \
28 | if [ -f yarn.lock ]; then yarn dev; \
29 | elif [ -f package-lock.json ]; then npm run dev; \
30 | elif [ -f pnpm-lock.yaml ]; then pnpm dev; \
31 | else yarn dev; \
32 | fi
33 |
--------------------------------------------------------------------------------
/next-js-app/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/next-ts-app/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nginx/ssl.conf:
--------------------------------------------------------------------------------
1 | # Generate SSL config using "Intermediate" setting for good support
2 | # https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1d&guideline=5.6
3 |
4 | # Enable session resumption to improve HTTPS performance
5 | ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
6 | ssl_session_timeout 1d;
7 | ssl_session_tickets off;
8 |
9 | # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
10 | # Generate a new cert with `curl https://ssl-config.mozilla.org/ffdhe2048.txt`
11 | ssl_dhparam /etc/nginx/certs/dhparam-2048.pem;
12 |
13 | # Enable server-side protection from BEAST attacks
14 | ssl_prefer_server_ciphers on;
15 |
16 | # Protocols and ciphers chosen for compatibility
17 | ssl_protocols TLSv1.2 TLSv1.3;
18 | ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
19 | # Enbale OCSP stapling to convey certificate revocation info in a privacy-preserving, scalable manner
20 | ssl_stapling on;
21 | ssl_stapling_verify on;
22 |
23 | # Note: Using add_header in `server` scope wipes out add_header in `http` scope, so include again
24 | # https://blog.g3rt.nl/nginx-add_header-pitfall.html
25 | include /etc/nginx/headers.conf;
26 |
27 | resolver 8.8.8.8 8.8.4.4;
28 |
--------------------------------------------------------------------------------
/nginx/certs/example/archive/local.mproske.com/cert1.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEXDCCA0SgAwIBAgISBGpthqxL9czlbtCInEjqO2IdMA0GCSqGSIb3DQEBCwUA
3 | MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
4 | EwJSMzAeFw0yMjEyMTQwNTAyMDhaFw0yMzAzMTQwNTAyMDdaMBwxGjAYBgNVBAMT
5 | EWxvY2FsLm1wcm9za2UuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjFX+
6 | 40rxS3aaCt1u7abdWBDNlvrfaA/Sv9IT73OlPxqeaPRWSln7xvdRd5PIoGmEP/41
7 | zpbHm620jeXM/a8Sr6OCAkswggJHMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
8 | BggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUvrTS
9 | HlrsAUvto1KsitG0Nc1hQ9YwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsU
10 | wsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5j
11 | ci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wHAYDVR0R
12 | BBUwE4IRbG9jYWwubXByb3NrZS5jb20wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYL
13 | KwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlw
14 | dC5vcmcwggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdgC3Pvsk35xNunXyOcW6WPRs
15 | XfxCz3qfNcSeHQmBJe20mQAAAYUPOd40AAAEAwBHMEUCIFEkCXsRofJHMxQEBi1w
16 | La8260zV4OzdzZ9zNUVru86bAiEA/H6CwcOd+9BJjHWrqg9KoHUQq9dZPWmasz1S
17 | e94ZkqEAdQDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYUPOd4p
18 | AAAEAwBGMEQCIGd7ddZ8HEVrCGzX77ArlEkj7/uNJVqbIK7QblueX5K0AiBSgdNz
19 | 7cmlgVNrNOVWkzohN95a79mNsh0rmGYY3wNdIDANBgkqhkiG9w0BAQsFAAOCAQEA
20 | Q0Pf05MKQ4G/ZJHVfvH0rbhq1eFzA3MkG19YopqrmZgx9uHkoB6iHU7UzPuD3wLT
21 | pz3sEjl5bTN/059iWk55aAevGqmG6WnAayef6g8tPYCksKnrC6upP3Yn/TY5FXSn
22 | rr/OvZ/qOSsLAFjL96S/fdgVbz5EHfsAEFtIzQN7GVar675KLLHkpBt1Kgk67eRA
23 | 6RTZVqqMp5LjK5RyhezJk/8RQN0rPhmbxBriJv8nYjbQ+wDVBKcGapyRoqSQhvl2
24 | QMG/3TN0HeI5hDQxmQLasZkCQjUd/36c3s6ttw9eikwqZ0VI6WoR/4ua9gHYfMOG
25 | mWE8w9aXIwOUSrd6GR4r5Q==
26 | -----END CERTIFICATE-----
27 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // Automatic code formatting
3 | "editor.formatOnSave": false,
4 | "eslint.format.enable": true,
5 | "[json]": {
6 | "editor.defaultFormatter": "dbaeumer.vscode-eslint",
7 | "editor.formatOnSave": true
8 | },
9 | "[jsonc]": {
10 | "editor.defaultFormatter": "dbaeumer.vscode-eslint",
11 | "editor.formatOnSave": true
12 | },
13 | "[javascript]": {
14 | "editor.defaultFormatter": "dbaeumer.vscode-eslint",
15 | "editor.formatOnSave": true
16 | },
17 | "[javascriptreact]": {
18 | "editor.defaultFormatter": "dbaeumer.vscode-eslint",
19 | "editor.formatOnSave": true
20 | },
21 | "[typescript]": {
22 | "editor.defaultFormatter": "dbaeumer.vscode-eslint",
23 | "editor.formatOnSave": true
24 | },
25 | "[typescriptreact]": {
26 | "editor.defaultFormatter": "dbaeumer.vscode-eslint",
27 | "editor.formatOnSave": true
28 | },
29 | "[html]": {
30 | "editor.defaultFormatter": "esbenp.prettier-vscode",
31 | "editor.formatOnSave": true
32 | },
33 | "[css]": {
34 | "editor.defaultFormatter": "esbenp.prettier-vscode",
35 | "editor.formatOnSave": true
36 | },
37 | "[yaml]": {
38 | "editor.defaultFormatter": "esbenp.prettier-vscode",
39 | "editor.formatOnSave": true
40 | },
41 | "[markdown]": {
42 | "editor.defaultFormatter": "esbenp.prettier-vscode",
43 | "editor.tabSize": 2,
44 | "editor.formatOnSave": false
45 | },
46 | "[nginx]": {
47 | "editor.defaultFormatter": "raynigon.nginx-formatter",
48 | "editor.formatOnSave": true
49 | },
50 | // Look for .eslintrc.json files here
51 | "eslint.workingDirectories": [
52 | ".",
53 | ],
54 | "editor.codeActionsOnSave": {
55 | "source.fixAll.eslint": "explicit"
56 | },
57 | "eslint.validate": ["javascript", "typescript"],
58 | "eslint.nodePath": "./node_modules/eslint"
59 | }
60 |
--------------------------------------------------------------------------------
/nginx/headers.conf:
--------------------------------------------------------------------------------
1 | # Note: The `always` parameter includes header on HTTP 4XX-5XX responses
2 | # Burp Suite expects security headers on HTTP 404
3 |
4 | # Prevent page from being embedded within an iframe
5 | add_header X-Frame-Options SAMEORIGIN always;
6 |
7 | # Disable content-type sniffing on some browsers
8 | add_header X-Content-Type-Options nosniff always;
9 |
10 | # Enable the XSS filter built into most modern browsers
11 | add_header X-XSS-Protection "1; mode=block" always;
12 |
13 | # Enable HSTS to avoid SSL stripping, tell the browser to always use HTTPS
14 | # Fixes Burp Suite issue "Unencrypted communications"
15 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
16 |
17 | # Restrict what resources can load to prevent XSS
18 | # Use a starter policy for all sites, then define stricter policy in
19 | # Read more: https://content-security-policy.com
20 | add_header Content-Security-Policy "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;" always;
21 |
22 | # Keep referrer data off HTTP connections
23 | # Recommended header
24 | add_header Referrer-Policy "no-referrer-when-downgrade" always;
25 |
26 | # Disable certain web features on all sites
27 | # Recommended header
28 | add_header Permissions-Policy "magnetometer=(), microphone=(), payment=(), usb=()" always;
29 |
30 | # Upcoming required COOP/COEP headers recommended by https://securityheaders.com
31 | # Read more: https://scotthelme.co.uk/coop-and-coep
32 |
33 | # Prevent assets being loaded that don't grant permission to load them via CORS or CORP
34 | # Note: `require-corp` currently blocks reCAPTCHA requests in Network tab
35 | add_header Cross-Origin-Embedder-Policy "unsafe-none" always;
36 |
37 | # Opt-in to Cross-Origin Isolation
38 | add_header Cross-Origin-Opener-Policy "same-origin" always;
39 |
40 | # Specify who can load sub-resources
41 | add_header Cross-Origin-Resource-Policy "cross-origin" always;
42 |
--------------------------------------------------------------------------------
/docker-compose.prod.yml:
--------------------------------------------------------------------------------
1 | # `version` is now deprecated
2 | # https://docs.docker.com/compose/compose-file/#version-top-level-element
3 |
4 | services:
5 | next-ts-app:
6 | container_name: next-ts-app
7 | build:
8 | context: ./next-ts-app
9 | dockerfile: prod.Dockerfile
10 | args:
11 | ENV_VARIABLE: ${ENV_VARIABLE}
12 | NEXT_PUBLIC_ENV_VARIABLE: ${NEXT_PUBLIC_ENV_VARIABLE}
13 | POSTGRES_HOST: ${POSTGRES_HOST}
14 | POSTGRES_PORT: ${POSTGRES_PORT}
15 | POSTGRES_DATABASE: ${POSTGRES_DATABASE}
16 | POSTGRES_USER: ${POSTGRES_USER}
17 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
18 | restart: always
19 | networks:
20 | - my_network
21 |
22 | next-js-app:
23 | container_name: next-js-app
24 | build:
25 | context: ./next-js-app
26 | dockerfile: prod.Dockerfile
27 | args:
28 | ENV_VARIABLE: ${ENV_VARIABLE}
29 | NEXT_PUBLIC_ENV_VARIABLE: ${NEXT_PUBLIC_ENV_VARIABLE}
30 | POSTGRES_HOST: ${POSTGRES_HOST}
31 | POSTGRES_PORT: ${POSTGRES_PORT}
32 | POSTGRES_DATABASE: ${POSTGRES_DATABASE}
33 | POSTGRES_USER: ${POSTGRES_USER}
34 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
35 | restart: always
36 | networks:
37 | - my_network
38 |
39 | nginx:
40 | container_name: nginx
41 | build:
42 | context: ./nginx
43 | dockerfile: Dockerfile
44 | volumes:
45 | - ./nginx/sites-enabled:/etc/nginx/sites-enabled
46 | - ./nginx/logs:/var/log/nginx
47 | ports:
48 | - 80:80
49 | - 443:443
50 | - 3000:3000
51 | depends_on:
52 | - next-ts-app
53 | - next-js-app
54 | restart: always
55 | networks:
56 | - my_network
57 |
58 | # Add more containers below
59 |
60 | # Define a network, which allows containers to communicate
61 | # with each other, by using their container name as a hostname
62 | networks:
63 | my_network:
64 | external: true
65 |
--------------------------------------------------------------------------------
/docker-compose.prod-without-multistage.yml:
--------------------------------------------------------------------------------
1 | # `version` is now deprecated
2 | # https://docs.docker.com/compose/compose-file/#version-top-level-element
3 |
4 | services:
5 | next-ts-app:
6 | container_name: next-ts-app
7 | build:
8 | context: ./next-ts-app
9 | dockerfile: prod-without-multistage.Dockerfile
10 | args:
11 | ENV_VARIABLE: ${ENV_VARIABLE}
12 | NEXT_PUBLIC_ENV_VARIABLE: ${NEXT_PUBLIC_ENV_VARIABLE}
13 | POSTGRES_HOST: ${POSTGRES_HOST}
14 | POSTGRES_PORT: ${POSTGRES_PORT}
15 | POSTGRES_DATABASE: ${POSTGRES_DATABASE}
16 | POSTGRES_USER: ${POSTGRES_USER}
17 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
18 | restart: always
19 | networks:
20 | - my_network
21 |
22 | next-js-app:
23 | container_name: next-js-app
24 | build:
25 | context: ./next-js-app
26 | dockerfile: prod-without-multistage.Dockerfile
27 | args:
28 | ENV_VARIABLE: ${ENV_VARIABLE}
29 | NEXT_PUBLIC_ENV_VARIABLE: ${NEXT_PUBLIC_ENV_VARIABLE}
30 | POSTGRES_HOST: ${POSTGRES_HOST}
31 | POSTGRES_PORT: ${POSTGRES_PORT}
32 | POSTGRES_DATABASE: ${POSTGRES_DATABASE}
33 | POSTGRES_USER: ${POSTGRES_USER}
34 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
35 | restart: always
36 | networks:
37 | - my_network
38 |
39 | nginx:
40 | container_name: nginx
41 | build:
42 | context: ./nginx
43 | dockerfile: Dockerfile
44 | volumes:
45 | - ./nginx/sites-enabled:/etc/nginx/sites-enabled
46 | - ./nginx/logs:/var/log/nginx
47 | ports:
48 | - 80:80
49 | - 443:443
50 | - 3000:3000
51 | depends_on:
52 | - next-ts-app
53 | - next-js-app
54 | restart: always
55 | networks:
56 | - my_network
57 |
58 | # Add more containers below
59 |
60 | # Define a network, which allows containers to communicate
61 | # with each other, by using their container name as a hostname
62 | networks:
63 | my_network:
64 | external: true
65 |
--------------------------------------------------------------------------------
/next-js-app/prod-without-multistage.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 |
3 | WORKDIR /app
4 |
5 | # Install dependencies based on the preferred package manager
6 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
7 | # Include --production flag for JavaScript
8 | RUN \
9 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
10 | elif [ -f package-lock.json ]; then npm ci; \
11 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
12 | # Allow install without lockfile, so example works even without Node.js installed locally
13 | else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
14 | fi
15 |
16 | COPY src ./src
17 | COPY public ./public
18 | COPY next.config.js .
19 | COPY jsconfig.json .
20 |
21 | # Environment variables must be present at build time
22 | # https://github.com/vercel/next.js/discussions/14030
23 | ARG ENV_VARIABLE
24 | ENV ENV_VARIABLE=${ENV_VARIABLE}
25 | ARG NEXT_PUBLIC_ENV_VARIABLE
26 | ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE}
27 | ARG POSTGRES_HOST
28 | ENV POSTGRES_HOST=${POSTGRES_HOST}
29 | ARG POSTGRES_PORT
30 | ENV POSTGRES_PORT=${POSTGRES_PORT}
31 | ARG POSTGRES_DATABASE
32 | ENV POSTGRES_DATABASE=${POSTGRES_DATABASE}
33 | ARG POSTGRES_USER
34 | ENV POSTGRES_USER=${POSTGRES_USER}
35 | ARG POSTGRES_PASSWORD
36 | ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
37 |
38 | # Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
39 | # Uncomment the following line to disable telemetry at build time
40 | # ENV NEXT_TELEMETRY_DISABLED 1
41 |
42 | # Note: Don't expose ports here, Compose will handle that for us
43 |
44 | # Build Next.js based on the preferred package manager
45 | RUN \
46 | if [ -f yarn.lock ]; then yarn build; \
47 | elif [ -f package-lock.json ]; then npm run build; \
48 | elif [ -f pnpm-lock.yaml ]; then pnpm build; \
49 | else yarn build; \
50 | fi
51 |
52 | # Start Next.js based on the preferred package manager
53 | CMD \
54 | if [ -f yarn.lock ]; then yarn start; \
55 | elif [ -f package-lock.json ]; then npm run start; \
56 | elif [ -f pnpm-lock.yaml ]; then pnpm start; \
57 | else yarn start; \
58 | fi
59 |
--------------------------------------------------------------------------------
/next-ts-app/prod-without-multistage.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 |
3 | WORKDIR /app
4 |
5 | # Install dependencies based on the preferred package manager
6 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
7 | # Omit --production flag for TypeScript devDependencies
8 | RUN \
9 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
10 | elif [ -f package-lock.json ]; then npm ci; \
11 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
12 | # Allow install without lockfile, so example works even without Node.js installed locally
13 | else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
14 | fi
15 |
16 | COPY src ./src
17 | COPY public ./public
18 | COPY next.config.js .
19 | COPY tsconfig.json .
20 |
21 | # Environment variables must be present at build time
22 | # https://github.com/vercel/next.js/discussions/14030
23 | ARG ENV_VARIABLE
24 | ENV ENV_VARIABLE=${ENV_VARIABLE}
25 | ARG NEXT_PUBLIC_ENV_VARIABLE
26 | ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE}
27 | ARG POSTGRES_HOST
28 | ENV POSTGRES_HOST=${POSTGRES_HOST}
29 | ARG POSTGRES_PORT
30 | ENV POSTGRES_PORT=${POSTGRES_PORT}
31 | ARG POSTGRES_DATABASE
32 | ENV POSTGRES_DATABASE=${POSTGRES_DATABASE}
33 | ARG POSTGRES_USER
34 | ENV POSTGRES_USER=${POSTGRES_USER}
35 | ARG POSTGRES_PASSWORD
36 | ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
37 |
38 | # Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
39 | # Uncomment the following line to disable telemetry at build time
40 | # ENV NEXT_TELEMETRY_DISABLED 1
41 |
42 | # Note: Don't expose ports here, Compose will handle that for us
43 |
44 | # Build Next.js based on the preferred package manager
45 | RUN \
46 | if [ -f yarn.lock ]; then yarn build; \
47 | elif [ -f package-lock.json ]; then npm run build; \
48 | elif [ -f pnpm-lock.yaml ]; then pnpm build; \
49 | else yarn build; \
50 | fi
51 |
52 | # Start Next.js based on the preferred package manager
53 | CMD \
54 | if [ -f yarn.lock ]; then yarn start; \
55 | elif [ -f package-lock.json ]; then npm run start; \
56 | elif [ -f pnpm-lock.yaml ]; then pnpm start; \
57 | else yarn start; \
58 | fi
59 |
--------------------------------------------------------------------------------
/nginx/sites-enabled/default.conf:
--------------------------------------------------------------------------------
1 | # Redirect http to https
2 | server {
3 | listen 80 default_server;
4 | listen [::]:80 default_server;
5 |
6 | location / {
7 | return 301 https://$host$request_uri;
8 | }
9 | }
10 |
11 | server {
12 | listen 443 ssl http2;
13 | listen [::]:443 ssl http2;
14 |
15 | # Your domain names here
16 | server_name
17 | local.mproske.com
18 | mproske.com;
19 |
20 | ssl_certificate /etc/nginx/certs/local.mproske.com/fullchain.pem;
21 | ssl_certificate_key /etc/nginx/certs/local.mproske.com/privkey.pem;
22 | include /etc/nginx/ssl.conf;
23 |
24 | error_log /var/log/nginx/local.mproske.com.error.log notice;
25 | access_log /var/log/nginx/local.mproske.com.access.log;
26 |
27 | location / {
28 | proxy_pass http://next-ts-app:3000;
29 | proxy_http_version 1.1;
30 | proxy_set_header Upgrade $http_upgrade;
31 | proxy_set_header Connection 'upgrade';
32 | proxy_set_header Host $host;
33 | proxy_cache_bypass $http_upgrade;
34 |
35 | # Required for rate limiting
36 | proxy_set_header X-Real-IP $remote_addr;
37 | proxy_set_header X-Forwarded-For $remote_addr;
38 |
39 | }
40 |
41 | location /js {
42 | proxy_pass http://next-js-app:3000;
43 | proxy_http_version 1.1;
44 | proxy_set_header Upgrade $http_upgrade;
45 | proxy_set_header Connection 'upgrade';
46 | proxy_set_header Host $host;
47 | proxy_cache_bypass $http_upgrade;
48 |
49 | # Required for rate limiting
50 | proxy_set_header X-Real-IP $remote_addr;
51 | proxy_set_header X-Forwarded-For $remote_addr;
52 |
53 | }
54 | }
55 |
56 | # Dev
57 | server {
58 | listen 3000;
59 | listen [::]:3000;
60 |
61 | server_name 127.0.0.1;
62 |
63 | location / {
64 | proxy_pass http://next-ts-app:3000;
65 | proxy_http_version 1.1;
66 | proxy_set_header Upgrade $http_upgrade;
67 | proxy_set_header Connection 'upgrade';
68 | proxy_set_header Host $host;
69 | proxy_cache_bypass $http_upgrade;
70 |
71 | # Required for rate limiting
72 | proxy_set_header X-Real-IP $remote_addr;
73 | proxy_set_header X-Forwarded-For $remote_addr;
74 | }
75 |
76 | location /js {
77 | proxy_pass http://next-js-app:3000;
78 | proxy_http_version 1.1;
79 | proxy_set_header Upgrade $http_upgrade;
80 | proxy_set_header Connection 'upgrade';
81 | proxy_set_header Host $host;
82 | proxy_cache_bypass $http_upgrade;
83 |
84 | # Required for rate limiting
85 | proxy_set_header X-Real-IP $remote_addr;
86 | proxy_set_header X-Forwarded-For $remote_addr;
87 |
88 | }
89 | }
--------------------------------------------------------------------------------
/next-js-app/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import Image from 'next/image'
3 | import Link from 'next/link'
4 | import { Inter } from 'next/font/google'
5 | import styles from 'src/styles/Home.module.css'
6 | import Blob from 'src/components/Blob'
7 | import sql from 'src/lib/postgres'
8 |
9 | const inter = Inter({ subsets: ['latin'] })
10 |
11 | export async function getServerSideProps() {
12 | try {
13 | const result = await sql`select count(*)::int from saas.users`
14 | const numUsers = result[0].count
15 | return { props: { numUsers } }
16 | } catch (err) {
17 | console.error(err)
18 | }
19 |
20 | return { props: { numUsers: 0 } }
21 | }
22 |
23 | export default function Home({ numUsers }) {
24 | return (
25 | <>
26 |
27 | Create Next App
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Get started by editing
37 | next-js-app/src/app/page.js,
and visiting the{' '}
38 | TypeScript app.
39 |
40 |
41 |
42 |
47 | Starter kit by Max Proske
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
74 |
75 | >
76 | )
77 | }
78 |
--------------------------------------------------------------------------------
/next-js-app/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --max-width: 1100px;
3 | --border-radius: 12px;
4 | --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
5 | "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
6 | "Fira Mono", "Droid Sans Mono", "Courier New", monospace;
7 |
8 | --foreground-rgb: 0, 0, 0;
9 | --background-start-rgb: 214, 219, 220;
10 | --background-end-rgb: 255, 255, 255;
11 |
12 | --primary-glow: conic-gradient(
13 | from 180deg at 50% 50%,
14 | #16abff33 0deg,
15 | #0885ff33 55deg,
16 | #54d6ff33 120deg,
17 | #0071ff33 160deg,
18 | transparent 360deg
19 | );
20 | --secondary-glow: radial-gradient(
21 | rgba(255, 255, 255, 1),
22 | rgba(255, 255, 255, 0)
23 | );
24 |
25 | --tile-start-rgb: 239, 245, 249;
26 | --tile-end-rgb: 228, 232, 233;
27 | --tile-border: conic-gradient(
28 | #00000080,
29 | #00000040,
30 | #00000030,
31 | #00000020,
32 | #00000010,
33 | #00000010,
34 | #00000080
35 | );
36 |
37 | --callout-rgb: 238, 240, 241;
38 | --callout-border-rgb: 172, 175, 176;
39 | --card-rgb: 180, 185, 188;
40 | --card-border-rgb: 131, 134, 135;
41 | }
42 |
43 | @media (prefers-color-scheme: dark) {
44 | :root {
45 | --foreground-rgb: 255, 255, 255;
46 | --background-start-rgb: 0, 0, 0;
47 | --background-end-rgb: 0, 0, 0;
48 |
49 | --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
50 | --secondary-glow: linear-gradient(
51 | to bottom right,
52 | rgba(1, 65, 255, 0),
53 | rgba(1, 65, 255, 0),
54 | rgba(1, 65, 255, 0.3)
55 | );
56 |
57 | --tile-start-rgb: 2, 13, 46;
58 | --tile-end-rgb: 2, 5, 19;
59 | --tile-border: conic-gradient(
60 | #ffffff80,
61 | #ffffff40,
62 | #ffffff30,
63 | #ffffff20,
64 | #ffffff10,
65 | #ffffff10,
66 | #ffffff80
67 | );
68 |
69 | --callout-rgb: 20, 20, 20;
70 | --callout-border-rgb: 108, 108, 108;
71 | --card-rgb: 100, 100, 100;
72 | --card-border-rgb: 200, 200, 200;
73 | }
74 | }
75 |
76 | * {
77 | box-sizing: border-box;
78 | padding: 0;
79 | margin: 0;
80 | }
81 |
82 | html,
83 | body {
84 | max-width: 100vw;
85 | overflow-x: hidden;
86 | }
87 |
88 | body {
89 | color: rbg(--foreground-rgb);
90 | background: linear-gradient(
91 | to bottom,
92 | transparent,
93 | rgb(var(--background-end-rgb))
94 | )
95 | rgb(var(--background-start-rgb));
96 | }
97 |
98 | a {
99 | color: inherit;
100 | text-decoration: none;
101 | }
102 |
103 | @media (prefers-color-scheme: dark) {
104 | html {
105 | color-scheme: dark;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/next-ts-app/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --max-width: 1100px;
3 | --border-radius: 12px;
4 | --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
5 | "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
6 | "Fira Mono", "Droid Sans Mono", "Courier New", monospace;
7 |
8 | --foreground-rgb: 0, 0, 0;
9 | --background-start-rgb: 214, 219, 220;
10 | --background-end-rgb: 255, 255, 255;
11 |
12 | --primary-glow: conic-gradient(
13 | from 180deg at 50% 50%,
14 | #16abff33 0deg,
15 | #0885ff33 55deg,
16 | #54d6ff33 120deg,
17 | #0071ff33 160deg,
18 | transparent 360deg
19 | );
20 | --secondary-glow: radial-gradient(
21 | rgba(255, 255, 255, 1),
22 | rgba(255, 255, 255, 0)
23 | );
24 |
25 | --tile-start-rgb: 239, 245, 249;
26 | --tile-end-rgb: 228, 232, 233;
27 | --tile-border: conic-gradient(
28 | #00000080,
29 | #00000040,
30 | #00000030,
31 | #00000020,
32 | #00000010,
33 | #00000010,
34 | #00000080
35 | );
36 |
37 | --callout-rgb: 238, 240, 241;
38 | --callout-border-rgb: 172, 175, 176;
39 | --card-rgb: 180, 185, 188;
40 | --card-border-rgb: 131, 134, 135;
41 | }
42 |
43 | @media (prefers-color-scheme: dark) {
44 | :root {
45 | --foreground-rgb: 255, 255, 255;
46 | --background-start-rgb: 0, 0, 0;
47 | --background-end-rgb: 0, 0, 0;
48 |
49 | --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
50 | --secondary-glow: linear-gradient(
51 | to bottom right,
52 | rgba(1, 65, 255, 0),
53 | rgba(1, 65, 255, 0),
54 | rgba(1, 65, 255, 0.3)
55 | );
56 |
57 | --tile-start-rgb: 2, 13, 46;
58 | --tile-end-rgb: 2, 5, 19;
59 | --tile-border: conic-gradient(
60 | #ffffff80,
61 | #ffffff40,
62 | #ffffff30,
63 | #ffffff20,
64 | #ffffff10,
65 | #ffffff10,
66 | #ffffff80
67 | );
68 |
69 | --callout-rgb: 20, 20, 20;
70 | --callout-border-rgb: 108, 108, 108;
71 | --card-rgb: 100, 100, 100;
72 | --card-border-rgb: 200, 200, 200;
73 | }
74 | }
75 |
76 | * {
77 | box-sizing: border-box;
78 | padding: 0;
79 | margin: 0;
80 | }
81 |
82 | html,
83 | body {
84 | max-width: 100vw;
85 | overflow-x: hidden;
86 | }
87 |
88 | body {
89 | color: rbg(--foreground-rgb);
90 | background: linear-gradient(
91 | to bottom,
92 | transparent,
93 | rgb(var(--background-end-rgb))
94 | )
95 | rgb(var(--background-start-rgb));
96 | }
97 |
98 | a {
99 | color: inherit;
100 | text-decoration: none;
101 | }
102 |
103 | @media (prefers-color-scheme: dark) {
104 | html {
105 | color-scheme: dark;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | # `version` is now deprecated
2 | # https://docs.docker.com/compose/compose-file/#version-top-level-element
3 |
4 | services:
5 | next-ts-app:
6 | container_name: next-ts-app
7 | build:
8 | context: ./next-ts-app
9 | dockerfile: dev.Dockerfile
10 | environment:
11 | ENV_VARIABLE: ${ENV_VARIABLE}
12 | NEXT_PUBLIC_ENV_VARIABLE: ${NEXT_PUBLIC_ENV_VARIABLE}
13 | POSTGRES_HOST: ${POSTGRES_HOST}
14 | POSTGRES_PORT: ${POSTGRES_PORT}
15 | POSTGRES_DATABASE: ${POSTGRES_DATABASE}
16 | POSTGRES_USER: ${POSTGRES_USER}
17 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
18 | volumes:
19 | - ./next-ts-app/src:/app/src
20 | - ./next-ts-app/public:/app/public
21 | # It's not necessary to sync the `.next` directory
22 | depends_on:
23 | - postgres
24 | restart: always
25 | networks:
26 | - my_network
27 |
28 | next-js-app:
29 | container_name: next-js-app
30 | build:
31 | context: ./next-js-app
32 | dockerfile: dev.Dockerfile
33 | environment:
34 | ENV_VARIABLE: ${ENV_VARIABLE}
35 | NEXT_PUBLIC_ENV_VARIABLE: ${NEXT_PUBLIC_ENV_VARIABLE}
36 | POSTGRES_HOST: ${POSTGRES_HOST}
37 | POSTGRES_PORT: ${POSTGRES_PORT}
38 | POSTGRES_DATABASE: ${POSTGRES_DATABASE}
39 | POSTGRES_USER: ${POSTGRES_USER}
40 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
41 | volumes:
42 | - ./next-js-app/src:/app/src
43 | - ./next-js-app/public:/app/public
44 | # It's not necessary to sync the `.next` directory
45 | depends_on:
46 | - postgres
47 | restart: always
48 | networks:
49 | - my_network
50 |
51 | nginx:
52 | container_name: nginx
53 | build:
54 | context: ./nginx
55 | dockerfile: Dockerfile
56 | volumes:
57 | - ./nginx/sites-enabled:/etc/nginx/sites-enabled
58 | - ./nginx/logs:/var/log/nginx
59 | ports:
60 | - 80:80
61 | - 443:443
62 | - 3000:3000
63 | depends_on:
64 | - next-ts-app
65 | - next-js-app
66 | restart: always
67 | networks:
68 | - my_network
69 |
70 | postgres:
71 | container_name: postgres
72 | build:
73 | context: ./postgres
74 | dockerfile: dev.Dockerfile
75 | environment:
76 | # The only variable required is `POSTGRES_PASSWORD`, the rest are optional
77 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
78 | POSTGRES_USER: ${POSTGRES_USER}
79 | POSTGRES_DB: ${POSTGRES_DATABASE}
80 | restart: always
81 | networks:
82 | - my_network
83 |
84 | # Add more containers below
85 |
86 | # Define a network, which allows containers to communicate
87 | # with each other, by using their container name as a hostname
88 | networks:
89 | my_network:
90 | external: true
91 |
--------------------------------------------------------------------------------
/next-ts-app/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import type { GetServerSideProps, InferGetServerSidePropsType } from 'next'
2 | import Head from 'next/head'
3 | import Image from 'next/image'
4 | import Link from 'next/link'
5 | import { Inter } from 'next/font/google'
6 | import styles from '../styles/Home.module.css'
7 | import Blob from '../components/Blob'
8 | import sql from '../lib/postgres'
9 |
10 | const inter = Inter({ subsets: ['latin'] })
11 |
12 | type HomeProps = {
13 | numUsers: number
14 | }
15 |
16 | export const getServerSideProps: GetServerSideProps = async () => {
17 | try {
18 | const result = await sql`select count(*)::int from saas.users`
19 | const numUsers = result[0].count
20 | return { props: { numUsers } }
21 | } catch (err) {
22 | console.error(err)
23 | }
24 |
25 | return { props: { numUsers: 0 } }
26 | }
27 |
28 | export default function Home({ numUsers }: InferGetServerSidePropsType) {
29 | return (
30 | <>
31 |
32 | Create Next App
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | Get started by editing
42 | next-ts-app/src/app/page.tsx,
and visiting the{' '}
43 | JavaScript app.
44 |
45 |
46 |
47 |
52 | Starter kit by Max Proske
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | JavaScript app ->
66 |
67 |
Visit the JavaScript app.
68 |
69 |
70 |
71 |
72 | Your app ->
73 |
74 |
75 | Your SaaS app here ({numUsers} {numUsers === 1 ? 'user' : 'users'}).
76 |
77 |
78 |
79 |
80 | >
81 | )
82 | }
83 |
--------------------------------------------------------------------------------
/next-js-app/prod.Dockerfile:
--------------------------------------------------------------------------------
1 | # Step 1. Rebuild the source code only when needed
2 | FROM node:20-alpine AS builder
3 |
4 | WORKDIR /app
5 |
6 | # Install dependencies based on the preferred package manager
7 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
8 | # Omit --production flag for TypeScript devDependencies
9 | RUN \
10 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
11 | elif [ -f package-lock.json ]; then npm ci; \
12 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
13 | # Allow install without lockfile, so example works even without Node.js installed locally
14 | else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
15 | fi
16 |
17 | COPY src ./src
18 | COPY public ./public
19 | COPY next.config.js .
20 | COPY jsconfig.json .
21 |
22 | # Environment variables must be present at build time
23 | # https://github.com/vercel/next.js/discussions/14030
24 | ARG ENV_VARIABLE
25 | ENV ENV_VARIABLE=${ENV_VARIABLE}
26 | ARG NEXT_PUBLIC_ENV_VARIABLE
27 | ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE}
28 | ARG POSTGRES_HOST
29 | ENV POSTGRES_HOST=${POSTGRES_HOST}
30 | ARG POSTGRES_PORT
31 | ENV POSTGRES_PORT=${POSTGRES_PORT}
32 | ARG POSTGRES_DATABASE
33 | ENV POSTGRES_DATABASE=${POSTGRES_DATABASE}
34 | ARG POSTGRES_USER
35 | ENV POSTGRES_USER=${POSTGRES_USER}
36 | ARG POSTGRES_PASSWORD
37 | ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
38 |
39 | # Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
40 | # Uncomment the following line to disable telemetry at build time
41 | # ENV NEXT_TELEMETRY_DISABLED 1
42 |
43 | # Build Next.js based on the preferred package manager
44 | RUN \
45 | if [ -f yarn.lock ]; then yarn build; \
46 | elif [ -f package-lock.json ]; then npm run build; \
47 | elif [ -f pnpm-lock.yaml ]; then pnpm build; \
48 | else yarn build; \
49 | fi
50 |
51 | # Note: It is not necessary to add an intermediate step that does a full copy of `node_modules` here
52 |
53 | # Step 2. Production image, copy all the files and run next
54 | FROM node:20-alpine AS runner
55 |
56 | WORKDIR /app
57 |
58 | # Don't run production as root
59 | RUN addgroup --system --gid 1001 nodejs
60 | RUN adduser --system --uid 1001 nextjs
61 | USER nextjs
62 |
63 | COPY --from=builder /app/public ./public
64 |
65 | # Automatically leverage output traces to reduce image size
66 | # https://nextjs.org/docs/advanced-features/output-file-tracing
67 | COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
68 | COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
69 |
70 | # Environment variables must be redefined at run time
71 | ARG ENV_VARIABLE
72 | ENV ENV_VARIABLE=${ENV_VARIABLE}
73 | ARG NEXT_PUBLIC_ENV_VARIABLE
74 | ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE}
75 | ARG POSTGRES_HOST
76 | ENV POSTGRES_HOST=${POSTGRES_HOST}
77 | ARG POSTGRES_PORT
78 | ENV POSTGRES_PORT=${POSTGRES_PORT}
79 | ARG POSTGRES_DATABASE
80 | ENV POSTGRES_DATABASE=${POSTGRES_DATABASE}
81 | ARG POSTGRES_USER
82 | ENV POSTGRES_USER=${POSTGRES_USER}
83 | ARG POSTGRES_PASSWORD
84 | ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
85 |
86 | # Uncomment the following line to disable telemetry at run time
87 | # ENV NEXT_TELEMETRY_DISABLED 1
88 |
89 | # Note: Don't expose ports here, Compose will handle that for us
90 |
91 | # We can use the node process itself here
92 | CMD node server.js
93 |
--------------------------------------------------------------------------------
/next-ts-app/prod.Dockerfile:
--------------------------------------------------------------------------------
1 | # Step 1. Rebuild the source code only when needed
2 | FROM node:20-alpine AS builder
3 |
4 | WORKDIR /app
5 |
6 | # Install dependencies based on the preferred package manager
7 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
8 | # Omit --production flag for TypeScript devDependencies
9 | RUN \
10 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
11 | elif [ -f package-lock.json ]; then npm ci; \
12 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
13 | # Allow install without lockfile, so example works even without Node.js installed locally
14 | else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
15 | fi
16 |
17 | COPY src ./src
18 | COPY public ./public
19 | COPY next.config.js .
20 | COPY tsconfig.json .
21 |
22 | # Environment variables must be present at build time
23 | # https://github.com/vercel/next.js/discussions/14030
24 | ARG ENV_VARIABLE
25 | ENV ENV_VARIABLE=${ENV_VARIABLE}
26 | ARG NEXT_PUBLIC_ENV_VARIABLE
27 | ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE}
28 | ARG POSTGRES_HOST
29 | ENV POSTGRES_HOST=${POSTGRES_HOST}
30 | ARG POSTGRES_PORT
31 | ENV POSTGRES_PORT=${POSTGRES_PORT}
32 | ARG POSTGRES_DATABASE
33 | ENV POSTGRES_DATABASE=${POSTGRES_DATABASE}
34 | ARG POSTGRES_USER
35 | ENV POSTGRES_USER=${POSTGRES_USER}
36 | ARG POSTGRES_PASSWORD
37 | ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
38 |
39 | # Next.js collects completely anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
40 | # Uncomment the following line to disable telemetry at build time
41 | # ENV NEXT_TELEMETRY_DISABLED 1
42 |
43 | # Build Next.js based on the preferred package manager
44 | RUN \
45 | if [ -f yarn.lock ]; then yarn build; \
46 | elif [ -f package-lock.json ]; then npm run build; \
47 | elif [ -f pnpm-lock.yaml ]; then pnpm build; \
48 | else yarn build; \
49 | fi
50 |
51 | # Note: It is not necessary to add an intermediate step that does a full copy of `node_modules` here
52 |
53 | # Step 2. Production image, copy all the files and run next
54 | FROM node:20-alpine AS runner
55 |
56 | WORKDIR /app
57 |
58 | # Don't run production as root
59 | RUN addgroup --system --gid 1001 nodejs
60 | RUN adduser --system --uid 1001 nextjs
61 | USER nextjs
62 |
63 | COPY --from=builder /app/public ./public
64 |
65 | # Automatically leverage output traces to reduce image size
66 | # https://nextjs.org/docs/advanced-features/output-file-tracing
67 | COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
68 | COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
69 |
70 | # Environment variables must be redefined at run time
71 | ARG ENV_VARIABLE
72 | ENV ENV_VARIABLE=${ENV_VARIABLE}
73 | ARG NEXT_PUBLIC_ENV_VARIABLE
74 | ENV NEXT_PUBLIC_ENV_VARIABLE=${NEXT_PUBLIC_ENV_VARIABLE}
75 | ARG POSTGRES_HOST
76 | ENV POSTGRES_HOST=${POSTGRES_HOST}
77 | ARG POSTGRES_PORT
78 | ENV POSTGRES_PORT=${POSTGRES_PORT}
79 | ARG POSTGRES_DATABASE
80 | ENV POSTGRES_DATABASE=${POSTGRES_DATABASE}
81 | ARG POSTGRES_USER
82 | ENV POSTGRES_USER=${POSTGRES_USER}
83 | ARG POSTGRES_PASSWORD
84 | ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
85 |
86 | # Uncomment the following line to disable telemetry at run time
87 | # ENV NEXT_TELEMETRY_DISABLED 1
88 |
89 | # Note: Don't expose ports here, Compose will handle that for us
90 |
91 | # We can use the node process itself here
92 | CMD node server.js
93 |
--------------------------------------------------------------------------------
/nginx/certs/example/archive/local.mproske.com/chain1.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
3 | TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
4 | cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
5 | WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
6 | RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
7 | AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
8 | R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
9 | sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
10 | NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
11 | Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
12 | /kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
13 | AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
14 | Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
15 | FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
16 | AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
17 | Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
18 | gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
19 | PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
20 | ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
21 | CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
22 | lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
23 | avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
24 | yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
25 | yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
26 | hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
27 | HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
28 | MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
29 | nLRbwHOoq7hHwg==
30 | -----END CERTIFICATE-----
31 | -----BEGIN CERTIFICATE-----
32 | MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
33 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
34 | DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
35 | TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
36 | cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
37 | AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
38 | ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
39 | wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
40 | LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
41 | 4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
42 | bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
43 | sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
44 | Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
45 | FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
46 | SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
47 | PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
48 | TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
49 | SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
50 | c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
51 | +tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
52 | ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
53 | b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
54 | U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
55 | MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
56 | 5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
57 | 9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
58 | WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
59 | he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
60 | Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
61 | -----END CERTIFICATE-----
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Next.js + Docker Production Kit
2 |
3 | Finally, a production-ready starter kit for Next.js and Docker Compose!
4 |
5 | Based on my [official Next.js example](https://github.com/vercel/next.js/tree/canary/examples/with-docker-compose), with multiple JavaScript and TypeScript apps, Postgres, SSL with Nginx, and tons of best practice defaults from over 5 years of tweaking.
6 |
7 | Issues/pull requests and ⭐ stars welcome as a show of support! Keep coming back, steal ideas for your development and production environment, and share your best practices as we continually make this example better.
8 |
9 |
10 | Show Preview
11 |
12 |
13 |
14 | ## Why use Compose with Next.js?
15 |
16 | Check out the [YouTube video](https://www.youtube.com/watch?v=-iaLmOGZuD4)!
17 |
18 | - 100% reproducable environment across macOS, Windows, and Linux teams.
19 | - Easy to develop, test, and run multiple Next.js apps, databases, and other services together.
20 | - Development and production environments are code. Compose file can be extended with any technology. If it exists, there's a Docker image of it. No exceptions.
21 | - Made with simple, best-in-class technologies that developers of all skill levels can quickly pick up.
22 |
23 | ## How to use
24 |
25 | Click the ![Fork][fork-icon] Fork button in the header of this repo before continuing. When finished, you'll be taken to your copy of the repo.
26 |
27 | Next, you'll need to clone your forked repo to your computer. In VSCode, press ⌘+SHIFT+P and search for `Git: Clone`, then enter `https://github.com/YOUR_GITHUB_USERNAME/nextjs-docker-production-kit.git`. If successful, a popup will prompt you to open your cloned repo.
28 |
29 | ## Development
30 |
31 | Make sure you have [Docker Desktop](https://docs.docker.com/get-docker) installed.
32 |
33 | In the root of your project, run your development environment:
34 |
35 | ```bash
36 | ./dev.sh
37 | ```
38 |
39 | Visit [http://localhost:3000](http://localhost:3000) to see the result.
40 |
41 | You can start editing the page by modifying `home/src/app/page.tsx`. The page auto-updates as you save the file.
42 |
43 | ### SSL ✨
44 |
45 | This example comes pre-configured with SSL. That is, your development environment is accessible using a secure HTTPS connection. You will need to append the contents of [hosts](hosts) to your `/etc/hosts` file.
46 | - [How do I find and update my `/etc/hosts` file?](https://docs.rackspace.com/support/how-to/modify-your-hosts-file).
47 |
48 | Visit [https://local.mproske.com](https://local.mproske.com) to develop locally on SSL.
49 |
50 | ### Auto-formatting ✨
51 |
52 | Install the recommended VSCode exensions. Then, install ESLint and Prettier by running `npm install`, `yarn install`, or `pnpm install` in the root of your project. Your JS and TS code should now auto-format on save.
53 |
54 | ## Production
55 |
56 | Run your production environment:
57 |
58 | ```bash
59 | ./prod.sh
60 | ```
61 |
62 | Visit [http://localhost:3000](http://localhost:3000) or [https://local.mproske.com](https://local.mproske.com).
63 |
64 | Alternatively, you can run production without multistage.
65 |
66 | ```bash
67 | ./prod-without-multistage.sh
68 | ```
69 |
70 | [Docker Multi-stage Builds](https://docs.docker.com/build/building/multi-stage) is recommended in production, because combined with [Next.js Output Standalone](https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files), only the minimum `node_modules` files required are copied into the final Docker image. This results in up to 85% smaller apps (Approximately 110 MB, compared to 1 GB with `create-next-app`). But this can be a good alternative for developers who don't want to get into the weeds. Because when you work in Docker, everything should be easily understandable.
71 |
72 | ## Deploy
73 |
74 | Spin up a One-Click Docker app, that's ready to run in about 1 minute. Login to your server, run the production command, and you're up and running!
75 |
76 | - [Digital Ocean](https://marketplace.digitalocean.com/apps/docker)
77 | - [Vultr](https://www.vultr.com/apps/docker)
78 |
79 | Visit http://YOUR_SERVERS_IP_ADDRESS:3000
80 |
81 | ## What now?
82 |
83 | Add any apps or technologies you like! Try copying your Next.js app to the root of the project, copy over the Dockerfiles from the `next-ts-app` or `next-js-app` directory.
84 |
85 | ## Gotchas
86 |
87 | - ???
88 |
89 | If you notice any gotchas with this setup, please [open an issue](https://github.com/maxproske/nextjs-docker-production-kit/issues/new) so I can add them to this list.
90 |
91 | ## Useful commands
92 |
93 | ```bash
94 | # Stop all running containers
95 | docker kill $(docker ps -aq) && docker rm $(docker ps -aq)
96 |
97 | # Free up space
98 | docker system prune -af --volumes
99 | ```
100 |
101 |
102 | [fork-icon]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo-forked.svg
103 |
--------------------------------------------------------------------------------
/nginx/certs/example/archive/local.mproske.com/fullchain1.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEXDCCA0SgAwIBAgISBGpthqxL9czlbtCInEjqO2IdMA0GCSqGSIb3DQEBCwUA
3 | MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
4 | EwJSMzAeFw0yMjEyMTQwNTAyMDhaFw0yMzAzMTQwNTAyMDdaMBwxGjAYBgNVBAMT
5 | EWxvY2FsLm1wcm9za2UuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjFX+
6 | 40rxS3aaCt1u7abdWBDNlvrfaA/Sv9IT73OlPxqeaPRWSln7xvdRd5PIoGmEP/41
7 | zpbHm620jeXM/a8Sr6OCAkswggJHMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
8 | BggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUvrTS
9 | HlrsAUvto1KsitG0Nc1hQ9YwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsU
10 | wsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5j
11 | ci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wHAYDVR0R
12 | BBUwE4IRbG9jYWwubXByb3NrZS5jb20wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYL
13 | KwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlw
14 | dC5vcmcwggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdgC3Pvsk35xNunXyOcW6WPRs
15 | XfxCz3qfNcSeHQmBJe20mQAAAYUPOd40AAAEAwBHMEUCIFEkCXsRofJHMxQEBi1w
16 | La8260zV4OzdzZ9zNUVru86bAiEA/H6CwcOd+9BJjHWrqg9KoHUQq9dZPWmasz1S
17 | e94ZkqEAdQDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYUPOd4p
18 | AAAEAwBGMEQCIGd7ddZ8HEVrCGzX77ArlEkj7/uNJVqbIK7QblueX5K0AiBSgdNz
19 | 7cmlgVNrNOVWkzohN95a79mNsh0rmGYY3wNdIDANBgkqhkiG9w0BAQsFAAOCAQEA
20 | Q0Pf05MKQ4G/ZJHVfvH0rbhq1eFzA3MkG19YopqrmZgx9uHkoB6iHU7UzPuD3wLT
21 | pz3sEjl5bTN/059iWk55aAevGqmG6WnAayef6g8tPYCksKnrC6upP3Yn/TY5FXSn
22 | rr/OvZ/qOSsLAFjL96S/fdgVbz5EHfsAEFtIzQN7GVar675KLLHkpBt1Kgk67eRA
23 | 6RTZVqqMp5LjK5RyhezJk/8RQN0rPhmbxBriJv8nYjbQ+wDVBKcGapyRoqSQhvl2
24 | QMG/3TN0HeI5hDQxmQLasZkCQjUd/36c3s6ttw9eikwqZ0VI6WoR/4ua9gHYfMOG
25 | mWE8w9aXIwOUSrd6GR4r5Q==
26 | -----END CERTIFICATE-----
27 | -----BEGIN CERTIFICATE-----
28 | MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
29 | TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
30 | cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
31 | WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
32 | RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
33 | AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
34 | R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
35 | sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
36 | NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
37 | Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
38 | /kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
39 | AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
40 | Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
41 | FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
42 | AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
43 | Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
44 | gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
45 | PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
46 | ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
47 | CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
48 | lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
49 | avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
50 | yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
51 | yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
52 | hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
53 | HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
54 | MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
55 | nLRbwHOoq7hHwg==
56 | -----END CERTIFICATE-----
57 | -----BEGIN CERTIFICATE-----
58 | MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
59 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
60 | DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
61 | TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
62 | cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
63 | AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
64 | ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
65 | wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
66 | LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
67 | 4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
68 | bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
69 | sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
70 | Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
71 | FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
72 | SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
73 | PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
74 | TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
75 | SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
76 | c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
77 | +tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
78 | ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
79 | b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
80 | U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
81 | MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
82 | 5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
83 | 9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
84 | WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
85 | he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
86 | Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
87 | -----END CERTIFICATE-----
88 |
--------------------------------------------------------------------------------
/next-js-app/src/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .main {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: space-between;
5 | align-items: center;
6 | padding: 6rem;
7 | min-height: 100vh;
8 | }
9 |
10 | .description {
11 | display: inherit;
12 | justify-content: inherit;
13 | align-items: inherit;
14 | font-size: 0.85rem;
15 | max-width: var(--max-width);
16 | width: 100%;
17 | z-index: 2;
18 | font-family: var(--font-mono);
19 | }
20 |
21 | .description a {
22 | display: flex;
23 | align-items: center;
24 | justify-content: center;
25 | gap: 0.5rem;
26 | }
27 |
28 | .description p {
29 | position: relative;
30 | margin: 0;
31 | padding: 1rem;
32 | background-color: rgba(var(--callout-rgb), 0.5);
33 | border: 1px solid rgba(var(--callout-border-rgb), 0.3);
34 | border-radius: var(--border-radius);
35 | }
36 |
37 | .code {
38 | font-weight: 700;
39 | font-family: var(--font-mono);
40 | }
41 |
42 | .grid {
43 | display: grid;
44 | grid-template-columns: repeat(3, minmax(33%, auto));
45 | width: var(--max-width);
46 | max-width: 100%;
47 | }
48 |
49 | .card {
50 | padding: 1rem 1.2rem;
51 | border-radius: var(--border-radius);
52 | background: rgba(var(--card-rgb), 0);
53 | border: 1px solid rgba(var(--card-border-rgb), 0);
54 | transition: background 200ms, border 200ms;
55 | }
56 |
57 | .card span {
58 | display: inline-block;
59 | transition: transform 200ms;
60 | }
61 |
62 | .card h2 {
63 | font-weight: 600;
64 | margin-bottom: 0.7rem;
65 | }
66 |
67 | .card p {
68 | margin: 0;
69 | opacity: 0.6;
70 | font-size: 0.9rem;
71 | line-height: 1.5;
72 | max-width: 34ch;
73 | }
74 |
75 | .center {
76 | display: flex;
77 | justify-content: center;
78 | align-items: center;
79 | position: relative;
80 | padding: 4rem 0;
81 | }
82 |
83 | .center::before {
84 | background: var(--secondary-glow);
85 | border-radius: 50%;
86 | width: 480px;
87 | height: 360px;
88 | margin-left: -400px;
89 | }
90 |
91 | .center::after {
92 | background: var(--primary-glow);
93 | width: 240px;
94 | height: 180px;
95 | z-index: -1;
96 | }
97 |
98 | .center::before,
99 | .center::after {
100 | content: "";
101 | left: 50%;
102 | position: absolute;
103 | filter: blur(45px);
104 | transform: translateZ(0);
105 | }
106 |
107 | .logo,
108 | .thirteen {
109 | position: relative;
110 | }
111 |
112 | .thirteen {
113 | display: flex;
114 | justify-content: center;
115 | align-items: center;
116 | width: 75px;
117 | height: 75px;
118 | padding: 25px 10px;
119 | margin-left: 16px;
120 | transform: translateZ(0);
121 | border-radius: var(--border-radius);
122 | overflow: hidden;
123 | /* box-shadow: 0px 2px 8px -1px #0000001a; */
124 | }
125 |
126 | .thirteen:hover {
127 | cursor: pointer;
128 | }
129 |
130 | .thirteen::before,
131 | .thirteen::after {
132 | content: "";
133 | position: absolute;
134 | z-index: -1;
135 | }
136 |
137 | /* Conic Gradient Animation */
138 | .thirteen::before {
139 | animation: 6s rotate linear infinite;
140 | width: 200%;
141 | height: 200%;
142 | background: var(--tile-border);
143 | }
144 |
145 | /* Inner Square */
146 | .thirteen::after {
147 | inset: 0;
148 | padding: 1px;
149 | border-radius: var(--border-radius);
150 | background: linear-gradient(
151 | to bottom right,
152 | rgba(var(--tile-start-rgb), 1),
153 | rgba(var(--tile-end-rgb), 1)
154 | );
155 | background-clip: content-box;
156 | }
157 |
158 | /* Enable hover only on non-touch devices */
159 | @media (hover: hover) and (pointer: fine) {
160 | .card:hover {
161 | background: rgba(var(--card-rgb), 0.1);
162 | border: 1px solid rgba(var(--card-border-rgb), 0.15);
163 | }
164 |
165 | .card:hover span {
166 | transform: translateX(4px);
167 | }
168 | }
169 |
170 | @media (prefers-reduced-motion) {
171 | .thirteen::before {
172 | animation: none;
173 | }
174 |
175 | .card:hover span {
176 | transform: none;
177 | }
178 | }
179 |
180 | /* Mobile and Tablet */
181 | @media (max-width: 1023px) {
182 | .content {
183 | padding: 4rem;
184 | }
185 |
186 | .grid {
187 | grid-template-columns: 1fr;
188 | margin-bottom: 120px;
189 | max-width: 320px;
190 | text-align: center;
191 | }
192 |
193 | .card {
194 | padding: 1rem 2.5rem;
195 | }
196 |
197 | .card h2 {
198 | margin-bottom: 0.5rem;
199 | }
200 |
201 | .center {
202 | padding: 8rem 0 6rem;
203 | }
204 |
205 | .center::before {
206 | transform: none;
207 | height: 300px;
208 | }
209 |
210 | .description {
211 | font-size: 0.8rem;
212 | }
213 |
214 | .description a {
215 | padding: 1rem;
216 | }
217 |
218 | .description p,
219 | .description div {
220 | display: flex;
221 | justify-content: center;
222 | position: fixed;
223 | width: 100%;
224 | }
225 |
226 | .description p {
227 | align-items: center;
228 | inset: 0 0 auto;
229 | padding: 2rem 1rem 1.4rem;
230 | border-radius: 0;
231 | border: none;
232 | border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
233 | background: linear-gradient(
234 | to bottom,
235 | rgba(var(--background-start-rgb), 1),
236 | rgba(var(--callout-rgb), 0.5)
237 | );
238 | background-clip: padding-box;
239 | backdrop-filter: blur(24px);
240 | }
241 |
242 | .description div {
243 | align-items: flex-end;
244 | pointer-events: none;
245 | inset: auto 0 0;
246 | padding: 2rem;
247 | height: 200px;
248 | background: linear-gradient(
249 | to bottom,
250 | transparent 0%,
251 | rgb(var(--background-end-rgb)) 40%
252 | );
253 | z-index: 1;
254 | }
255 | }
256 |
257 | @media (prefers-color-scheme: dark) {
258 | .vercelLogo {
259 | filter: invert(1);
260 | }
261 |
262 | .logo {
263 | filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
264 | }
265 | }
266 |
267 | @keyframes rotate {
268 | from {
269 | transform: rotate(360deg);
270 | }
271 | to {
272 | transform: rotate(0deg);
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/next-ts-app/src/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .main {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: space-between;
5 | align-items: center;
6 | padding: 6rem;
7 | min-height: 100vh;
8 | }
9 |
10 | .description {
11 | display: inherit;
12 | justify-content: inherit;
13 | align-items: inherit;
14 | font-size: 0.85rem;
15 | max-width: var(--max-width);
16 | width: 100%;
17 | z-index: 2;
18 | font-family: var(--font-mono);
19 | }
20 |
21 | .description a {
22 | display: flex;
23 | align-items: center;
24 | justify-content: center;
25 | gap: 0.5rem;
26 | }
27 |
28 | .description p {
29 | position: relative;
30 | margin: 0;
31 | padding: 1rem;
32 | background-color: rgba(var(--callout-rgb), 0.5);
33 | border: 1px solid rgba(var(--callout-border-rgb), 0.3);
34 | border-radius: var(--border-radius);
35 | }
36 |
37 | .code {
38 | font-weight: 700;
39 | font-family: var(--font-mono);
40 | }
41 |
42 | .grid {
43 | display: grid;
44 | grid-template-columns: repeat(3, minmax(33%, auto));
45 | width: var(--max-width);
46 | max-width: 100%;
47 | }
48 |
49 | .card {
50 | padding: 1rem 1.2rem;
51 | border-radius: var(--border-radius);
52 | background: rgba(var(--card-rgb), 0);
53 | border: 1px solid rgba(var(--card-border-rgb), 0);
54 | transition: background 200ms, border 200ms;
55 | }
56 |
57 | .card span {
58 | display: inline-block;
59 | transition: transform 200ms;
60 | }
61 |
62 | .card h2 {
63 | font-weight: 600;
64 | margin-bottom: 0.7rem;
65 | }
66 |
67 | .card p {
68 | margin: 0;
69 | opacity: 0.6;
70 | font-size: 0.9rem;
71 | line-height: 1.5;
72 | max-width: 34ch;
73 | }
74 |
75 | .center {
76 | display: flex;
77 | justify-content: center;
78 | align-items: center;
79 | position: relative;
80 | padding: 4rem 0;
81 | }
82 |
83 | .center::before {
84 | background: var(--secondary-glow);
85 | border-radius: 50%;
86 | width: 480px;
87 | height: 360px;
88 | margin-left: -400px;
89 | }
90 |
91 | .center::after {
92 | background: var(--primary-glow);
93 | width: 240px;
94 | height: 180px;
95 | z-index: -1;
96 | }
97 |
98 | .center::before,
99 | .center::after {
100 | content: "";
101 | left: 50%;
102 | position: absolute;
103 | filter: blur(45px);
104 | transform: translateZ(0);
105 | }
106 |
107 | .logo,
108 | .thirteen {
109 | position: relative;
110 | }
111 |
112 | .thirteen {
113 | display: flex;
114 | justify-content: center;
115 | align-items: center;
116 | width: 75px;
117 | height: 75px;
118 | padding: 25px 10px;
119 | margin-left: 16px;
120 | transform: translateZ(0);
121 | border-radius: var(--border-radius);
122 | overflow: hidden;
123 | /* box-shadow: 0px 2px 8px -1px #0000001a; */
124 | }
125 |
126 | .thirteen:hover {
127 | cursor: pointer;
128 | }
129 |
130 | .thirteen::before,
131 | .thirteen::after {
132 | content: "";
133 | position: absolute;
134 | z-index: -1;
135 | }
136 |
137 | /* Conic Gradient Animation */
138 | .thirteen::before {
139 | animation: 6s rotate linear infinite;
140 | width: 200%;
141 | height: 200%;
142 | background: var(--tile-border);
143 | }
144 |
145 | /* Inner Square */
146 | .thirteen::after {
147 | inset: 0;
148 | padding: 1px;
149 | border-radius: var(--border-radius);
150 | background: linear-gradient(
151 | to bottom right,
152 | rgba(var(--tile-start-rgb), 1),
153 | rgba(var(--tile-end-rgb), 1)
154 | );
155 | background-clip: content-box;
156 | }
157 |
158 | /* Enable hover only on non-touch devices */
159 | @media (hover: hover) and (pointer: fine) {
160 | .card:hover {
161 | background: rgba(var(--card-rgb), 0.1);
162 | border: 1px solid rgba(var(--card-border-rgb), 0.15);
163 | }
164 |
165 | .card:hover span {
166 | transform: translateX(4px);
167 | }
168 | }
169 |
170 | @media (prefers-reduced-motion) {
171 | .thirteen::before {
172 | animation: none;
173 | }
174 |
175 | .card:hover span {
176 | transform: none;
177 | }
178 | }
179 |
180 | /* Mobile and Tablet */
181 | @media (max-width: 1023px) {
182 | .content {
183 | padding: 4rem;
184 | }
185 |
186 | .grid {
187 | grid-template-columns: 1fr;
188 | margin-bottom: 120px;
189 | max-width: 320px;
190 | text-align: center;
191 | }
192 |
193 | .card {
194 | padding: 1rem 2.5rem;
195 | }
196 |
197 | .card h2 {
198 | margin-bottom: 0.5rem;
199 | }
200 |
201 | .center {
202 | padding: 8rem 0 6rem;
203 | }
204 |
205 | .center::before {
206 | transform: none;
207 | height: 300px;
208 | }
209 |
210 | .description {
211 | font-size: 0.8rem;
212 | }
213 |
214 | .description a {
215 | padding: 1rem;
216 | }
217 |
218 | .description p,
219 | .description div {
220 | display: flex;
221 | justify-content: center;
222 | position: fixed;
223 | width: 100%;
224 | }
225 |
226 | .description p {
227 | align-items: center;
228 | inset: 0 0 auto;
229 | padding: 2rem 1rem 1.4rem;
230 | border-radius: 0;
231 | border: none;
232 | border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
233 | background: linear-gradient(
234 | to bottom,
235 | rgba(var(--background-start-rgb), 1),
236 | rgba(var(--callout-rgb), 0.5)
237 | );
238 | background-clip: padding-box;
239 | backdrop-filter: blur(24px);
240 | }
241 |
242 | .description div {
243 | align-items: flex-end;
244 | pointer-events: none;
245 | inset: auto 0 0;
246 | padding: 2rem;
247 | height: 200px;
248 | background: linear-gradient(
249 | to bottom,
250 | transparent 0%,
251 | rgb(var(--background-end-rgb)) 40%
252 | );
253 | z-index: 1;
254 | }
255 | }
256 |
257 | @media (prefers-color-scheme: dark) {
258 | .vercelLogo {
259 | filter: invert(1);
260 | }
261 |
262 | .logo {
263 | filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
264 | }
265 | }
266 |
267 | @keyframes rotate {
268 | from {
269 | transform: rotate(360deg);
270 | }
271 | to {
272 | transform: rotate(0deg);
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/next-ts-app/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | next:
12 | specifier: ^15.0.3
13 | version: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
14 | postgres:
15 | specifier: ^3.4.5
16 | version: 3.4.5
17 | react:
18 | specifier: ^18.3.1
19 | version: 18.3.1
20 | react-dom:
21 | specifier: ^18.3.1
22 | version: 18.3.1(react@18.3.1)
23 | devDependencies:
24 | '@types/node':
25 | specifier: ^22.9.0
26 | version: 22.9.0
27 | '@types/react':
28 | specifier: ^18.3.12
29 | version: 18.3.12
30 | '@types/react-dom':
31 | specifier: ^18.3.1
32 | version: 18.3.1
33 | typescript:
34 | specifier: ^5.6.3
35 | version: 5.6.3
36 |
37 | packages:
38 |
39 | '@emnapi/runtime@1.3.1':
40 | resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
41 |
42 | '@img/sharp-darwin-arm64@0.33.5':
43 | resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
44 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
45 | cpu: [arm64]
46 | os: [darwin]
47 |
48 | '@img/sharp-darwin-x64@0.33.5':
49 | resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
50 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
51 | cpu: [x64]
52 | os: [darwin]
53 |
54 | '@img/sharp-libvips-darwin-arm64@1.0.4':
55 | resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
56 | cpu: [arm64]
57 | os: [darwin]
58 |
59 | '@img/sharp-libvips-darwin-x64@1.0.4':
60 | resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
61 | cpu: [x64]
62 | os: [darwin]
63 |
64 | '@img/sharp-libvips-linux-arm64@1.0.4':
65 | resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
66 | cpu: [arm64]
67 | os: [linux]
68 |
69 | '@img/sharp-libvips-linux-arm@1.0.5':
70 | resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
71 | cpu: [arm]
72 | os: [linux]
73 |
74 | '@img/sharp-libvips-linux-s390x@1.0.4':
75 | resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
76 | cpu: [s390x]
77 | os: [linux]
78 |
79 | '@img/sharp-libvips-linux-x64@1.0.4':
80 | resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
81 | cpu: [x64]
82 | os: [linux]
83 |
84 | '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
85 | resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
86 | cpu: [arm64]
87 | os: [linux]
88 |
89 | '@img/sharp-libvips-linuxmusl-x64@1.0.4':
90 | resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
91 | cpu: [x64]
92 | os: [linux]
93 |
94 | '@img/sharp-linux-arm64@0.33.5':
95 | resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
96 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
97 | cpu: [arm64]
98 | os: [linux]
99 |
100 | '@img/sharp-linux-arm@0.33.5':
101 | resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
102 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
103 | cpu: [arm]
104 | os: [linux]
105 |
106 | '@img/sharp-linux-s390x@0.33.5':
107 | resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
108 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
109 | cpu: [s390x]
110 | os: [linux]
111 |
112 | '@img/sharp-linux-x64@0.33.5':
113 | resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
114 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
115 | cpu: [x64]
116 | os: [linux]
117 |
118 | '@img/sharp-linuxmusl-arm64@0.33.5':
119 | resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
120 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
121 | cpu: [arm64]
122 | os: [linux]
123 |
124 | '@img/sharp-linuxmusl-x64@0.33.5':
125 | resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
126 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
127 | cpu: [x64]
128 | os: [linux]
129 |
130 | '@img/sharp-wasm32@0.33.5':
131 | resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
132 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
133 | cpu: [wasm32]
134 |
135 | '@img/sharp-win32-ia32@0.33.5':
136 | resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
137 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
138 | cpu: [ia32]
139 | os: [win32]
140 |
141 | '@img/sharp-win32-x64@0.33.5':
142 | resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
143 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
144 | cpu: [x64]
145 | os: [win32]
146 |
147 | '@next/env@15.0.3':
148 | resolution: {integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==}
149 |
150 | '@next/swc-darwin-arm64@15.0.3':
151 | resolution: {integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==}
152 | engines: {node: '>= 10'}
153 | cpu: [arm64]
154 | os: [darwin]
155 |
156 | '@next/swc-darwin-x64@15.0.3':
157 | resolution: {integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==}
158 | engines: {node: '>= 10'}
159 | cpu: [x64]
160 | os: [darwin]
161 |
162 | '@next/swc-linux-arm64-gnu@15.0.3':
163 | resolution: {integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==}
164 | engines: {node: '>= 10'}
165 | cpu: [arm64]
166 | os: [linux]
167 |
168 | '@next/swc-linux-arm64-musl@15.0.3':
169 | resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==}
170 | engines: {node: '>= 10'}
171 | cpu: [arm64]
172 | os: [linux]
173 |
174 | '@next/swc-linux-x64-gnu@15.0.3':
175 | resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==}
176 | engines: {node: '>= 10'}
177 | cpu: [x64]
178 | os: [linux]
179 |
180 | '@next/swc-linux-x64-musl@15.0.3':
181 | resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==}
182 | engines: {node: '>= 10'}
183 | cpu: [x64]
184 | os: [linux]
185 |
186 | '@next/swc-win32-arm64-msvc@15.0.3':
187 | resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==}
188 | engines: {node: '>= 10'}
189 | cpu: [arm64]
190 | os: [win32]
191 |
192 | '@next/swc-win32-x64-msvc@15.0.3':
193 | resolution: {integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==}
194 | engines: {node: '>= 10'}
195 | cpu: [x64]
196 | os: [win32]
197 |
198 | '@swc/counter@0.1.3':
199 | resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
200 |
201 | '@swc/helpers@0.5.13':
202 | resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==}
203 |
204 | '@types/node@22.9.0':
205 | resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==}
206 |
207 | '@types/prop-types@15.7.13':
208 | resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
209 |
210 | '@types/react-dom@18.3.1':
211 | resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==}
212 |
213 | '@types/react@18.3.12':
214 | resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==}
215 |
216 | busboy@1.6.0:
217 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
218 | engines: {node: '>=10.16.0'}
219 |
220 | caniuse-lite@1.0.30001680:
221 | resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==}
222 |
223 | client-only@0.0.1:
224 | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
225 |
226 | color-convert@2.0.1:
227 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
228 | engines: {node: '>=7.0.0'}
229 |
230 | color-name@1.1.4:
231 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
232 |
233 | color-string@1.9.1:
234 | resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
235 |
236 | color@4.2.3:
237 | resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
238 | engines: {node: '>=12.5.0'}
239 |
240 | csstype@3.1.3:
241 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
242 |
243 | detect-libc@2.0.3:
244 | resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
245 | engines: {node: '>=8'}
246 |
247 | is-arrayish@0.3.2:
248 | resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
249 |
250 | js-tokens@4.0.0:
251 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
252 |
253 | loose-envify@1.4.0:
254 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
255 | hasBin: true
256 |
257 | nanoid@3.3.7:
258 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
259 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
260 | hasBin: true
261 |
262 | next@15.0.3:
263 | resolution: {integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==}
264 | engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
265 | hasBin: true
266 | peerDependencies:
267 | '@opentelemetry/api': ^1.1.0
268 | '@playwright/test': ^1.41.2
269 | babel-plugin-react-compiler: '*'
270 | react: ^18.2.0 || 19.0.0-rc-66855b96-20241106
271 | react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106
272 | sass: ^1.3.0
273 | peerDependenciesMeta:
274 | '@opentelemetry/api':
275 | optional: true
276 | '@playwright/test':
277 | optional: true
278 | babel-plugin-react-compiler:
279 | optional: true
280 | sass:
281 | optional: true
282 |
283 | picocolors@1.1.1:
284 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
285 |
286 | postcss@8.4.31:
287 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
288 | engines: {node: ^10 || ^12 || >=14}
289 |
290 | postgres@3.4.5:
291 | resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==}
292 | engines: {node: '>=12'}
293 |
294 | react-dom@18.3.1:
295 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
296 | peerDependencies:
297 | react: ^18.3.1
298 |
299 | react@18.3.1:
300 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
301 | engines: {node: '>=0.10.0'}
302 |
303 | scheduler@0.23.2:
304 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
305 |
306 | semver@7.6.3:
307 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
308 | engines: {node: '>=10'}
309 | hasBin: true
310 |
311 | sharp@0.33.5:
312 | resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
313 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
314 |
315 | simple-swizzle@0.2.2:
316 | resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
317 |
318 | source-map-js@1.2.1:
319 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
320 | engines: {node: '>=0.10.0'}
321 |
322 | streamsearch@1.1.0:
323 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
324 | engines: {node: '>=10.0.0'}
325 |
326 | styled-jsx@5.1.6:
327 | resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
328 | engines: {node: '>= 12.0.0'}
329 | peerDependencies:
330 | '@babel/core': '*'
331 | babel-plugin-macros: '*'
332 | react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
333 | peerDependenciesMeta:
334 | '@babel/core':
335 | optional: true
336 | babel-plugin-macros:
337 | optional: true
338 |
339 | tslib@2.8.1:
340 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
341 |
342 | typescript@5.6.3:
343 | resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
344 | engines: {node: '>=14.17'}
345 | hasBin: true
346 |
347 | undici-types@6.19.8:
348 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
349 |
350 | snapshots:
351 |
352 | '@emnapi/runtime@1.3.1':
353 | dependencies:
354 | tslib: 2.8.1
355 | optional: true
356 |
357 | '@img/sharp-darwin-arm64@0.33.5':
358 | optionalDependencies:
359 | '@img/sharp-libvips-darwin-arm64': 1.0.4
360 | optional: true
361 |
362 | '@img/sharp-darwin-x64@0.33.5':
363 | optionalDependencies:
364 | '@img/sharp-libvips-darwin-x64': 1.0.4
365 | optional: true
366 |
367 | '@img/sharp-libvips-darwin-arm64@1.0.4':
368 | optional: true
369 |
370 | '@img/sharp-libvips-darwin-x64@1.0.4':
371 | optional: true
372 |
373 | '@img/sharp-libvips-linux-arm64@1.0.4':
374 | optional: true
375 |
376 | '@img/sharp-libvips-linux-arm@1.0.5':
377 | optional: true
378 |
379 | '@img/sharp-libvips-linux-s390x@1.0.4':
380 | optional: true
381 |
382 | '@img/sharp-libvips-linux-x64@1.0.4':
383 | optional: true
384 |
385 | '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
386 | optional: true
387 |
388 | '@img/sharp-libvips-linuxmusl-x64@1.0.4':
389 | optional: true
390 |
391 | '@img/sharp-linux-arm64@0.33.5':
392 | optionalDependencies:
393 | '@img/sharp-libvips-linux-arm64': 1.0.4
394 | optional: true
395 |
396 | '@img/sharp-linux-arm@0.33.5':
397 | optionalDependencies:
398 | '@img/sharp-libvips-linux-arm': 1.0.5
399 | optional: true
400 |
401 | '@img/sharp-linux-s390x@0.33.5':
402 | optionalDependencies:
403 | '@img/sharp-libvips-linux-s390x': 1.0.4
404 | optional: true
405 |
406 | '@img/sharp-linux-x64@0.33.5':
407 | optionalDependencies:
408 | '@img/sharp-libvips-linux-x64': 1.0.4
409 | optional: true
410 |
411 | '@img/sharp-linuxmusl-arm64@0.33.5':
412 | optionalDependencies:
413 | '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
414 | optional: true
415 |
416 | '@img/sharp-linuxmusl-x64@0.33.5':
417 | optionalDependencies:
418 | '@img/sharp-libvips-linuxmusl-x64': 1.0.4
419 | optional: true
420 |
421 | '@img/sharp-wasm32@0.33.5':
422 | dependencies:
423 | '@emnapi/runtime': 1.3.1
424 | optional: true
425 |
426 | '@img/sharp-win32-ia32@0.33.5':
427 | optional: true
428 |
429 | '@img/sharp-win32-x64@0.33.5':
430 | optional: true
431 |
432 | '@next/env@15.0.3': {}
433 |
434 | '@next/swc-darwin-arm64@15.0.3':
435 | optional: true
436 |
437 | '@next/swc-darwin-x64@15.0.3':
438 | optional: true
439 |
440 | '@next/swc-linux-arm64-gnu@15.0.3':
441 | optional: true
442 |
443 | '@next/swc-linux-arm64-musl@15.0.3':
444 | optional: true
445 |
446 | '@next/swc-linux-x64-gnu@15.0.3':
447 | optional: true
448 |
449 | '@next/swc-linux-x64-musl@15.0.3':
450 | optional: true
451 |
452 | '@next/swc-win32-arm64-msvc@15.0.3':
453 | optional: true
454 |
455 | '@next/swc-win32-x64-msvc@15.0.3':
456 | optional: true
457 |
458 | '@swc/counter@0.1.3': {}
459 |
460 | '@swc/helpers@0.5.13':
461 | dependencies:
462 | tslib: 2.8.1
463 |
464 | '@types/node@22.9.0':
465 | dependencies:
466 | undici-types: 6.19.8
467 |
468 | '@types/prop-types@15.7.13': {}
469 |
470 | '@types/react-dom@18.3.1':
471 | dependencies:
472 | '@types/react': 18.3.12
473 |
474 | '@types/react@18.3.12':
475 | dependencies:
476 | '@types/prop-types': 15.7.13
477 | csstype: 3.1.3
478 |
479 | busboy@1.6.0:
480 | dependencies:
481 | streamsearch: 1.1.0
482 |
483 | caniuse-lite@1.0.30001680: {}
484 |
485 | client-only@0.0.1: {}
486 |
487 | color-convert@2.0.1:
488 | dependencies:
489 | color-name: 1.1.4
490 | optional: true
491 |
492 | color-name@1.1.4:
493 | optional: true
494 |
495 | color-string@1.9.1:
496 | dependencies:
497 | color-name: 1.1.4
498 | simple-swizzle: 0.2.2
499 | optional: true
500 |
501 | color@4.2.3:
502 | dependencies:
503 | color-convert: 2.0.1
504 | color-string: 1.9.1
505 | optional: true
506 |
507 | csstype@3.1.3: {}
508 |
509 | detect-libc@2.0.3:
510 | optional: true
511 |
512 | is-arrayish@0.3.2:
513 | optional: true
514 |
515 | js-tokens@4.0.0: {}
516 |
517 | loose-envify@1.4.0:
518 | dependencies:
519 | js-tokens: 4.0.0
520 |
521 | nanoid@3.3.7: {}
522 |
523 | next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
524 | dependencies:
525 | '@next/env': 15.0.3
526 | '@swc/counter': 0.1.3
527 | '@swc/helpers': 0.5.13
528 | busboy: 1.6.0
529 | caniuse-lite: 1.0.30001680
530 | postcss: 8.4.31
531 | react: 18.3.1
532 | react-dom: 18.3.1(react@18.3.1)
533 | styled-jsx: 5.1.6(react@18.3.1)
534 | optionalDependencies:
535 | '@next/swc-darwin-arm64': 15.0.3
536 | '@next/swc-darwin-x64': 15.0.3
537 | '@next/swc-linux-arm64-gnu': 15.0.3
538 | '@next/swc-linux-arm64-musl': 15.0.3
539 | '@next/swc-linux-x64-gnu': 15.0.3
540 | '@next/swc-linux-x64-musl': 15.0.3
541 | '@next/swc-win32-arm64-msvc': 15.0.3
542 | '@next/swc-win32-x64-msvc': 15.0.3
543 | sharp: 0.33.5
544 | transitivePeerDependencies:
545 | - '@babel/core'
546 | - babel-plugin-macros
547 |
548 | picocolors@1.1.1: {}
549 |
550 | postcss@8.4.31:
551 | dependencies:
552 | nanoid: 3.3.7
553 | picocolors: 1.1.1
554 | source-map-js: 1.2.1
555 |
556 | postgres@3.4.5: {}
557 |
558 | react-dom@18.3.1(react@18.3.1):
559 | dependencies:
560 | loose-envify: 1.4.0
561 | react: 18.3.1
562 | scheduler: 0.23.2
563 |
564 | react@18.3.1:
565 | dependencies:
566 | loose-envify: 1.4.0
567 |
568 | scheduler@0.23.2:
569 | dependencies:
570 | loose-envify: 1.4.0
571 |
572 | semver@7.6.3:
573 | optional: true
574 |
575 | sharp@0.33.5:
576 | dependencies:
577 | color: 4.2.3
578 | detect-libc: 2.0.3
579 | semver: 7.6.3
580 | optionalDependencies:
581 | '@img/sharp-darwin-arm64': 0.33.5
582 | '@img/sharp-darwin-x64': 0.33.5
583 | '@img/sharp-libvips-darwin-arm64': 1.0.4
584 | '@img/sharp-libvips-darwin-x64': 1.0.4
585 | '@img/sharp-libvips-linux-arm': 1.0.5
586 | '@img/sharp-libvips-linux-arm64': 1.0.4
587 | '@img/sharp-libvips-linux-s390x': 1.0.4
588 | '@img/sharp-libvips-linux-x64': 1.0.4
589 | '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
590 | '@img/sharp-libvips-linuxmusl-x64': 1.0.4
591 | '@img/sharp-linux-arm': 0.33.5
592 | '@img/sharp-linux-arm64': 0.33.5
593 | '@img/sharp-linux-s390x': 0.33.5
594 | '@img/sharp-linux-x64': 0.33.5
595 | '@img/sharp-linuxmusl-arm64': 0.33.5
596 | '@img/sharp-linuxmusl-x64': 0.33.5
597 | '@img/sharp-wasm32': 0.33.5
598 | '@img/sharp-win32-ia32': 0.33.5
599 | '@img/sharp-win32-x64': 0.33.5
600 | optional: true
601 |
602 | simple-swizzle@0.2.2:
603 | dependencies:
604 | is-arrayish: 0.3.2
605 | optional: true
606 |
607 | source-map-js@1.2.1: {}
608 |
609 | streamsearch@1.1.0: {}
610 |
611 | styled-jsx@5.1.6(react@18.3.1):
612 | dependencies:
613 | client-only: 0.0.1
614 | react: 18.3.1
615 |
616 | tslib@2.8.1: {}
617 |
618 | typescript@5.6.3: {}
619 |
620 | undici-types@6.19.8: {}
621 |
--------------------------------------------------------------------------------
/next-js-app/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | next:
12 | specifier: ^15.0.3
13 | version: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
14 | postgres:
15 | specifier: ^3.4.5
16 | version: 3.4.5
17 | react:
18 | specifier: ^18.3.1
19 | version: 18.3.1
20 | react-dom:
21 | specifier: ^18.3.1
22 | version: 18.3.1(react@18.3.1)
23 | devDependencies:
24 | '@eslint/compat':
25 | specifier: ^1.2.3
26 | version: 1.2.3(eslint@9.15.0)
27 | '@eslint/js':
28 | specifier: ^9.15.0
29 | version: 9.15.0
30 | '@types/eslint__js':
31 | specifier: ^8.42.3
32 | version: 8.42.3
33 | eslint:
34 | specifier: ^9.15.0
35 | version: 9.15.0
36 | eslint-plugin-react-hooks:
37 | specifier: ^5.0.0
38 | version: 5.0.0(eslint@9.15.0)
39 | typescript:
40 | specifier: ^5.6.3
41 | version: 5.6.3
42 | typescript-eslint:
43 | specifier: ^8.14.0
44 | version: 8.14.0(eslint@9.15.0)(typescript@5.6.3)
45 |
46 | packages:
47 |
48 | '@emnapi/runtime@1.3.1':
49 | resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
50 |
51 | '@eslint-community/eslint-utils@4.4.1':
52 | resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
53 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
54 | peerDependencies:
55 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
56 |
57 | '@eslint-community/regexpp@4.12.1':
58 | resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
59 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
60 |
61 | '@eslint/compat@1.2.3':
62 | resolution: {integrity: sha512-wlZhwlDFxkxIZ571aH0FoK4h4Vwx7P3HJx62Gp8hTc10bfpwT2x0nULuAHmQSJBOWPgPeVf+9YtnD4j50zVHmA==}
63 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
64 | peerDependencies:
65 | eslint: ^9.10.0
66 | peerDependenciesMeta:
67 | eslint:
68 | optional: true
69 |
70 | '@eslint/config-array@0.19.0':
71 | resolution: {integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==}
72 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
73 |
74 | '@eslint/core@0.9.0':
75 | resolution: {integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==}
76 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
77 |
78 | '@eslint/eslintrc@3.2.0':
79 | resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==}
80 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
81 |
82 | '@eslint/js@9.15.0':
83 | resolution: {integrity: sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==}
84 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
85 |
86 | '@eslint/object-schema@2.1.4':
87 | resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==}
88 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
89 |
90 | '@eslint/plugin-kit@0.2.3':
91 | resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==}
92 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
93 |
94 | '@humanfs/core@0.19.1':
95 | resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
96 | engines: {node: '>=18.18.0'}
97 |
98 | '@humanfs/node@0.16.6':
99 | resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
100 | engines: {node: '>=18.18.0'}
101 |
102 | '@humanwhocodes/module-importer@1.0.1':
103 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
104 | engines: {node: '>=12.22'}
105 |
106 | '@humanwhocodes/retry@0.3.1':
107 | resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
108 | engines: {node: '>=18.18'}
109 |
110 | '@humanwhocodes/retry@0.4.1':
111 | resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==}
112 | engines: {node: '>=18.18'}
113 |
114 | '@img/sharp-darwin-arm64@0.33.5':
115 | resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
116 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
117 | cpu: [arm64]
118 | os: [darwin]
119 |
120 | '@img/sharp-darwin-x64@0.33.5':
121 | resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
122 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
123 | cpu: [x64]
124 | os: [darwin]
125 |
126 | '@img/sharp-libvips-darwin-arm64@1.0.4':
127 | resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
128 | cpu: [arm64]
129 | os: [darwin]
130 |
131 | '@img/sharp-libvips-darwin-x64@1.0.4':
132 | resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
133 | cpu: [x64]
134 | os: [darwin]
135 |
136 | '@img/sharp-libvips-linux-arm64@1.0.4':
137 | resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
138 | cpu: [arm64]
139 | os: [linux]
140 |
141 | '@img/sharp-libvips-linux-arm@1.0.5':
142 | resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
143 | cpu: [arm]
144 | os: [linux]
145 |
146 | '@img/sharp-libvips-linux-s390x@1.0.4':
147 | resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
148 | cpu: [s390x]
149 | os: [linux]
150 |
151 | '@img/sharp-libvips-linux-x64@1.0.4':
152 | resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
153 | cpu: [x64]
154 | os: [linux]
155 |
156 | '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
157 | resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
158 | cpu: [arm64]
159 | os: [linux]
160 |
161 | '@img/sharp-libvips-linuxmusl-x64@1.0.4':
162 | resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
163 | cpu: [x64]
164 | os: [linux]
165 |
166 | '@img/sharp-linux-arm64@0.33.5':
167 | resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
168 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
169 | cpu: [arm64]
170 | os: [linux]
171 |
172 | '@img/sharp-linux-arm@0.33.5':
173 | resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
174 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
175 | cpu: [arm]
176 | os: [linux]
177 |
178 | '@img/sharp-linux-s390x@0.33.5':
179 | resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
180 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
181 | cpu: [s390x]
182 | os: [linux]
183 |
184 | '@img/sharp-linux-x64@0.33.5':
185 | resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
186 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
187 | cpu: [x64]
188 | os: [linux]
189 |
190 | '@img/sharp-linuxmusl-arm64@0.33.5':
191 | resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
192 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
193 | cpu: [arm64]
194 | os: [linux]
195 |
196 | '@img/sharp-linuxmusl-x64@0.33.5':
197 | resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
198 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
199 | cpu: [x64]
200 | os: [linux]
201 |
202 | '@img/sharp-wasm32@0.33.5':
203 | resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
204 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
205 | cpu: [wasm32]
206 |
207 | '@img/sharp-win32-ia32@0.33.5':
208 | resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
209 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
210 | cpu: [ia32]
211 | os: [win32]
212 |
213 | '@img/sharp-win32-x64@0.33.5':
214 | resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
215 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
216 | cpu: [x64]
217 | os: [win32]
218 |
219 | '@next/env@15.0.3':
220 | resolution: {integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==}
221 |
222 | '@next/swc-darwin-arm64@15.0.3':
223 | resolution: {integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==}
224 | engines: {node: '>= 10'}
225 | cpu: [arm64]
226 | os: [darwin]
227 |
228 | '@next/swc-darwin-x64@15.0.3':
229 | resolution: {integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==}
230 | engines: {node: '>= 10'}
231 | cpu: [x64]
232 | os: [darwin]
233 |
234 | '@next/swc-linux-arm64-gnu@15.0.3':
235 | resolution: {integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==}
236 | engines: {node: '>= 10'}
237 | cpu: [arm64]
238 | os: [linux]
239 |
240 | '@next/swc-linux-arm64-musl@15.0.3':
241 | resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==}
242 | engines: {node: '>= 10'}
243 | cpu: [arm64]
244 | os: [linux]
245 |
246 | '@next/swc-linux-x64-gnu@15.0.3':
247 | resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==}
248 | engines: {node: '>= 10'}
249 | cpu: [x64]
250 | os: [linux]
251 |
252 | '@next/swc-linux-x64-musl@15.0.3':
253 | resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==}
254 | engines: {node: '>= 10'}
255 | cpu: [x64]
256 | os: [linux]
257 |
258 | '@next/swc-win32-arm64-msvc@15.0.3':
259 | resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==}
260 | engines: {node: '>= 10'}
261 | cpu: [arm64]
262 | os: [win32]
263 |
264 | '@next/swc-win32-x64-msvc@15.0.3':
265 | resolution: {integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==}
266 | engines: {node: '>= 10'}
267 | cpu: [x64]
268 | os: [win32]
269 |
270 | '@nodelib/fs.scandir@2.1.5':
271 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
272 | engines: {node: '>= 8'}
273 |
274 | '@nodelib/fs.stat@2.0.5':
275 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
276 | engines: {node: '>= 8'}
277 |
278 | '@nodelib/fs.walk@1.2.8':
279 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
280 | engines: {node: '>= 8'}
281 |
282 | '@swc/counter@0.1.3':
283 | resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
284 |
285 | '@swc/helpers@0.5.13':
286 | resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==}
287 |
288 | '@types/eslint@9.6.1':
289 | resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==}
290 |
291 | '@types/eslint__js@8.42.3':
292 | resolution: {integrity: sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==}
293 |
294 | '@types/estree@1.0.6':
295 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
296 |
297 | '@types/json-schema@7.0.15':
298 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
299 |
300 | '@typescript-eslint/eslint-plugin@8.14.0':
301 | resolution: {integrity: sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==}
302 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
303 | peerDependencies:
304 | '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
305 | eslint: ^8.57.0 || ^9.0.0
306 | typescript: '*'
307 | peerDependenciesMeta:
308 | typescript:
309 | optional: true
310 |
311 | '@typescript-eslint/parser@8.14.0':
312 | resolution: {integrity: sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==}
313 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
314 | peerDependencies:
315 | eslint: ^8.57.0 || ^9.0.0
316 | typescript: '*'
317 | peerDependenciesMeta:
318 | typescript:
319 | optional: true
320 |
321 | '@typescript-eslint/scope-manager@8.14.0':
322 | resolution: {integrity: sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==}
323 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
324 |
325 | '@typescript-eslint/type-utils@8.14.0':
326 | resolution: {integrity: sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==}
327 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
328 | peerDependencies:
329 | typescript: '*'
330 | peerDependenciesMeta:
331 | typescript:
332 | optional: true
333 |
334 | '@typescript-eslint/types@8.14.0':
335 | resolution: {integrity: sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==}
336 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
337 |
338 | '@typescript-eslint/typescript-estree@8.14.0':
339 | resolution: {integrity: sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==}
340 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
341 | peerDependencies:
342 | typescript: '*'
343 | peerDependenciesMeta:
344 | typescript:
345 | optional: true
346 |
347 | '@typescript-eslint/utils@8.14.0':
348 | resolution: {integrity: sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==}
349 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
350 | peerDependencies:
351 | eslint: ^8.57.0 || ^9.0.0
352 |
353 | '@typescript-eslint/visitor-keys@8.14.0':
354 | resolution: {integrity: sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==}
355 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
356 |
357 | acorn-jsx@5.3.2:
358 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
359 | peerDependencies:
360 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
361 |
362 | acorn@8.14.0:
363 | resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
364 | engines: {node: '>=0.4.0'}
365 | hasBin: true
366 |
367 | ajv@6.12.6:
368 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
369 |
370 | ansi-styles@4.3.0:
371 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
372 | engines: {node: '>=8'}
373 |
374 | argparse@2.0.1:
375 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
376 |
377 | balanced-match@1.0.2:
378 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
379 |
380 | brace-expansion@1.1.11:
381 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
382 |
383 | brace-expansion@2.0.1:
384 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
385 |
386 | braces@3.0.3:
387 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
388 | engines: {node: '>=8'}
389 |
390 | busboy@1.6.0:
391 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
392 | engines: {node: '>=10.16.0'}
393 |
394 | callsites@3.1.0:
395 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
396 | engines: {node: '>=6'}
397 |
398 | caniuse-lite@1.0.30001680:
399 | resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==}
400 |
401 | chalk@4.1.2:
402 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
403 | engines: {node: '>=10'}
404 |
405 | client-only@0.0.1:
406 | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
407 |
408 | color-convert@2.0.1:
409 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
410 | engines: {node: '>=7.0.0'}
411 |
412 | color-name@1.1.4:
413 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
414 |
415 | color-string@1.9.1:
416 | resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
417 |
418 | color@4.2.3:
419 | resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
420 | engines: {node: '>=12.5.0'}
421 |
422 | concat-map@0.0.1:
423 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
424 |
425 | cross-spawn@7.0.5:
426 | resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==}
427 | engines: {node: '>= 8'}
428 |
429 | debug@4.3.7:
430 | resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
431 | engines: {node: '>=6.0'}
432 | peerDependencies:
433 | supports-color: '*'
434 | peerDependenciesMeta:
435 | supports-color:
436 | optional: true
437 |
438 | deep-is@0.1.4:
439 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
440 |
441 | detect-libc@2.0.3:
442 | resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
443 | engines: {node: '>=8'}
444 |
445 | escape-string-regexp@4.0.0:
446 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
447 | engines: {node: '>=10'}
448 |
449 | eslint-plugin-react-hooks@5.0.0:
450 | resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==}
451 | engines: {node: '>=10'}
452 | peerDependencies:
453 | eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
454 |
455 | eslint-scope@8.2.0:
456 | resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==}
457 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
458 |
459 | eslint-visitor-keys@3.4.3:
460 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
461 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
462 |
463 | eslint-visitor-keys@4.2.0:
464 | resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
465 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
466 |
467 | eslint@9.15.0:
468 | resolution: {integrity: sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==}
469 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
470 | hasBin: true
471 | peerDependencies:
472 | jiti: '*'
473 | peerDependenciesMeta:
474 | jiti:
475 | optional: true
476 |
477 | espree@10.3.0:
478 | resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
479 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
480 |
481 | esquery@1.6.0:
482 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
483 | engines: {node: '>=0.10'}
484 |
485 | esrecurse@4.3.0:
486 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
487 | engines: {node: '>=4.0'}
488 |
489 | estraverse@5.3.0:
490 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
491 | engines: {node: '>=4.0'}
492 |
493 | esutils@2.0.3:
494 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
495 | engines: {node: '>=0.10.0'}
496 |
497 | fast-deep-equal@3.1.3:
498 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
499 |
500 | fast-glob@3.3.2:
501 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
502 | engines: {node: '>=8.6.0'}
503 |
504 | fast-json-stable-stringify@2.1.0:
505 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
506 |
507 | fast-levenshtein@2.0.6:
508 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
509 |
510 | fastq@1.17.1:
511 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
512 |
513 | file-entry-cache@8.0.0:
514 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
515 | engines: {node: '>=16.0.0'}
516 |
517 | fill-range@7.1.1:
518 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
519 | engines: {node: '>=8'}
520 |
521 | find-up@5.0.0:
522 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
523 | engines: {node: '>=10'}
524 |
525 | flat-cache@4.0.1:
526 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
527 | engines: {node: '>=16'}
528 |
529 | flatted@3.3.1:
530 | resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
531 |
532 | glob-parent@5.1.2:
533 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
534 | engines: {node: '>= 6'}
535 |
536 | glob-parent@6.0.2:
537 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
538 | engines: {node: '>=10.13.0'}
539 |
540 | globals@14.0.0:
541 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
542 | engines: {node: '>=18'}
543 |
544 | graphemer@1.4.0:
545 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
546 |
547 | has-flag@4.0.0:
548 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
549 | engines: {node: '>=8'}
550 |
551 | ignore@5.3.2:
552 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
553 | engines: {node: '>= 4'}
554 |
555 | import-fresh@3.3.0:
556 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
557 | engines: {node: '>=6'}
558 |
559 | imurmurhash@0.1.4:
560 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
561 | engines: {node: '>=0.8.19'}
562 |
563 | is-arrayish@0.3.2:
564 | resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
565 |
566 | is-extglob@2.1.1:
567 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
568 | engines: {node: '>=0.10.0'}
569 |
570 | is-glob@4.0.3:
571 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
572 | engines: {node: '>=0.10.0'}
573 |
574 | is-number@7.0.0:
575 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
576 | engines: {node: '>=0.12.0'}
577 |
578 | isexe@2.0.0:
579 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
580 |
581 | js-tokens@4.0.0:
582 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
583 |
584 | js-yaml@4.1.0:
585 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
586 | hasBin: true
587 |
588 | json-buffer@3.0.1:
589 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
590 |
591 | json-schema-traverse@0.4.1:
592 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
593 |
594 | json-stable-stringify-without-jsonify@1.0.1:
595 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
596 |
597 | keyv@4.5.4:
598 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
599 |
600 | levn@0.4.1:
601 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
602 | engines: {node: '>= 0.8.0'}
603 |
604 | locate-path@6.0.0:
605 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
606 | engines: {node: '>=10'}
607 |
608 | lodash.merge@4.6.2:
609 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
610 |
611 | loose-envify@1.4.0:
612 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
613 | hasBin: true
614 |
615 | merge2@1.4.1:
616 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
617 | engines: {node: '>= 8'}
618 |
619 | micromatch@4.0.8:
620 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
621 | engines: {node: '>=8.6'}
622 |
623 | minimatch@3.1.2:
624 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
625 |
626 | minimatch@9.0.5:
627 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
628 | engines: {node: '>=16 || 14 >=14.17'}
629 |
630 | ms@2.1.3:
631 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
632 |
633 | nanoid@3.3.7:
634 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
635 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
636 | hasBin: true
637 |
638 | natural-compare@1.4.0:
639 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
640 |
641 | next@15.0.3:
642 | resolution: {integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==}
643 | engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
644 | hasBin: true
645 | peerDependencies:
646 | '@opentelemetry/api': ^1.1.0
647 | '@playwright/test': ^1.41.2
648 | babel-plugin-react-compiler: '*'
649 | react: ^18.2.0 || 19.0.0-rc-66855b96-20241106
650 | react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106
651 | sass: ^1.3.0
652 | peerDependenciesMeta:
653 | '@opentelemetry/api':
654 | optional: true
655 | '@playwright/test':
656 | optional: true
657 | babel-plugin-react-compiler:
658 | optional: true
659 | sass:
660 | optional: true
661 |
662 | optionator@0.9.4:
663 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
664 | engines: {node: '>= 0.8.0'}
665 |
666 | p-limit@3.1.0:
667 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
668 | engines: {node: '>=10'}
669 |
670 | p-locate@5.0.0:
671 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
672 | engines: {node: '>=10'}
673 |
674 | parent-module@1.0.1:
675 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
676 | engines: {node: '>=6'}
677 |
678 | path-exists@4.0.0:
679 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
680 | engines: {node: '>=8'}
681 |
682 | path-key@3.1.1:
683 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
684 | engines: {node: '>=8'}
685 |
686 | picocolors@1.1.1:
687 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
688 |
689 | picomatch@2.3.1:
690 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
691 | engines: {node: '>=8.6'}
692 |
693 | postcss@8.4.31:
694 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
695 | engines: {node: ^10 || ^12 || >=14}
696 |
697 | postgres@3.4.5:
698 | resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==}
699 | engines: {node: '>=12'}
700 |
701 | prelude-ls@1.2.1:
702 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
703 | engines: {node: '>= 0.8.0'}
704 |
705 | punycode@2.3.1:
706 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
707 | engines: {node: '>=6'}
708 |
709 | queue-microtask@1.2.3:
710 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
711 |
712 | react-dom@18.3.1:
713 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
714 | peerDependencies:
715 | react: ^18.3.1
716 |
717 | react@18.3.1:
718 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
719 | engines: {node: '>=0.10.0'}
720 |
721 | resolve-from@4.0.0:
722 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
723 | engines: {node: '>=4'}
724 |
725 | reusify@1.0.4:
726 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
727 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
728 |
729 | run-parallel@1.2.0:
730 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
731 |
732 | scheduler@0.23.2:
733 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
734 |
735 | semver@7.6.3:
736 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
737 | engines: {node: '>=10'}
738 | hasBin: true
739 |
740 | sharp@0.33.5:
741 | resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
742 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
743 |
744 | shebang-command@2.0.0:
745 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
746 | engines: {node: '>=8'}
747 |
748 | shebang-regex@3.0.0:
749 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
750 | engines: {node: '>=8'}
751 |
752 | simple-swizzle@0.2.2:
753 | resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
754 |
755 | source-map-js@1.2.1:
756 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
757 | engines: {node: '>=0.10.0'}
758 |
759 | streamsearch@1.1.0:
760 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
761 | engines: {node: '>=10.0.0'}
762 |
763 | strip-json-comments@3.1.1:
764 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
765 | engines: {node: '>=8'}
766 |
767 | styled-jsx@5.1.6:
768 | resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
769 | engines: {node: '>= 12.0.0'}
770 | peerDependencies:
771 | '@babel/core': '*'
772 | babel-plugin-macros: '*'
773 | react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
774 | peerDependenciesMeta:
775 | '@babel/core':
776 | optional: true
777 | babel-plugin-macros:
778 | optional: true
779 |
780 | supports-color@7.2.0:
781 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
782 | engines: {node: '>=8'}
783 |
784 | to-regex-range@5.0.1:
785 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
786 | engines: {node: '>=8.0'}
787 |
788 | ts-api-utils@1.4.0:
789 | resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==}
790 | engines: {node: '>=16'}
791 | peerDependencies:
792 | typescript: '>=4.2.0'
793 |
794 | tslib@2.8.1:
795 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
796 |
797 | type-check@0.4.0:
798 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
799 | engines: {node: '>= 0.8.0'}
800 |
801 | typescript-eslint@8.14.0:
802 | resolution: {integrity: sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==}
803 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
804 | peerDependencies:
805 | typescript: '*'
806 | peerDependenciesMeta:
807 | typescript:
808 | optional: true
809 |
810 | typescript@5.6.3:
811 | resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
812 | engines: {node: '>=14.17'}
813 | hasBin: true
814 |
815 | uri-js@4.4.1:
816 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
817 |
818 | which@2.0.2:
819 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
820 | engines: {node: '>= 8'}
821 | hasBin: true
822 |
823 | word-wrap@1.2.5:
824 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
825 | engines: {node: '>=0.10.0'}
826 |
827 | yocto-queue@0.1.0:
828 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
829 | engines: {node: '>=10'}
830 |
831 | snapshots:
832 |
833 | '@emnapi/runtime@1.3.1':
834 | dependencies:
835 | tslib: 2.8.1
836 | optional: true
837 |
838 | '@eslint-community/eslint-utils@4.4.1(eslint@9.15.0)':
839 | dependencies:
840 | eslint: 9.15.0
841 | eslint-visitor-keys: 3.4.3
842 |
843 | '@eslint-community/regexpp@4.12.1': {}
844 |
845 | '@eslint/compat@1.2.3(eslint@9.15.0)':
846 | optionalDependencies:
847 | eslint: 9.15.0
848 |
849 | '@eslint/config-array@0.19.0':
850 | dependencies:
851 | '@eslint/object-schema': 2.1.4
852 | debug: 4.3.7
853 | minimatch: 3.1.2
854 | transitivePeerDependencies:
855 | - supports-color
856 |
857 | '@eslint/core@0.9.0': {}
858 |
859 | '@eslint/eslintrc@3.2.0':
860 | dependencies:
861 | ajv: 6.12.6
862 | debug: 4.3.7
863 | espree: 10.3.0
864 | globals: 14.0.0
865 | ignore: 5.3.2
866 | import-fresh: 3.3.0
867 | js-yaml: 4.1.0
868 | minimatch: 3.1.2
869 | strip-json-comments: 3.1.1
870 | transitivePeerDependencies:
871 | - supports-color
872 |
873 | '@eslint/js@9.15.0': {}
874 |
875 | '@eslint/object-schema@2.1.4': {}
876 |
877 | '@eslint/plugin-kit@0.2.3':
878 | dependencies:
879 | levn: 0.4.1
880 |
881 | '@humanfs/core@0.19.1': {}
882 |
883 | '@humanfs/node@0.16.6':
884 | dependencies:
885 | '@humanfs/core': 0.19.1
886 | '@humanwhocodes/retry': 0.3.1
887 |
888 | '@humanwhocodes/module-importer@1.0.1': {}
889 |
890 | '@humanwhocodes/retry@0.3.1': {}
891 |
892 | '@humanwhocodes/retry@0.4.1': {}
893 |
894 | '@img/sharp-darwin-arm64@0.33.5':
895 | optionalDependencies:
896 | '@img/sharp-libvips-darwin-arm64': 1.0.4
897 | optional: true
898 |
899 | '@img/sharp-darwin-x64@0.33.5':
900 | optionalDependencies:
901 | '@img/sharp-libvips-darwin-x64': 1.0.4
902 | optional: true
903 |
904 | '@img/sharp-libvips-darwin-arm64@1.0.4':
905 | optional: true
906 |
907 | '@img/sharp-libvips-darwin-x64@1.0.4':
908 | optional: true
909 |
910 | '@img/sharp-libvips-linux-arm64@1.0.4':
911 | optional: true
912 |
913 | '@img/sharp-libvips-linux-arm@1.0.5':
914 | optional: true
915 |
916 | '@img/sharp-libvips-linux-s390x@1.0.4':
917 | optional: true
918 |
919 | '@img/sharp-libvips-linux-x64@1.0.4':
920 | optional: true
921 |
922 | '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
923 | optional: true
924 |
925 | '@img/sharp-libvips-linuxmusl-x64@1.0.4':
926 | optional: true
927 |
928 | '@img/sharp-linux-arm64@0.33.5':
929 | optionalDependencies:
930 | '@img/sharp-libvips-linux-arm64': 1.0.4
931 | optional: true
932 |
933 | '@img/sharp-linux-arm@0.33.5':
934 | optionalDependencies:
935 | '@img/sharp-libvips-linux-arm': 1.0.5
936 | optional: true
937 |
938 | '@img/sharp-linux-s390x@0.33.5':
939 | optionalDependencies:
940 | '@img/sharp-libvips-linux-s390x': 1.0.4
941 | optional: true
942 |
943 | '@img/sharp-linux-x64@0.33.5':
944 | optionalDependencies:
945 | '@img/sharp-libvips-linux-x64': 1.0.4
946 | optional: true
947 |
948 | '@img/sharp-linuxmusl-arm64@0.33.5':
949 | optionalDependencies:
950 | '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
951 | optional: true
952 |
953 | '@img/sharp-linuxmusl-x64@0.33.5':
954 | optionalDependencies:
955 | '@img/sharp-libvips-linuxmusl-x64': 1.0.4
956 | optional: true
957 |
958 | '@img/sharp-wasm32@0.33.5':
959 | dependencies:
960 | '@emnapi/runtime': 1.3.1
961 | optional: true
962 |
963 | '@img/sharp-win32-ia32@0.33.5':
964 | optional: true
965 |
966 | '@img/sharp-win32-x64@0.33.5':
967 | optional: true
968 |
969 | '@next/env@15.0.3': {}
970 |
971 | '@next/swc-darwin-arm64@15.0.3':
972 | optional: true
973 |
974 | '@next/swc-darwin-x64@15.0.3':
975 | optional: true
976 |
977 | '@next/swc-linux-arm64-gnu@15.0.3':
978 | optional: true
979 |
980 | '@next/swc-linux-arm64-musl@15.0.3':
981 | optional: true
982 |
983 | '@next/swc-linux-x64-gnu@15.0.3':
984 | optional: true
985 |
986 | '@next/swc-linux-x64-musl@15.0.3':
987 | optional: true
988 |
989 | '@next/swc-win32-arm64-msvc@15.0.3':
990 | optional: true
991 |
992 | '@next/swc-win32-x64-msvc@15.0.3':
993 | optional: true
994 |
995 | '@nodelib/fs.scandir@2.1.5':
996 | dependencies:
997 | '@nodelib/fs.stat': 2.0.5
998 | run-parallel: 1.2.0
999 |
1000 | '@nodelib/fs.stat@2.0.5': {}
1001 |
1002 | '@nodelib/fs.walk@1.2.8':
1003 | dependencies:
1004 | '@nodelib/fs.scandir': 2.1.5
1005 | fastq: 1.17.1
1006 |
1007 | '@swc/counter@0.1.3': {}
1008 |
1009 | '@swc/helpers@0.5.13':
1010 | dependencies:
1011 | tslib: 2.8.1
1012 |
1013 | '@types/eslint@9.6.1':
1014 | dependencies:
1015 | '@types/estree': 1.0.6
1016 | '@types/json-schema': 7.0.15
1017 |
1018 | '@types/eslint__js@8.42.3':
1019 | dependencies:
1020 | '@types/eslint': 9.6.1
1021 |
1022 | '@types/estree@1.0.6': {}
1023 |
1024 | '@types/json-schema@7.0.15': {}
1025 |
1026 | '@typescript-eslint/eslint-plugin@8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.6.3))(eslint@9.15.0)(typescript@5.6.3)':
1027 | dependencies:
1028 | '@eslint-community/regexpp': 4.12.1
1029 | '@typescript-eslint/parser': 8.14.0(eslint@9.15.0)(typescript@5.6.3)
1030 | '@typescript-eslint/scope-manager': 8.14.0
1031 | '@typescript-eslint/type-utils': 8.14.0(eslint@9.15.0)(typescript@5.6.3)
1032 | '@typescript-eslint/utils': 8.14.0(eslint@9.15.0)(typescript@5.6.3)
1033 | '@typescript-eslint/visitor-keys': 8.14.0
1034 | eslint: 9.15.0
1035 | graphemer: 1.4.0
1036 | ignore: 5.3.2
1037 | natural-compare: 1.4.0
1038 | ts-api-utils: 1.4.0(typescript@5.6.3)
1039 | optionalDependencies:
1040 | typescript: 5.6.3
1041 | transitivePeerDependencies:
1042 | - supports-color
1043 |
1044 | '@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.6.3)':
1045 | dependencies:
1046 | '@typescript-eslint/scope-manager': 8.14.0
1047 | '@typescript-eslint/types': 8.14.0
1048 | '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3)
1049 | '@typescript-eslint/visitor-keys': 8.14.0
1050 | debug: 4.3.7
1051 | eslint: 9.15.0
1052 | optionalDependencies:
1053 | typescript: 5.6.3
1054 | transitivePeerDependencies:
1055 | - supports-color
1056 |
1057 | '@typescript-eslint/scope-manager@8.14.0':
1058 | dependencies:
1059 | '@typescript-eslint/types': 8.14.0
1060 | '@typescript-eslint/visitor-keys': 8.14.0
1061 |
1062 | '@typescript-eslint/type-utils@8.14.0(eslint@9.15.0)(typescript@5.6.3)':
1063 | dependencies:
1064 | '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3)
1065 | '@typescript-eslint/utils': 8.14.0(eslint@9.15.0)(typescript@5.6.3)
1066 | debug: 4.3.7
1067 | ts-api-utils: 1.4.0(typescript@5.6.3)
1068 | optionalDependencies:
1069 | typescript: 5.6.3
1070 | transitivePeerDependencies:
1071 | - eslint
1072 | - supports-color
1073 |
1074 | '@typescript-eslint/types@8.14.0': {}
1075 |
1076 | '@typescript-eslint/typescript-estree@8.14.0(typescript@5.6.3)':
1077 | dependencies:
1078 | '@typescript-eslint/types': 8.14.0
1079 | '@typescript-eslint/visitor-keys': 8.14.0
1080 | debug: 4.3.7
1081 | fast-glob: 3.3.2
1082 | is-glob: 4.0.3
1083 | minimatch: 9.0.5
1084 | semver: 7.6.3
1085 | ts-api-utils: 1.4.0(typescript@5.6.3)
1086 | optionalDependencies:
1087 | typescript: 5.6.3
1088 | transitivePeerDependencies:
1089 | - supports-color
1090 |
1091 | '@typescript-eslint/utils@8.14.0(eslint@9.15.0)(typescript@5.6.3)':
1092 | dependencies:
1093 | '@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0)
1094 | '@typescript-eslint/scope-manager': 8.14.0
1095 | '@typescript-eslint/types': 8.14.0
1096 | '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3)
1097 | eslint: 9.15.0
1098 | transitivePeerDependencies:
1099 | - supports-color
1100 | - typescript
1101 |
1102 | '@typescript-eslint/visitor-keys@8.14.0':
1103 | dependencies:
1104 | '@typescript-eslint/types': 8.14.0
1105 | eslint-visitor-keys: 3.4.3
1106 |
1107 | acorn-jsx@5.3.2(acorn@8.14.0):
1108 | dependencies:
1109 | acorn: 8.14.0
1110 |
1111 | acorn@8.14.0: {}
1112 |
1113 | ajv@6.12.6:
1114 | dependencies:
1115 | fast-deep-equal: 3.1.3
1116 | fast-json-stable-stringify: 2.1.0
1117 | json-schema-traverse: 0.4.1
1118 | uri-js: 4.4.1
1119 |
1120 | ansi-styles@4.3.0:
1121 | dependencies:
1122 | color-convert: 2.0.1
1123 |
1124 | argparse@2.0.1: {}
1125 |
1126 | balanced-match@1.0.2: {}
1127 |
1128 | brace-expansion@1.1.11:
1129 | dependencies:
1130 | balanced-match: 1.0.2
1131 | concat-map: 0.0.1
1132 |
1133 | brace-expansion@2.0.1:
1134 | dependencies:
1135 | balanced-match: 1.0.2
1136 |
1137 | braces@3.0.3:
1138 | dependencies:
1139 | fill-range: 7.1.1
1140 |
1141 | busboy@1.6.0:
1142 | dependencies:
1143 | streamsearch: 1.1.0
1144 |
1145 | callsites@3.1.0: {}
1146 |
1147 | caniuse-lite@1.0.30001680: {}
1148 |
1149 | chalk@4.1.2:
1150 | dependencies:
1151 | ansi-styles: 4.3.0
1152 | supports-color: 7.2.0
1153 |
1154 | client-only@0.0.1: {}
1155 |
1156 | color-convert@2.0.1:
1157 | dependencies:
1158 | color-name: 1.1.4
1159 |
1160 | color-name@1.1.4: {}
1161 |
1162 | color-string@1.9.1:
1163 | dependencies:
1164 | color-name: 1.1.4
1165 | simple-swizzle: 0.2.2
1166 | optional: true
1167 |
1168 | color@4.2.3:
1169 | dependencies:
1170 | color-convert: 2.0.1
1171 | color-string: 1.9.1
1172 | optional: true
1173 |
1174 | concat-map@0.0.1: {}
1175 |
1176 | cross-spawn@7.0.5:
1177 | dependencies:
1178 | path-key: 3.1.1
1179 | shebang-command: 2.0.0
1180 | which: 2.0.2
1181 |
1182 | debug@4.3.7:
1183 | dependencies:
1184 | ms: 2.1.3
1185 |
1186 | deep-is@0.1.4: {}
1187 |
1188 | detect-libc@2.0.3:
1189 | optional: true
1190 |
1191 | escape-string-regexp@4.0.0: {}
1192 |
1193 | eslint-plugin-react-hooks@5.0.0(eslint@9.15.0):
1194 | dependencies:
1195 | eslint: 9.15.0
1196 |
1197 | eslint-scope@8.2.0:
1198 | dependencies:
1199 | esrecurse: 4.3.0
1200 | estraverse: 5.3.0
1201 |
1202 | eslint-visitor-keys@3.4.3: {}
1203 |
1204 | eslint-visitor-keys@4.2.0: {}
1205 |
1206 | eslint@9.15.0:
1207 | dependencies:
1208 | '@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0)
1209 | '@eslint-community/regexpp': 4.12.1
1210 | '@eslint/config-array': 0.19.0
1211 | '@eslint/core': 0.9.0
1212 | '@eslint/eslintrc': 3.2.0
1213 | '@eslint/js': 9.15.0
1214 | '@eslint/plugin-kit': 0.2.3
1215 | '@humanfs/node': 0.16.6
1216 | '@humanwhocodes/module-importer': 1.0.1
1217 | '@humanwhocodes/retry': 0.4.1
1218 | '@types/estree': 1.0.6
1219 | '@types/json-schema': 7.0.15
1220 | ajv: 6.12.6
1221 | chalk: 4.1.2
1222 | cross-spawn: 7.0.5
1223 | debug: 4.3.7
1224 | escape-string-regexp: 4.0.0
1225 | eslint-scope: 8.2.0
1226 | eslint-visitor-keys: 4.2.0
1227 | espree: 10.3.0
1228 | esquery: 1.6.0
1229 | esutils: 2.0.3
1230 | fast-deep-equal: 3.1.3
1231 | file-entry-cache: 8.0.0
1232 | find-up: 5.0.0
1233 | glob-parent: 6.0.2
1234 | ignore: 5.3.2
1235 | imurmurhash: 0.1.4
1236 | is-glob: 4.0.3
1237 | json-stable-stringify-without-jsonify: 1.0.1
1238 | lodash.merge: 4.6.2
1239 | minimatch: 3.1.2
1240 | natural-compare: 1.4.0
1241 | optionator: 0.9.4
1242 | transitivePeerDependencies:
1243 | - supports-color
1244 |
1245 | espree@10.3.0:
1246 | dependencies:
1247 | acorn: 8.14.0
1248 | acorn-jsx: 5.3.2(acorn@8.14.0)
1249 | eslint-visitor-keys: 4.2.0
1250 |
1251 | esquery@1.6.0:
1252 | dependencies:
1253 | estraverse: 5.3.0
1254 |
1255 | esrecurse@4.3.0:
1256 | dependencies:
1257 | estraverse: 5.3.0
1258 |
1259 | estraverse@5.3.0: {}
1260 |
1261 | esutils@2.0.3: {}
1262 |
1263 | fast-deep-equal@3.1.3: {}
1264 |
1265 | fast-glob@3.3.2:
1266 | dependencies:
1267 | '@nodelib/fs.stat': 2.0.5
1268 | '@nodelib/fs.walk': 1.2.8
1269 | glob-parent: 5.1.2
1270 | merge2: 1.4.1
1271 | micromatch: 4.0.8
1272 |
1273 | fast-json-stable-stringify@2.1.0: {}
1274 |
1275 | fast-levenshtein@2.0.6: {}
1276 |
1277 | fastq@1.17.1:
1278 | dependencies:
1279 | reusify: 1.0.4
1280 |
1281 | file-entry-cache@8.0.0:
1282 | dependencies:
1283 | flat-cache: 4.0.1
1284 |
1285 | fill-range@7.1.1:
1286 | dependencies:
1287 | to-regex-range: 5.0.1
1288 |
1289 | find-up@5.0.0:
1290 | dependencies:
1291 | locate-path: 6.0.0
1292 | path-exists: 4.0.0
1293 |
1294 | flat-cache@4.0.1:
1295 | dependencies:
1296 | flatted: 3.3.1
1297 | keyv: 4.5.4
1298 |
1299 | flatted@3.3.1: {}
1300 |
1301 | glob-parent@5.1.2:
1302 | dependencies:
1303 | is-glob: 4.0.3
1304 |
1305 | glob-parent@6.0.2:
1306 | dependencies:
1307 | is-glob: 4.0.3
1308 |
1309 | globals@14.0.0: {}
1310 |
1311 | graphemer@1.4.0: {}
1312 |
1313 | has-flag@4.0.0: {}
1314 |
1315 | ignore@5.3.2: {}
1316 |
1317 | import-fresh@3.3.0:
1318 | dependencies:
1319 | parent-module: 1.0.1
1320 | resolve-from: 4.0.0
1321 |
1322 | imurmurhash@0.1.4: {}
1323 |
1324 | is-arrayish@0.3.2:
1325 | optional: true
1326 |
1327 | is-extglob@2.1.1: {}
1328 |
1329 | is-glob@4.0.3:
1330 | dependencies:
1331 | is-extglob: 2.1.1
1332 |
1333 | is-number@7.0.0: {}
1334 |
1335 | isexe@2.0.0: {}
1336 |
1337 | js-tokens@4.0.0: {}
1338 |
1339 | js-yaml@4.1.0:
1340 | dependencies:
1341 | argparse: 2.0.1
1342 |
1343 | json-buffer@3.0.1: {}
1344 |
1345 | json-schema-traverse@0.4.1: {}
1346 |
1347 | json-stable-stringify-without-jsonify@1.0.1: {}
1348 |
1349 | keyv@4.5.4:
1350 | dependencies:
1351 | json-buffer: 3.0.1
1352 |
1353 | levn@0.4.1:
1354 | dependencies:
1355 | prelude-ls: 1.2.1
1356 | type-check: 0.4.0
1357 |
1358 | locate-path@6.0.0:
1359 | dependencies:
1360 | p-locate: 5.0.0
1361 |
1362 | lodash.merge@4.6.2: {}
1363 |
1364 | loose-envify@1.4.0:
1365 | dependencies:
1366 | js-tokens: 4.0.0
1367 |
1368 | merge2@1.4.1: {}
1369 |
1370 | micromatch@4.0.8:
1371 | dependencies:
1372 | braces: 3.0.3
1373 | picomatch: 2.3.1
1374 |
1375 | minimatch@3.1.2:
1376 | dependencies:
1377 | brace-expansion: 1.1.11
1378 |
1379 | minimatch@9.0.5:
1380 | dependencies:
1381 | brace-expansion: 2.0.1
1382 |
1383 | ms@2.1.3: {}
1384 |
1385 | nanoid@3.3.7: {}
1386 |
1387 | natural-compare@1.4.0: {}
1388 |
1389 | next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
1390 | dependencies:
1391 | '@next/env': 15.0.3
1392 | '@swc/counter': 0.1.3
1393 | '@swc/helpers': 0.5.13
1394 | busboy: 1.6.0
1395 | caniuse-lite: 1.0.30001680
1396 | postcss: 8.4.31
1397 | react: 18.3.1
1398 | react-dom: 18.3.1(react@18.3.1)
1399 | styled-jsx: 5.1.6(react@18.3.1)
1400 | optionalDependencies:
1401 | '@next/swc-darwin-arm64': 15.0.3
1402 | '@next/swc-darwin-x64': 15.0.3
1403 | '@next/swc-linux-arm64-gnu': 15.0.3
1404 | '@next/swc-linux-arm64-musl': 15.0.3
1405 | '@next/swc-linux-x64-gnu': 15.0.3
1406 | '@next/swc-linux-x64-musl': 15.0.3
1407 | '@next/swc-win32-arm64-msvc': 15.0.3
1408 | '@next/swc-win32-x64-msvc': 15.0.3
1409 | sharp: 0.33.5
1410 | transitivePeerDependencies:
1411 | - '@babel/core'
1412 | - babel-plugin-macros
1413 |
1414 | optionator@0.9.4:
1415 | dependencies:
1416 | deep-is: 0.1.4
1417 | fast-levenshtein: 2.0.6
1418 | levn: 0.4.1
1419 | prelude-ls: 1.2.1
1420 | type-check: 0.4.0
1421 | word-wrap: 1.2.5
1422 |
1423 | p-limit@3.1.0:
1424 | dependencies:
1425 | yocto-queue: 0.1.0
1426 |
1427 | p-locate@5.0.0:
1428 | dependencies:
1429 | p-limit: 3.1.0
1430 |
1431 | parent-module@1.0.1:
1432 | dependencies:
1433 | callsites: 3.1.0
1434 |
1435 | path-exists@4.0.0: {}
1436 |
1437 | path-key@3.1.1: {}
1438 |
1439 | picocolors@1.1.1: {}
1440 |
1441 | picomatch@2.3.1: {}
1442 |
1443 | postcss@8.4.31:
1444 | dependencies:
1445 | nanoid: 3.3.7
1446 | picocolors: 1.1.1
1447 | source-map-js: 1.2.1
1448 |
1449 | postgres@3.4.5: {}
1450 |
1451 | prelude-ls@1.2.1: {}
1452 |
1453 | punycode@2.3.1: {}
1454 |
1455 | queue-microtask@1.2.3: {}
1456 |
1457 | react-dom@18.3.1(react@18.3.1):
1458 | dependencies:
1459 | loose-envify: 1.4.0
1460 | react: 18.3.1
1461 | scheduler: 0.23.2
1462 |
1463 | react@18.3.1:
1464 | dependencies:
1465 | loose-envify: 1.4.0
1466 |
1467 | resolve-from@4.0.0: {}
1468 |
1469 | reusify@1.0.4: {}
1470 |
1471 | run-parallel@1.2.0:
1472 | dependencies:
1473 | queue-microtask: 1.2.3
1474 |
1475 | scheduler@0.23.2:
1476 | dependencies:
1477 | loose-envify: 1.4.0
1478 |
1479 | semver@7.6.3: {}
1480 |
1481 | sharp@0.33.5:
1482 | dependencies:
1483 | color: 4.2.3
1484 | detect-libc: 2.0.3
1485 | semver: 7.6.3
1486 | optionalDependencies:
1487 | '@img/sharp-darwin-arm64': 0.33.5
1488 | '@img/sharp-darwin-x64': 0.33.5
1489 | '@img/sharp-libvips-darwin-arm64': 1.0.4
1490 | '@img/sharp-libvips-darwin-x64': 1.0.4
1491 | '@img/sharp-libvips-linux-arm': 1.0.5
1492 | '@img/sharp-libvips-linux-arm64': 1.0.4
1493 | '@img/sharp-libvips-linux-s390x': 1.0.4
1494 | '@img/sharp-libvips-linux-x64': 1.0.4
1495 | '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
1496 | '@img/sharp-libvips-linuxmusl-x64': 1.0.4
1497 | '@img/sharp-linux-arm': 0.33.5
1498 | '@img/sharp-linux-arm64': 0.33.5
1499 | '@img/sharp-linux-s390x': 0.33.5
1500 | '@img/sharp-linux-x64': 0.33.5
1501 | '@img/sharp-linuxmusl-arm64': 0.33.5
1502 | '@img/sharp-linuxmusl-x64': 0.33.5
1503 | '@img/sharp-wasm32': 0.33.5
1504 | '@img/sharp-win32-ia32': 0.33.5
1505 | '@img/sharp-win32-x64': 0.33.5
1506 | optional: true
1507 |
1508 | shebang-command@2.0.0:
1509 | dependencies:
1510 | shebang-regex: 3.0.0
1511 |
1512 | shebang-regex@3.0.0: {}
1513 |
1514 | simple-swizzle@0.2.2:
1515 | dependencies:
1516 | is-arrayish: 0.3.2
1517 | optional: true
1518 |
1519 | source-map-js@1.2.1: {}
1520 |
1521 | streamsearch@1.1.0: {}
1522 |
1523 | strip-json-comments@3.1.1: {}
1524 |
1525 | styled-jsx@5.1.6(react@18.3.1):
1526 | dependencies:
1527 | client-only: 0.0.1
1528 | react: 18.3.1
1529 |
1530 | supports-color@7.2.0:
1531 | dependencies:
1532 | has-flag: 4.0.0
1533 |
1534 | to-regex-range@5.0.1:
1535 | dependencies:
1536 | is-number: 7.0.0
1537 |
1538 | ts-api-utils@1.4.0(typescript@5.6.3):
1539 | dependencies:
1540 | typescript: 5.6.3
1541 |
1542 | tslib@2.8.1: {}
1543 |
1544 | type-check@0.4.0:
1545 | dependencies:
1546 | prelude-ls: 1.2.1
1547 |
1548 | typescript-eslint@8.14.0(eslint@9.15.0)(typescript@5.6.3):
1549 | dependencies:
1550 | '@typescript-eslint/eslint-plugin': 8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.15.0)(typescript@5.6.3))(eslint@9.15.0)(typescript@5.6.3)
1551 | '@typescript-eslint/parser': 8.14.0(eslint@9.15.0)(typescript@5.6.3)
1552 | '@typescript-eslint/utils': 8.14.0(eslint@9.15.0)(typescript@5.6.3)
1553 | optionalDependencies:
1554 | typescript: 5.6.3
1555 | transitivePeerDependencies:
1556 | - eslint
1557 | - supports-color
1558 |
1559 | typescript@5.6.3: {}
1560 |
1561 | uri-js@4.4.1:
1562 | dependencies:
1563 | punycode: 2.3.1
1564 |
1565 | which@2.0.2:
1566 | dependencies:
1567 | isexe: 2.0.0
1568 |
1569 | word-wrap@1.2.5: {}
1570 |
1571 | yocto-queue@0.1.0: {}
1572 |
--------------------------------------------------------------------------------